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.
- 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,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
|