rucc 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +55 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +5 -0
  5. data/Gemfile +6 -0
  6. data/Gemfile.lock +46 -0
  7. data/LICENCE +21 -0
  8. data/README.md +82 -0
  9. data/Rakefile +2 -0
  10. data/Vagrantfile +10 -0
  11. data/bin/console +10 -0
  12. data/bin/rspec +2 -0
  13. data/bin/setup +8 -0
  14. data/exe/rucc +7 -0
  15. data/include/8cc.h +48 -0
  16. data/include/float.h +44 -0
  17. data/include/iso646.h +20 -0
  18. data/include/rucc.h +2 -0
  19. data/include/stdalign.h +11 -0
  20. data/include/stdarg.h +52 -0
  21. data/include/stdbool.h +11 -0
  22. data/include/stddef.h +15 -0
  23. data/include/stdnoreturn.h +8 -0
  24. data/lib/rucc.rb +8 -0
  25. data/lib/rucc/case.rb +22 -0
  26. data/lib/rucc/decl.rb +9 -0
  27. data/lib/rucc/enc.rb +9 -0
  28. data/lib/rucc/engine.rb +138 -0
  29. data/lib/rucc/file_io.rb +108 -0
  30. data/lib/rucc/file_io_list.rb +56 -0
  31. data/lib/rucc/gen.rb +1602 -0
  32. data/lib/rucc/int_evaluator.rb +114 -0
  33. data/lib/rucc/k.rb +73 -0
  34. data/lib/rucc/keyword.rb +17 -0
  35. data/lib/rucc/kind.rb +43 -0
  36. data/lib/rucc/label_gen.rb +13 -0
  37. data/lib/rucc/lexer.rb +40 -0
  38. data/lib/rucc/lexer/impl.rb +683 -0
  39. data/lib/rucc/lexer/preprocessor.rb +888 -0
  40. data/lib/rucc/lexer/preprocessor/cond_incl.rb +27 -0
  41. data/lib/rucc/lexer/preprocessor/constructor.rb +54 -0
  42. data/lib/rucc/lexer/preprocessor/pragma.rb +31 -0
  43. data/lib/rucc/lexer/preprocessor/special_macro.rb +110 -0
  44. data/lib/rucc/libc.rb +47 -0
  45. data/lib/rucc/m.rb +7 -0
  46. data/lib/rucc/macro.rb +24 -0
  47. data/lib/rucc/node.rb +530 -0
  48. data/lib/rucc/node/conv.rb +33 -0
  49. data/lib/rucc/op.rb +61 -0
  50. data/lib/rucc/operator.rb +13 -0
  51. data/lib/rucc/option.rb +30 -0
  52. data/lib/rucc/parser.rb +961 -0
  53. data/lib/rucc/parser/break.rb +18 -0
  54. data/lib/rucc/parser/builtin.rb +25 -0
  55. data/lib/rucc/parser/continue.rb +18 -0
  56. data/lib/rucc/parser/do.rb +33 -0
  57. data/lib/rucc/parser/ensure.rb +39 -0
  58. data/lib/rucc/parser/enum.rb +64 -0
  59. data/lib/rucc/parser/expr.rb +493 -0
  60. data/lib/rucc/parser/for.rb +71 -0
  61. data/lib/rucc/parser/func.rb +274 -0
  62. data/lib/rucc/parser/func_call.rb +54 -0
  63. data/lib/rucc/parser/goto.rb +29 -0
  64. data/lib/rucc/parser/if.rb +23 -0
  65. data/lib/rucc/parser/initializer.rb +237 -0
  66. data/lib/rucc/parser/label.rb +31 -0
  67. data/lib/rucc/parser/return.rb +16 -0
  68. data/lib/rucc/parser/struct_and_union.rb +280 -0
  69. data/lib/rucc/parser/switch.rb +117 -0
  70. data/lib/rucc/parser/while.rb +29 -0
  71. data/lib/rucc/pos.rb +11 -0
  72. data/lib/rucc/rmap.rb +22 -0
  73. data/lib/rucc/s.rb +9 -0
  74. data/lib/rucc/static_label_gen.rb +15 -0
  75. data/lib/rucc/t.rb +18 -0
  76. data/lib/rucc/tempname_gen.rb +14 -0
  77. data/lib/rucc/token.rb +114 -0
  78. data/lib/rucc/token_gen.rb +68 -0
  79. data/lib/rucc/type.rb +304 -0
  80. data/lib/rucc/type/check.rb +39 -0
  81. data/lib/rucc/type/conv.rb +29 -0
  82. data/lib/rucc/type_info.rb +21 -0
  83. data/lib/rucc/utf.rb +126 -0
  84. data/lib/rucc/util.rb +111 -0
  85. data/lib/rucc/version.rb +3 -0
  86. data/rucc.gemspec +38 -0
  87. 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