rucc 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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