module Rucc::Parser::StructAndUnion
Private Instance Methods
compute_padding(offset, align)
click to toggle source
@param [Integer] off @param [Integer] align @return [Integer]
# File lib/rucc/parser/struct_and_union.rb, line 244 def compute_padding(offset, align) ((offset % align) == 0) ? 0 : (align - (offset % align)) end
finish_bitfield(off, bitoff)
click to toggle source
@param [Integer] off @param [Integer] bitoff @return [<Integer, Integer>] off, bitoff
# File lib/rucc/parser/struct_and_union.rb, line 235 def finish_bitfield(off, bitoff) off += (bitoff + 7) / 8 bitoff = 0 return off, bitoff end
fix_rectype_flexible_member(fields)
click to toggle source
# File lib/rucc/parser/struct_and_union.rb, line 124 def fix_rectype_flexible_member(fields) fields.each_with_index do |pair, i| name = pair[0] ty = pair[1] next if ty.kind != Kind::ARRAY if ty.len == -1 if i != (fields.size - 1) raise "flexible member may only appear as the last member: #{ty} #{name}" end if fields.size == 1 raise "flexible member with no other fields: #{ty} #{name}" end ty.len = 0; ty.size = 0; end end end
read_bitsize(name, ty)
click to toggle source
@param [String] name @param [Type] ty @return [integer]
# File lib/rucc/parser/struct_and_union.rb, line 251 def read_bitsize(name, ty) if !Type.is_inttype(ty) raise "non-integer type cannot be a bitfield: #{ty}" end tok = peek r = read_intexpr maxsize = ty.kind == Kind::BOOL ? 1 : ty.size * 8 if (r < 0) || (maxsize < r) Util.errort!(tok, "invalid bitfield size for #{ty}: #{r}") end if (r == 0) && name != "" Util.errort(tok, "zero-width bitfield needs to be unnamed: #{name}") end r end
read_rectype_def(is_struct)
click to toggle source
@param [Boolean] is_struct @return [Type]
# File lib/rucc/parser/struct_and_union.rb, line 34 def read_rectype_def(is_struct) tag = read_rectype_tag if !tag.nil? r = @tags[tag] if r && ((r.kind == Kind::ENUM) || (r.is_struct != is_struct)) raise "declarations of #{tag} does not match" end if r.nil? r = Type.make_rectype(is_struct) @tags[tag] = r end else r = Type.make_rectype(is_struct) end size = 0 align = 1 size, align, fields = read_rectype_fields(size, align, is_struct) r.align = align if !fields.nil? r.fields = fields r.size = size end r end
read_rectype_fields(rsize, align, is_struct)
click to toggle source
@param [Integer] rsize @param [Integer] align @parsm [Boolean] is_struct @return [<Integer, Integer, Hash>]
# File lib/rucc/parser/struct_and_union.rb, line 73 def read_rectype_fields(rsize, align, is_struct) if !next_token?('{') return rsize, align, nil end fields = read_rectype_fields_sub fix_rectype_flexible_member(fields) if is_struct return update_struct_offset(rsize, align, fields) end update_union_offset(rsize, align, fields) end
read_rectype_fields_sub()
click to toggle source
@return [Array]
# File lib/rucc/parser/struct_and_union.rb, line 86 def read_rectype_fields_sub r = [] while true if next_token?(K::STATIC_ASSERT) read_static_assert next end if !is_type?(peek) break end basetype, _ = read_decl_spec if (basetype.kind == Kind::STRUCT) && next_token?(';') r.push(["", basetype]) next end while true name = "" fieldtype = read_declarator(name, basetype, nil, DECL::PARAM_TYPEONLY) ensure_not_void!(fieldtype) fieldtype = fieldtype.dup fieldtype.bitsize = next_token?(':') ? read_bitsize(name, fieldtype) : -1 r.push([name, fieldtype]) if next_token?(',') next end if Token.is_keyword?(peek, '}') # TODO(south37) Impl warnt when necessary # warnt(peek(), "missing ';' at the end of field list"); else expect!(';') end break end end expect!('}') r end
read_rectype_tag()
click to toggle source
@return [String]
# File lib/rucc/parser/struct_and_union.rb, line 60 def read_rectype_tag tok = get if tok.kind == T::IDENT return tok.sval end @lexer.unget_token(tok) nil end
read_struct_def()
click to toggle source
@return [Type]
# File lib/rucc/parser/struct_and_union.rb, line 23 def read_struct_def read_rectype_def(true) end
read_struct_field(struct)
click to toggle source
@param [Node] struct
# File lib/rucc/parser/struct_and_union.rb, line 7 def read_struct_field(struct) if struct.ty.kind != Kind::STRUCT raise "struct expected, but got #{struct}" end name = get if name.kind != T::IDENT raise "field name expected, but got #{name}" end field = struct.ty.fields[name.sval] if field.nil? raise "struct has no such field: #{name}" end Node.ast_struct_ref(field, struct, name.sval) end
read_union_def()
click to toggle source
@return [Type]
# File lib/rucc/parser/struct_and_union.rb, line 28 def read_union_def read_rectype_def(false) end
squash_unnamed_struct(dict, unnamed, offset)
click to toggle source
@param [Hash] dict @param [Type] unnamed @param [Integer] offset
# File lib/rucc/parser/struct_and_union.rb, line 270 def squash_unnamed_struct(dict, unnamed, offset) keys = unnamed.fields.keys keys.each do |name| t = unnamed.fields[name].dup t.offset += offset dict[name] = t end end
update_struct_offset(rsize, align, fields)
click to toggle source
@param [Integer] rsize @param [Integer] align @param [Array] fields @return [<Integer, Integer, Hash>]
# File lib/rucc/parser/struct_and_union.rb, line 146 def update_struct_offset(rsize, align, fields) off = 0 bitoff = 0 r = {} fields.each do |(name, fieldtype)| # C11 6.7.2.1p14: Each member is aligned to its natural boundary. # As a result the entire struct is aligned to the largest among its members. # Unnamed fields will never be accessed, so they shouldn't be taken into account # when calculating alignment. if name != "" align = [align, fieldtype.align].max end if name == "" && (fieldtype.kind == Kind::STRUCT) # C11 6.7.2.1p13: Anonymous struct off, bitoff = finish_bitfield(off, bitoff) off += compute_padding(off, fieldtype.align) squash_unnamed_struct(r, fieldtype, off) off += fieldtype.size next end if fieldtype.bitsize == 0 # C11 6.7.2.1p12: The zero-size bit-field indicates the end of the # current run of the bit-fields. off, bitoff = finish_bitfield(off, bitoff) off += compute_padding(off, fieldtype.align) bitoff = 0 next end if fieldtype.bitsize && fieldtype.bitsize > 0 bit = fieldtype.size * 8 room = bit - ((off * 8 + bitoff) % bit) if fieldtype.bitsize <= room fieldtype.offset = off fieldtype.bitoff = bitoff else off, bitoff = finish_bitfield(off, bitoff) off += compute_padding(off, fieldtype.align) fieldtype.offset = off fieldtype.bitoff = 0 end bitoff += fieldtype.bitsize else off, bitoff = finish_bitfield(off, bitoff) off += compute_padding(off, fieldtype.align) fieldtype.offset = off off += fieldtype.size end if name != "" r[name] = fieldtype end end off, bitoff = finish_bitfield(off, bitoff) rsize = off + compute_padding(off, align) return rsize, align, r end
update_union_offset(rsize, align, fields)
click to toggle source
@param [Integer] rsize @param [Integer] align @param [Array] fields @return [<Integer, Integer, Hash>]
# File lib/rucc/parser/struct_and_union.rb, line 210 def update_union_offset(rsize, align, fields) maxsize = 0 r = {} fields.each do |(name, fieldtype)| maxsize = [maxsize, fieldtype.size].max align = [align, fieldtype.align].max if name == "" && (fieldtype.kind == Kind::STRUCT) squash_unnamed_struct(r, fieldtype, 0) next end fieldtype.offset = 0 if fieldtype.bitsize.nil? || fieldtype.bitsize >= 0 fieldtype.bitoff = 0 end if name r[name] = fieldtype end end rsize = maxsize + compute_padding(maxsize, align) return rsize, align, r end