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,237 @@
1
+ module Rucc
2
+ class Parser
3
+ module Initializer
4
+
5
+ private
6
+
7
+ # @param [Type] ty
8
+ # @return [Array]
9
+ def read_decl_init(ty)
10
+ r = []
11
+ if Token.is_keyword?(peek, '{') || Type.is_string(ty)
12
+ read_initializer_list(r, ty, 0, false)
13
+ else
14
+ init = Node.conv(read_assignment_expr)
15
+ if Type.is_arithtype(init.ty) && init.ty.kind != ty.kind
16
+ init = Node.ast_conv(ty, init)
17
+ end
18
+ r.push Node.ast_init(init, ty, 0)
19
+ end
20
+ r
21
+ end
22
+
23
+ # @param(return) [Array] inits
24
+ # @param [Type] ty
25
+ # @param [Integer] off
26
+ # @param [Boolean] designated
27
+ def read_initializer_list(inits, ty, off, designated)
28
+ tok = get
29
+ if Type.is_string(ty)
30
+ if tok.kind == T::STRING
31
+ assign_string(inits, ty, tok.sval, off)
32
+ return
33
+ end
34
+
35
+ if Token.is_keyword?(tok, '{') && (peek.kind == T::STRING)
36
+ tok = get
37
+ assign_string(inits, ty, tok.sval, off)
38
+ expect!('}')
39
+ return
40
+ end
41
+ end
42
+ @lexer.unget_token(tok)
43
+ if ty.kind == Kind::ARRAY
44
+ read_array_initializer(inits, ty, off, designated)
45
+ elsif ty.kind == Kind::STRUCT
46
+ read_struct_initializer(inits, ty, off, designated)
47
+ else
48
+ arraytype = Type.make_array_type(ty, 1)
49
+ read_array_initializer(inits, arraytype, off, designated)
50
+ end
51
+ end
52
+
53
+ # @param(return) [Array] inits
54
+ # @param [Type] ty
55
+ # @param [Integer] off
56
+ # @param [Boolean] designated
57
+ def read_array_initializer(inits, ty, off, designated)
58
+ read_array_initializer_sub(inits, ty, off, designated)
59
+ sort_inits!(inits)
60
+ end
61
+
62
+ # @param(return) [Array] inits
63
+ # @param(return) [Type] ty
64
+ # @param [Integer] off
65
+ # @param [Boolean] designated
66
+ def read_array_initializer_sub(inits, ty, off, designated)
67
+ has_brace = maybe_read_brace!
68
+ flexible = ty.len <= 0
69
+ elemsize = ty.ptr.size
70
+ i = 0
71
+ while flexible || i < ty.len
72
+ tok = get
73
+ if Token.is_keyword?(tok, '}')
74
+ if !has_brace
75
+ @lexer.unget_token(tok)
76
+ end
77
+ read_array_initializer_type(ty, elemsize, i)
78
+ return
79
+ end
80
+ if (Token.is_keyword?(tok, '.') || Token.is_keyword?(tok, '[')) && !has_brace && !designated
81
+ @lexer.unget_token(tok)
82
+ return
83
+ end
84
+ if Token.is_keyword?(tok, '[')
85
+ tok = peek
86
+ idx = read_intexpr
87
+ if (idx < 0) || (!flexible && ty.len <= idx)
88
+ Util.errort!(tok, "array designator exceeds array bounds: #{idx}")
89
+ end
90
+ i = idx
91
+ expect!(']')
92
+ designated = true
93
+ else
94
+ @lexer.unget_token(tok)
95
+ end
96
+ read_initializer_elem(inits, ty.ptr, off + elemsize * i, designated)
97
+ maybe_skip_comma!
98
+ designated = false
99
+ i += 1
100
+ end
101
+ if has_brace
102
+ skip_to_brace!
103
+ end
104
+ read_array_initializer_type(ty, elemsize, i)
105
+ end
106
+
107
+ # @param(return) [Type] ty
108
+ # @param [Integer] elemsize
109
+ # @param [Integer] i
110
+ def read_array_initializer_type(ty, elemsize, i)
111
+ if ty.len < 0
112
+ ty.len = i
113
+ ty.size = elemsize * i
114
+ end
115
+ end
116
+
117
+ # @param(return) [Array] inits
118
+ # @param [Type] ty
119
+ # @param [Integer] off
120
+ # @param [Boolean] designated
121
+ def read_struct_initializer(inits, ty, off, designated)
122
+ read_struct_initializer_sub(inits, ty, off, designated)
123
+ sort_inits!(inits)
124
+ end
125
+
126
+ # @param(return) [Array] inits
127
+ # @param [Type] ty
128
+ # @param [Integer] off
129
+ # @param [Boolean] designated
130
+ def read_struct_initializer_sub(inits, ty, off, designated)
131
+ has_brace = maybe_read_brace!
132
+ keys = ty.fields.keys
133
+ i = 0
134
+ while true
135
+ tok = get
136
+ if Token.is_keyword?(tok, '}')
137
+ if !has_brace
138
+ @lexer.unget_token(tok)
139
+ end
140
+ return
141
+ end
142
+ if (Token.is_keyword?(tok, '.') || Token.is_keyword?(tok, '[')) && !has_brace && !designated
143
+ @lexer.unget_token(tok)
144
+ return
145
+ end
146
+ if Token.is_keyword?(tok, '.')
147
+ tok = get
148
+ if !tok || (tok.kind != T::IDENT)
149
+ Util.errort!(tok, "malformed desginated initializer: #{tok}")
150
+ end
151
+ fieldname = tok.sval
152
+ fieldtype = ty.fields[fieldname]
153
+ if !fieldtype
154
+ Util.errort!(tok, "field does not exist: #{tok}")
155
+ end
156
+ keys = ty.fields.keys
157
+ i = 0
158
+ while i < keys.size
159
+ s = keys[i]
160
+ i += 1
161
+ if fieldname == s
162
+ break
163
+ end
164
+ end
165
+ designated = true
166
+ else
167
+ @lexer.unget_token(tok)
168
+ if i == keys.size
169
+ break
170
+ end
171
+ fieldname = keys[i]
172
+ i += 1
173
+ fieldtype = ty.fields[fieldname]
174
+ end
175
+ read_initializer_elem(inits, fieldtype, off + fieldtype.offset, designated)
176
+ maybe_skip_comma!
177
+ designated = false
178
+ if !ty.is_struct
179
+ break
180
+ end
181
+ end
182
+ if has_brace
183
+ skip_to_brace!
184
+ end
185
+ end
186
+
187
+ # @param(return) [Array] inits
188
+ # @param(return) [Type] ty
189
+ # @param [Integer] off
190
+ # @param [Boolean] designated
191
+ def read_initializer_elem(inits, ty, off, designated)
192
+ next_token?('=')
193
+ if (ty.kind == Kind::ARRAY) || (ty.kind == Kind::STRUCT)
194
+ read_initializer_list(inits, ty, off, designated)
195
+ elsif next_token?('{')
196
+ read_initializer_elem(inits, ty, off, true)
197
+ expect!('}')
198
+ else
199
+ expr = Node.conv(read_assignment_expr)
200
+ Type.ensure_assignable!(ty, expr.ty)
201
+ inits.push(Node.ast_init(expr, ty, off))
202
+ end
203
+ end
204
+
205
+ def sort_inits!(inits)
206
+ inits.sort_by! { |init| init.initoff }
207
+ end
208
+
209
+ # @return [Boolean]
210
+ def maybe_read_brace!
211
+ next_token?('{')
212
+ end
213
+
214
+ def maybe_skip_comma!
215
+ next_token?(',')
216
+ end
217
+
218
+ def skip_to_brace!
219
+ while true
220
+ if next_token?('}')
221
+ return
222
+ end
223
+ if next_token?('.')
224
+ get
225
+ expect!('=')
226
+ end
227
+ # tok = peek
228
+ ignore = read_assignment_expr
229
+ return if !ignore
230
+ # TODO(south37) Impl warnt when necessary
231
+ # warnt(tok, "excessive initializer: %s", node2s(ignore));
232
+ maybe_skip_comma!();
233
+ end
234
+ end
235
+ end
236
+ end
237
+ end
@@ -0,0 +1,31 @@
1
+ module Rucc
2
+ class Parser
3
+ module Label
4
+
5
+ private
6
+
7
+ # @param [Token] tok
8
+ # @return [Node]
9
+ def read_label(tok)
10
+ label = tok.sval
11
+ if @labels[label]
12
+ Util.errort!(tok, "duplicate label: #{tok}")
13
+ end
14
+ r = Node.ast_label(label)
15
+ @labels[label] = r
16
+ read_label_tail(r)
17
+ end
18
+
19
+ # @param [Node] label
20
+ # @return [Node]
21
+ def read_label_tail(label)
22
+ stmt = read_stmt
23
+ v = [label]
24
+ if stmt
25
+ v.push(stmt)
26
+ end
27
+ Node.ast_compound_stmt(v)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,16 @@
1
+ module Rucc
2
+ class Parser
3
+ module Return
4
+ private
5
+
6
+ def read_return_stmt
7
+ retval = read_expr_opt
8
+ expect!(';')
9
+ if !retval.nil?
10
+ return Node.ast_return(Node.ast_conv(@current_func_type.rettype, retval))
11
+ end
12
+ Node.ast_return(nil)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,280 @@
1
+ module Rucc
2
+ class Parser
3
+ module StructAndUnion
4
+ private
5
+
6
+ # @param [Node] struct
7
+ def read_struct_field(struct)
8
+ if struct.ty.kind != Kind::STRUCT
9
+ raise "struct expected, but got #{struct}"
10
+ end
11
+ name = get
12
+ if name.kind != T::IDENT
13
+ raise "field name expected, but got #{name}"
14
+ end
15
+ field = struct.ty.fields[name.sval]
16
+ if field.nil?
17
+ raise "struct has no such field: #{name}"
18
+ end
19
+ Node.ast_struct_ref(field, struct, name.sval)
20
+ end
21
+
22
+ # @return [Type]
23
+ def read_struct_def
24
+ read_rectype_def(true)
25
+ end
26
+
27
+ # @return [Type]
28
+ def read_union_def
29
+ read_rectype_def(false)
30
+ end
31
+
32
+ # @param [Boolean] is_struct
33
+ # @return [Type]
34
+ def read_rectype_def(is_struct)
35
+ tag = read_rectype_tag
36
+ if !tag.nil?
37
+ r = @tags[tag]
38
+ if r && ((r.kind == Kind::ENUM) || (r.is_struct != is_struct))
39
+ raise "declarations of #{tag} does not match"
40
+ end
41
+ if r.nil?
42
+ r = Type.make_rectype(is_struct)
43
+ @tags[tag] = r
44
+ end
45
+ else
46
+ r = Type.make_rectype(is_struct)
47
+ end
48
+ size = 0
49
+ align = 1
50
+ size, align, fields = read_rectype_fields(size, align, is_struct)
51
+ r.align = align
52
+ if !fields.nil?
53
+ r.fields = fields
54
+ r.size = size
55
+ end
56
+ r
57
+ end
58
+
59
+ # @return [String]
60
+ def read_rectype_tag
61
+ tok = get
62
+ if tok.kind == T::IDENT
63
+ return tok.sval
64
+ end
65
+ @lexer.unget_token(tok)
66
+ nil
67
+ end
68
+
69
+ # @param [Integer] rsize
70
+ # @param [Integer] align
71
+ # @parsm [Boolean] is_struct
72
+ # @return [<Integer, Integer, Hash>]
73
+ def read_rectype_fields(rsize, align, is_struct)
74
+ if !next_token?('{')
75
+ return rsize, align, nil
76
+ end
77
+ fields = read_rectype_fields_sub
78
+ fix_rectype_flexible_member(fields)
79
+ if is_struct
80
+ return update_struct_offset(rsize, align, fields)
81
+ end
82
+ update_union_offset(rsize, align, fields)
83
+ end
84
+
85
+ # @return [Array]
86
+ def read_rectype_fields_sub
87
+ r = []
88
+ while true
89
+ if next_token?(K::STATIC_ASSERT)
90
+ read_static_assert
91
+ next
92
+ end
93
+ if !is_type?(peek)
94
+ break
95
+ end
96
+ basetype, _ = read_decl_spec
97
+ if (basetype.kind == Kind::STRUCT) && next_token?(';')
98
+ r.push(["", basetype])
99
+ next
100
+ end
101
+ while true
102
+ name = ""
103
+ fieldtype = read_declarator(name, basetype, nil, DECL::PARAM_TYPEONLY)
104
+ ensure_not_void!(fieldtype)
105
+ fieldtype = fieldtype.dup
106
+ fieldtype.bitsize = next_token?(':') ? read_bitsize(name, fieldtype) : -1
107
+ r.push([name, fieldtype])
108
+ if next_token?(',')
109
+ next
110
+ end
111
+ if Token.is_keyword?(peek, '}')
112
+ # TODO(south37) Impl warnt when necessary
113
+ # warnt(peek(), "missing ';' at the end of field list");
114
+ else
115
+ expect!(';')
116
+ end
117
+ break
118
+ end
119
+ end
120
+ expect!('}')
121
+ r
122
+ end
123
+
124
+ def fix_rectype_flexible_member(fields)
125
+ fields.each_with_index do |pair, i|
126
+ name = pair[0]
127
+ ty = pair[1]
128
+ next if ty.kind != Kind::ARRAY
129
+ if ty.len == -1
130
+ if i != (fields.size - 1)
131
+ raise "flexible member may only appear as the last member: #{ty} #{name}"
132
+ end
133
+ if fields.size == 1
134
+ raise "flexible member with no other fields: #{ty} #{name}"
135
+ end
136
+ ty.len = 0;
137
+ ty.size = 0;
138
+ end
139
+ end
140
+ end
141
+
142
+ # @param [Integer] rsize
143
+ # @param [Integer] align
144
+ # @param [Array] fields
145
+ # @return [<Integer, Integer, Hash>]
146
+ def update_struct_offset(rsize, align, fields)
147
+ off = 0
148
+ bitoff = 0
149
+ r = {}
150
+ fields.each do |(name, fieldtype)|
151
+ # C11 6.7.2.1p14: Each member is aligned to its natural boundary.
152
+ # As a result the entire struct is aligned to the largest among its members.
153
+ # Unnamed fields will never be accessed, so they shouldn't be taken into account
154
+ # when calculating alignment.
155
+ if name != ""
156
+ align = [align, fieldtype.align].max
157
+ end
158
+
159
+ if name == "" && (fieldtype.kind == Kind::STRUCT)
160
+ # C11 6.7.2.1p13: Anonymous struct
161
+ off, bitoff = finish_bitfield(off, bitoff)
162
+ off += compute_padding(off, fieldtype.align)
163
+ squash_unnamed_struct(r, fieldtype, off)
164
+ off += fieldtype.size
165
+ next
166
+ end
167
+
168
+ if fieldtype.bitsize == 0
169
+ # C11 6.7.2.1p12: The zero-size bit-field indicates the end of the
170
+ # current run of the bit-fields.
171
+ off, bitoff = finish_bitfield(off, bitoff)
172
+ off += compute_padding(off, fieldtype.align)
173
+ bitoff = 0
174
+ next
175
+ end
176
+
177
+ if fieldtype.bitsize && fieldtype.bitsize > 0
178
+ bit = fieldtype.size * 8
179
+ room = bit - ((off * 8 + bitoff) % bit)
180
+ if fieldtype.bitsize <= room
181
+ fieldtype.offset = off
182
+ fieldtype.bitoff = bitoff
183
+ else
184
+ off, bitoff = finish_bitfield(off, bitoff)
185
+ off += compute_padding(off, fieldtype.align)
186
+ fieldtype.offset = off
187
+ fieldtype.bitoff = 0
188
+ end
189
+ bitoff += fieldtype.bitsize
190
+ else
191
+ off, bitoff = finish_bitfield(off, bitoff)
192
+ off += compute_padding(off, fieldtype.align)
193
+ fieldtype.offset = off
194
+ off += fieldtype.size
195
+ end
196
+
197
+ if name != ""
198
+ r[name] = fieldtype
199
+ end
200
+ end
201
+ off, bitoff = finish_bitfield(off, bitoff)
202
+ rsize = off + compute_padding(off, align)
203
+ return rsize, align, r
204
+ end
205
+
206
+ # @param [Integer] rsize
207
+ # @param [Integer] align
208
+ # @param [Array] fields
209
+ # @return [<Integer, Integer, Hash>]
210
+ def update_union_offset(rsize, align, fields)
211
+ maxsize = 0
212
+ r = {}
213
+ fields.each do |(name, fieldtype)|
214
+ maxsize = [maxsize, fieldtype.size].max
215
+ align = [align, fieldtype.align].max
216
+ if name == "" && (fieldtype.kind == Kind::STRUCT)
217
+ squash_unnamed_struct(r, fieldtype, 0)
218
+ next
219
+ end
220
+ fieldtype.offset = 0
221
+ if fieldtype.bitsize.nil? || fieldtype.bitsize >= 0
222
+ fieldtype.bitoff = 0
223
+ end
224
+ if name
225
+ r[name] = fieldtype
226
+ end
227
+ end
228
+ rsize = maxsize + compute_padding(maxsize, align)
229
+ return rsize, align, r
230
+ end
231
+
232
+ # @param [Integer] off
233
+ # @param [Integer] bitoff
234
+ # @return [<Integer, Integer>] off, bitoff
235
+ def finish_bitfield(off, bitoff)
236
+ off += (bitoff + 7) / 8
237
+ bitoff = 0
238
+ return off, bitoff
239
+ end
240
+
241
+ # @param [Integer] off
242
+ # @param [Integer] align
243
+ # @return [Integer]
244
+ def compute_padding(offset, align)
245
+ ((offset % align) == 0) ? 0 : (align - (offset % align))
246
+ end
247
+
248
+ # @param [String] name
249
+ # @param [Type] ty
250
+ # @return [integer]
251
+ def read_bitsize(name, ty)
252
+ if !Type.is_inttype(ty)
253
+ raise "non-integer type cannot be a bitfield: #{ty}"
254
+ end
255
+ tok = peek
256
+ r = read_intexpr
257
+ maxsize = ty.kind == Kind::BOOL ? 1 : ty.size * 8
258
+ if (r < 0) || (maxsize < r)
259
+ Util.errort!(tok, "invalid bitfield size for #{ty}: #{r}")
260
+ end
261
+ if (r == 0) && name != ""
262
+ Util.errort(tok, "zero-width bitfield needs to be unnamed: #{name}")
263
+ end
264
+ r
265
+ end
266
+
267
+ # @param [Hash] dict
268
+ # @param [Type] unnamed
269
+ # @param [Integer] offset
270
+ def squash_unnamed_struct(dict, unnamed, offset)
271
+ keys = unnamed.fields.keys
272
+ keys.each do |name|
273
+ t = unnamed.fields[name].dup
274
+ t.offset += offset
275
+ dict[name] = t
276
+ end
277
+ end
278
+ end
279
+ end
280
+ end