rucc 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +55 -0
- data/.rspec +1 -0
- data/.travis.yml +5 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +46 -0
- data/LICENCE +21 -0
- data/README.md +82 -0
- data/Rakefile +2 -0
- data/Vagrantfile +10 -0
- data/bin/console +10 -0
- data/bin/rspec +2 -0
- data/bin/setup +8 -0
- data/exe/rucc +7 -0
- data/include/8cc.h +48 -0
- data/include/float.h +44 -0
- data/include/iso646.h +20 -0
- data/include/rucc.h +2 -0
- data/include/stdalign.h +11 -0
- data/include/stdarg.h +52 -0
- data/include/stdbool.h +11 -0
- data/include/stddef.h +15 -0
- data/include/stdnoreturn.h +8 -0
- data/lib/rucc.rb +8 -0
- data/lib/rucc/case.rb +22 -0
- data/lib/rucc/decl.rb +9 -0
- data/lib/rucc/enc.rb +9 -0
- data/lib/rucc/engine.rb +138 -0
- data/lib/rucc/file_io.rb +108 -0
- data/lib/rucc/file_io_list.rb +56 -0
- data/lib/rucc/gen.rb +1602 -0
- data/lib/rucc/int_evaluator.rb +114 -0
- data/lib/rucc/k.rb +73 -0
- data/lib/rucc/keyword.rb +17 -0
- data/lib/rucc/kind.rb +43 -0
- data/lib/rucc/label_gen.rb +13 -0
- data/lib/rucc/lexer.rb +40 -0
- data/lib/rucc/lexer/impl.rb +683 -0
- data/lib/rucc/lexer/preprocessor.rb +888 -0
- data/lib/rucc/lexer/preprocessor/cond_incl.rb +27 -0
- data/lib/rucc/lexer/preprocessor/constructor.rb +54 -0
- data/lib/rucc/lexer/preprocessor/pragma.rb +31 -0
- data/lib/rucc/lexer/preprocessor/special_macro.rb +110 -0
- data/lib/rucc/libc.rb +47 -0
- data/lib/rucc/m.rb +7 -0
- data/lib/rucc/macro.rb +24 -0
- data/lib/rucc/node.rb +530 -0
- data/lib/rucc/node/conv.rb +33 -0
- data/lib/rucc/op.rb +61 -0
- data/lib/rucc/operator.rb +13 -0
- data/lib/rucc/option.rb +30 -0
- data/lib/rucc/parser.rb +961 -0
- data/lib/rucc/parser/break.rb +18 -0
- data/lib/rucc/parser/builtin.rb +25 -0
- data/lib/rucc/parser/continue.rb +18 -0
- data/lib/rucc/parser/do.rb +33 -0
- data/lib/rucc/parser/ensure.rb +39 -0
- data/lib/rucc/parser/enum.rb +64 -0
- data/lib/rucc/parser/expr.rb +493 -0
- data/lib/rucc/parser/for.rb +71 -0
- data/lib/rucc/parser/func.rb +274 -0
- data/lib/rucc/parser/func_call.rb +54 -0
- data/lib/rucc/parser/goto.rb +29 -0
- data/lib/rucc/parser/if.rb +23 -0
- data/lib/rucc/parser/initializer.rb +237 -0
- data/lib/rucc/parser/label.rb +31 -0
- data/lib/rucc/parser/return.rb +16 -0
- data/lib/rucc/parser/struct_and_union.rb +280 -0
- data/lib/rucc/parser/switch.rb +117 -0
- data/lib/rucc/parser/while.rb +29 -0
- data/lib/rucc/pos.rb +11 -0
- data/lib/rucc/rmap.rb +22 -0
- data/lib/rucc/s.rb +9 -0
- data/lib/rucc/static_label_gen.rb +15 -0
- data/lib/rucc/t.rb +18 -0
- data/lib/rucc/tempname_gen.rb +14 -0
- data/lib/rucc/token.rb +114 -0
- data/lib/rucc/token_gen.rb +68 -0
- data/lib/rucc/type.rb +304 -0
- data/lib/rucc/type/check.rb +39 -0
- data/lib/rucc/type/conv.rb +29 -0
- data/lib/rucc/type_info.rb +21 -0
- data/lib/rucc/utf.rb +126 -0
- data/lib/rucc/util.rb +111 -0
- data/lib/rucc/version.rb +3 -0
- data/rucc.gemspec +38 -0
- metadata +201 -0
@@ -0,0 +1,71 @@
|
|
1
|
+
module Rucc
|
2
|
+
class Parser
|
3
|
+
module For
|
4
|
+
private
|
5
|
+
# @return [Node]
|
6
|
+
def read_for_stmt
|
7
|
+
expect!('(')
|
8
|
+
beg = @label_gen.next
|
9
|
+
mid = @label_gen.next
|
10
|
+
lst = @label_gen.next
|
11
|
+
|
12
|
+
orig = @localenv
|
13
|
+
@localenv = RMap.new(@localenv)
|
14
|
+
init = read_opt_decl_or_stmt
|
15
|
+
cond = read_expr_opt
|
16
|
+
if cond && Type.is_flotype(cond.ty)
|
17
|
+
cond = Node.ast_conv(Type::BOOL, cond)
|
18
|
+
end
|
19
|
+
expect!(';')
|
20
|
+
step = read_expr_opt
|
21
|
+
expect!(')')
|
22
|
+
body = nil # declaration for ruby
|
23
|
+
with_jump_labels(mid, lst) { body = read_stmt }
|
24
|
+
@localenv = orig
|
25
|
+
|
26
|
+
v = []
|
27
|
+
if !init.nil?
|
28
|
+
v.push(init)
|
29
|
+
end
|
30
|
+
v.push(Node.ast_dest(beg))
|
31
|
+
if !cond.nil?
|
32
|
+
v.push(Node.ast_if(cond, nil, Node.ast_jump(lst)))
|
33
|
+
end
|
34
|
+
if !body.nil?
|
35
|
+
v.push(body)
|
36
|
+
end
|
37
|
+
v.push(Node.ast_dest(mid))
|
38
|
+
if !step.nil?
|
39
|
+
v.push(step)
|
40
|
+
end
|
41
|
+
v.push(Node.ast_jump(beg))
|
42
|
+
v.push(Node.ast_dest(lst))
|
43
|
+
Node.ast_compound_stmt(v)
|
44
|
+
end
|
45
|
+
|
46
|
+
# @param [String] cont
|
47
|
+
# @param [String] brk
|
48
|
+
def with_jump_labels(cont, brk)
|
49
|
+
# Set jump lablels
|
50
|
+
ocontinue = @lcontinue
|
51
|
+
obreak = @lbreak
|
52
|
+
@lcontinue = cont
|
53
|
+
@lbreak = brk
|
54
|
+
|
55
|
+
yield
|
56
|
+
|
57
|
+
# Restore jump lablels
|
58
|
+
@lcontinue = ocontinue
|
59
|
+
@lbreak = obreak
|
60
|
+
end
|
61
|
+
|
62
|
+
# @return [Node, NilClass]
|
63
|
+
def read_opt_decl_or_stmt
|
64
|
+
return nil if next_token?(';')
|
65
|
+
list = []
|
66
|
+
read_decl_or_stmt(list)
|
67
|
+
Node.ast_compound_stmt(list)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,274 @@
|
|
1
|
+
module Rucc
|
2
|
+
class Parser
|
3
|
+
module Func
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
# @param [Type] basety
|
8
|
+
# @param(return) [Array] params
|
9
|
+
# @return [Type]
|
10
|
+
def read_declarator_func(basety, params)
|
11
|
+
if basety.kind == Kind::FUNC
|
12
|
+
raise "function returning a function"
|
13
|
+
end
|
14
|
+
if basety.kind == Kind::ARRAY
|
15
|
+
raise "function returning an array"
|
16
|
+
end
|
17
|
+
read_func_param_list(params, basety)
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param [Array, NilClass] paramvars
|
21
|
+
# @param [Type] rettype
|
22
|
+
# @return [Type]
|
23
|
+
def read_func_param_list(paramvars, rettype)
|
24
|
+
# C11 6.7.6.3p10: A parameter list with just "void" specifies that
|
25
|
+
# the function has no parameters.
|
26
|
+
tok = get
|
27
|
+
if Token.is_keyword?(tok, K::VOID) && next_token?(')')
|
28
|
+
return Type.make_func_type(rettype, [], false, false)
|
29
|
+
end
|
30
|
+
|
31
|
+
# C11 6.7.6.3p14: K&R-style un-prototyped declaration or
|
32
|
+
# function definition having no parameters.
|
33
|
+
# We return a type representing K&R-style declaration here.
|
34
|
+
# If this is actually part of a declartion, the type will be fixed later.
|
35
|
+
if Token.is_keyword?(tok, ')')
|
36
|
+
return Type.make_func_type(rettype, [], true, true)
|
37
|
+
end
|
38
|
+
@lexer.unget_token(tok)
|
39
|
+
|
40
|
+
tok2 = peek
|
41
|
+
if next_token?(K::ELLIPSIS)
|
42
|
+
Util.errort!(tok2, "at least one parameter is required before \"...\"")
|
43
|
+
end
|
44
|
+
|
45
|
+
if is_type?(peek)
|
46
|
+
paramtypes = []
|
47
|
+
ellipsis = read_declarator_params(paramtypes, paramvars)
|
48
|
+
return Type.make_func_type(rettype, paramtypes, ellipsis, false)
|
49
|
+
end
|
50
|
+
|
51
|
+
if paramvars.nil?
|
52
|
+
Util.errort!(tok, "invalid function definition")
|
53
|
+
end
|
54
|
+
|
55
|
+
read_declarator_params_oldstyle(paramvars)
|
56
|
+
paramtypes = []
|
57
|
+
(0..(paramvars.size - 1)).each do
|
58
|
+
paramtypes.push Type::INT
|
59
|
+
end
|
60
|
+
Type.make_func_type(rettype, paramtypes, false, true)
|
61
|
+
end
|
62
|
+
|
63
|
+
# @param [Array] types
|
64
|
+
# @param [Array] vars
|
65
|
+
# @return [Boolean] ellipsis
|
66
|
+
def read_declarator_params(types, vars)
|
67
|
+
typeonly = vars.nil?
|
68
|
+
ellipsis = false
|
69
|
+
while true
|
70
|
+
tok = peek
|
71
|
+
if next_token?(K::ELLIPSIS)
|
72
|
+
if types.size == 0
|
73
|
+
Util.errort!(tok, "at least one parameter is required before \"...\"")
|
74
|
+
end
|
75
|
+
expect!(')')
|
76
|
+
ellipsis = true
|
77
|
+
return ellipsis
|
78
|
+
end
|
79
|
+
|
80
|
+
name = ""
|
81
|
+
ty = read_func_param(name, typeonly)
|
82
|
+
ensure_not_void!(ty)
|
83
|
+
types.push(ty)
|
84
|
+
if !typeonly
|
85
|
+
vars.push(Node.ast_lvar(ty, name, @localenv, @localvars))
|
86
|
+
end
|
87
|
+
|
88
|
+
tok = get
|
89
|
+
if Token.is_keyword?(tok, ')')
|
90
|
+
return ellipsis
|
91
|
+
end
|
92
|
+
if !Token.is_keyword?(tok, ',')
|
93
|
+
Util.errort!(tok, "comma expected, but got #{tok}")
|
94
|
+
end
|
95
|
+
end
|
96
|
+
raise "must not reach here"
|
97
|
+
end
|
98
|
+
|
99
|
+
# @param [<String>] name
|
100
|
+
# @param [Boolean] optional
|
101
|
+
# @return [Type]
|
102
|
+
def read_func_param(name, optional)
|
103
|
+
basety = Type::INT
|
104
|
+
if is_type?(peek)
|
105
|
+
basety, _ = read_decl_spec
|
106
|
+
elsif optional
|
107
|
+
Util.errort!(peek, "type expected, but got #{peek}")
|
108
|
+
end
|
109
|
+
ty = read_declarator(name, basety, nil, optional ? DECL::PARAM_TYPEONLY : DECL::PARAM)
|
110
|
+
# C11 6.7.6.3p7: Array of T is adjusted to pointer to T
|
111
|
+
# in a function parameter list.
|
112
|
+
if ty.kind == Kind::ARRAY
|
113
|
+
return Type.make_ptr_type(ty.ptr)
|
114
|
+
end
|
115
|
+
# C11 6.7.6.3p8: Function is adjusted to pointer to function
|
116
|
+
# in a function parameter list.
|
117
|
+
if ty.kind == Kind::FUNC
|
118
|
+
return Type.make_ptr_type(ty)
|
119
|
+
end
|
120
|
+
ty
|
121
|
+
end
|
122
|
+
|
123
|
+
# Reads a K&R-style un-prototyped function parameter list.
|
124
|
+
#
|
125
|
+
# @param [<Node>] vars
|
126
|
+
def read_declarator_params_oldstyle(vars)
|
127
|
+
while true
|
128
|
+
tok = get
|
129
|
+
if tok.kind != T::IDENT
|
130
|
+
Util.errort!(tok, "identifier expected, but got #{tok}")
|
131
|
+
end
|
132
|
+
vars.push(Node.ast_lvar(Type::INT, tok.sval, @localenv, @localvars))
|
133
|
+
if next_token?(')')
|
134
|
+
return
|
135
|
+
end
|
136
|
+
if !next_token?(',')
|
137
|
+
Util.errort!(tok, "comma expected, but got #{get}")
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
#
|
143
|
+
# Function definition
|
144
|
+
#
|
145
|
+
|
146
|
+
# @return [Node]
|
147
|
+
def read_funcdef
|
148
|
+
basetype, sclass = read_decl_spec_opt
|
149
|
+
r = nil
|
150
|
+
|
151
|
+
with_func_context do
|
152
|
+
name = "" # Used as return value
|
153
|
+
params = [] # Used as return value
|
154
|
+
functype = read_declarator(name, basetype, params, DECL::BODY)
|
155
|
+
if functype.oldstyle
|
156
|
+
if (params.size == 0)
|
157
|
+
functype.hasva = false
|
158
|
+
end
|
159
|
+
read_oldstyle_param_type(params)
|
160
|
+
functype.params = param_types(params)
|
161
|
+
end
|
162
|
+
functype.isstatic = (sclass == S::STATIC)
|
163
|
+
Node.ast_gvar(functype, name, @globalenv)
|
164
|
+
expect!('{')
|
165
|
+
r = read_func_body(functype, name, params)
|
166
|
+
backfill_labels!
|
167
|
+
end
|
168
|
+
|
169
|
+
r
|
170
|
+
end
|
171
|
+
|
172
|
+
def with_func_context(&block)
|
173
|
+
@localenv = RMap.new(@globalenv)
|
174
|
+
@gotos = []
|
175
|
+
@labels = RMap.new
|
176
|
+
|
177
|
+
yield
|
178
|
+
|
179
|
+
@localenv = nil
|
180
|
+
@gotos = nil
|
181
|
+
@labels = nil
|
182
|
+
end
|
183
|
+
|
184
|
+
# @param(return) [<Node>] params
|
185
|
+
def read_oldstyle_param_type(params)
|
186
|
+
vars = read_oldstyle_param_args
|
187
|
+
update_oldstyle_param_type(params, vars)
|
188
|
+
end
|
189
|
+
|
190
|
+
def read_oldstyle_param_args
|
191
|
+
orig = @localenv
|
192
|
+
@localenv = nil
|
193
|
+
r = []
|
194
|
+
while true
|
195
|
+
if Token.is_keyword?(peek, '{')
|
196
|
+
break
|
197
|
+
end
|
198
|
+
if !is_type?(peek)
|
199
|
+
Util.errort!(peek, "K&R-style declarator expected, but got #{peek}")
|
200
|
+
end
|
201
|
+
read_decl(r, false)
|
202
|
+
end
|
203
|
+
@localenv = orig
|
204
|
+
r
|
205
|
+
end
|
206
|
+
|
207
|
+
# @param(return) [Array] params
|
208
|
+
# @param [Node] vars
|
209
|
+
def update_oldstyle_param_type(params, vars)
|
210
|
+
vars.each do |decl|
|
211
|
+
Util.assert!{ decl.kind == AST::DECL }
|
212
|
+
var = decl.declvar
|
213
|
+
Util.assert!{ var.kind == AST::LVAR }
|
214
|
+
params.each do |param|
|
215
|
+
Util.assert!{ param.kind == AST::LVAR }
|
216
|
+
if (param.varname != var.varname)
|
217
|
+
next
|
218
|
+
end
|
219
|
+
param.ty = var.ty
|
220
|
+
return # found
|
221
|
+
end
|
222
|
+
raise "missing parameter: #{var.varname}"
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def backfill_labels!
|
227
|
+
@gotos.each do |src|
|
228
|
+
label = src.label
|
229
|
+
dest = @labels[label]
|
230
|
+
if dest.nil?
|
231
|
+
raise "stray #{src.kind == AST::GOTO ? "goto" : "unary &&"}: #{label}"
|
232
|
+
end
|
233
|
+
|
234
|
+
if dest.newlabel
|
235
|
+
src.newlabel = dest.newlabel
|
236
|
+
else
|
237
|
+
src.newlabel = dest.newlabel = @label_gen.next
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
# @param [Type] functype
|
243
|
+
# @param [String] fname
|
244
|
+
# @param [Array] params
|
245
|
+
# @return [Node]
|
246
|
+
def read_func_body(functype, fname, params)
|
247
|
+
r = nil
|
248
|
+
|
249
|
+
with_func_body_context(functype) do
|
250
|
+
funcname = Node.ast_string(ENC::NONE, fname)
|
251
|
+
@localenv["__func__"] = funcname
|
252
|
+
@localenv["__FUNCTION__"] = funcname
|
253
|
+
body = read_compound_stmt
|
254
|
+
r = Node.ast_func(functype, fname, params, body, @localvars)
|
255
|
+
end
|
256
|
+
|
257
|
+
r
|
258
|
+
end
|
259
|
+
|
260
|
+
# @param [Type] functype
|
261
|
+
def with_func_body_context(functype, &block)
|
262
|
+
@localenv = RMap.new(@localenv)
|
263
|
+
@localvars = []
|
264
|
+
@current_func_type = functype
|
265
|
+
|
266
|
+
yield
|
267
|
+
|
268
|
+
@localenv = nil
|
269
|
+
@localvars = nil
|
270
|
+
@current_func_type = nil
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Rucc
|
2
|
+
class Parser
|
3
|
+
module FuncCall
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
# @param [Node] fp
|
8
|
+
def read_funcall(fp)
|
9
|
+
if (fp.kind == AST::ADDR) && (fp.operand.kind == AST::FUNCDESG)
|
10
|
+
desg = fp.operand
|
11
|
+
args = read_func_args(desg.ty.params)
|
12
|
+
return Node.ast_funcall(desg.ty, desg.fname, args)
|
13
|
+
end
|
14
|
+
args = read_func_args(fp.ty.ptr.params)
|
15
|
+
Node.ast_funcptr_call(fp, args)
|
16
|
+
end
|
17
|
+
|
18
|
+
# @param [Array] params
|
19
|
+
# @return [Array]
|
20
|
+
def read_func_args(params)
|
21
|
+
args = []
|
22
|
+
i = 0
|
23
|
+
while true
|
24
|
+
break if next_token?(')')
|
25
|
+
arg = Node.conv(read_assignment_expr)
|
26
|
+
if i < params.size
|
27
|
+
paramtype = params[i]
|
28
|
+
i += 1
|
29
|
+
else
|
30
|
+
paramtype =
|
31
|
+
if Type.is_flotype(arg.ty)
|
32
|
+
Type::DOUBLE
|
33
|
+
elsif Type.is_inttype(arg.ty)
|
34
|
+
Type::INT
|
35
|
+
else
|
36
|
+
arg.ty
|
37
|
+
end
|
38
|
+
end
|
39
|
+
Type.ensure_assignable!(paramtype, arg.ty)
|
40
|
+
if paramtype.kind != arg.ty.kind
|
41
|
+
arg = Node.ast_conv(paramtype, arg)
|
42
|
+
end
|
43
|
+
args.push(arg)
|
44
|
+
tok = get
|
45
|
+
break if Token.is_keyword?(tok, ')')
|
46
|
+
if !Token.is_keyword?(tok, ',')
|
47
|
+
Util.errort(tok, "unexpected token: '#{tok}'")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
args
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Rucc
|
2
|
+
class Parser
|
3
|
+
module Goto
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
# @return [Node]
|
8
|
+
def read_goto_stmt
|
9
|
+
if next_token?('*')
|
10
|
+
# [GNU] computed goto. "goto *p" jumps to the address pointed by p.
|
11
|
+
tok = peek
|
12
|
+
expr = read_cast_expr
|
13
|
+
if expr.ty.kind != Kind::PTR
|
14
|
+
Util.errort!(tok, "pointer expected for computed goto, but got #{expr}")
|
15
|
+
end
|
16
|
+
return Node.ast_computed_goto(expr)
|
17
|
+
end
|
18
|
+
tok = get
|
19
|
+
if !tok || (tok.kind != T::IDENT)
|
20
|
+
Util.errort!(tok, "identifier expected, but got #{tok}")
|
21
|
+
end
|
22
|
+
expect!(';')
|
23
|
+
r = Node.ast_goto(tok.sval)
|
24
|
+
@gotos.push(r)
|
25
|
+
r
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Rucc
|
2
|
+
class Parser
|
3
|
+
module If
|
4
|
+
private
|
5
|
+
def read_if_stmt
|
6
|
+
expect!('(')
|
7
|
+
cond = read_boolean_expr
|
8
|
+
expect!(')')
|
9
|
+
thn = read_stmt
|
10
|
+
if !next_token?(K::ELSE)
|
11
|
+
return Node.ast_if(cond, thn, nil)
|
12
|
+
end
|
13
|
+
els = read_stmt
|
14
|
+
Node.ast_if(cond, thn, els)
|
15
|
+
end
|
16
|
+
|
17
|
+
def read_boolean_expr
|
18
|
+
cond = read_expr
|
19
|
+
Type.is_flotype(cond.ty) ? Node.ast_conv(Type::BOOL, cond) : cond
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|