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,117 @@
1
+ require "rucc/case"
2
+
3
+ module Rucc
4
+ class Parser
5
+ module Switch
6
+
7
+ private
8
+
9
+ # @return [Node]
10
+ def read_switch_stmt
11
+ expect!('(')
12
+ expr = Node.conv(read_expr)
13
+ ensure_inttype!(expr)
14
+ expect!(')')
15
+
16
+ e = @label_gen.next
17
+ v = []
18
+ with_switch_context(e) do
19
+ body = read_stmt
20
+ var = Node.ast_lvar(expr.ty, @tempname_gen.next, @localenv, @localvars)
21
+ v.push(Node.ast_binop(expr.ty, '=', var, expr))
22
+ @cases.each do |c|
23
+ v.push(make_switch_jump(var, c))
24
+ end
25
+ v.push(Node.ast_jump(@defaultcase ? @defaultcase : e))
26
+ if body
27
+ v.push(body)
28
+ end
29
+ v.push(Node.ast_dest(e))
30
+ end
31
+ Node.ast_compound_stmt(v)
32
+ end
33
+
34
+ def with_switch_context(brk, &block)
35
+ # Set switch context
36
+ ocases = @cases
37
+ odefaultcase = @defaultcase
38
+ obreak = @lbreak
39
+ @cases = []
40
+ @defaultcase = nil
41
+ @lbreak = brk
42
+
43
+ yield
44
+
45
+ # Restore switch context
46
+ @cases = ocases
47
+ @defaultcase = odefaultcase
48
+ @lbreak = obreak
49
+ end
50
+
51
+ # @param [Node] var
52
+ # @param [Case] c
53
+ # @return [Node]
54
+ def make_switch_jump(var, c)
55
+ if c.b == c.e
56
+ cond = Node.ast_binop(Type::INT, OP::EQ, var, Node.ast_inttype(Type::INT, c.b))
57
+ else
58
+ # [GNU] case i ... j is compiled to if (i <= cond && cond <= j) goto <label>.
59
+ x = Node.ast_binop(Type::INT, OP::LE, Node.ast_inttype(Type::INT, c.b), var)
60
+ y = Node.ast_binop(Type::INT, OP::LE, var, Node.ast_inttype(Type::INT, c.e))
61
+ cond = Node.ast_binop(Type::INT, OP::LOGAND, x, y)
62
+ end
63
+ Node.ast_if(cond, Node.ast_jump(c.label), nil)
64
+ end
65
+
66
+ # @return [Node]
67
+ def read_case_label(tok)
68
+ if !@cases
69
+ Util.errort!(tok, "stray case label")
70
+ end
71
+ label = @label_gen.next
72
+ b = read_intexpr
73
+ if next_token?(K::ELLIPSIS)
74
+ e = read_intexpr
75
+ expect!(':')
76
+ if b > e
77
+ Util.errort!(tok, "case region is not in correct order: #{b} ... #{e}")
78
+ end
79
+ @cases.push(Case.make_case(b, e, label))
80
+ else
81
+ expect!(':')
82
+ @cases.push(Case.make_case(b, b, label))
83
+ end
84
+ check_case_duplicates!
85
+ read_label_tail(Node.ast_dest(label))
86
+ end
87
+
88
+ # C11 6.8.4.2p3: No two case constant expressions have the same value.
89
+ def check_case_duplicates!
90
+ len = @cases.size
91
+ x = @cases[len - 1]
92
+ @cases[0..-2].each do |y|
93
+ if (x.e < y.b) || (y.e < x.b)
94
+ next
95
+ end
96
+ if (x.b == x.e)
97
+ raise "duplicate case value: #{x.b}"
98
+ # error("duplicate case value: %d", x->beg)
99
+ end
100
+ raise "duplicate case value: #{x.b} ... #{x.e}"
101
+ # error("duplicate case value: #{x.b} ... #{x.e}")
102
+ end
103
+ end
104
+
105
+ # @param [Token] tok
106
+ # @return [Node]
107
+ def read_default_label(tok)
108
+ expect!(':');
109
+ if @defaultcase
110
+ Util.errort!(tok, "duplicate default")
111
+ end
112
+ @defaultcase = @label_gen.next
113
+ read_label_tail(Node.ast_dest(@defaultcase))
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,29 @@
1
+ module Rucc
2
+ class Parser
3
+ module While
4
+
5
+ private
6
+
7
+ # @param [Token] tok
8
+ # @return [Node]
9
+ def read_while_stmt
10
+ expect!('(')
11
+ cond = read_boolean_expr
12
+ expect!(')')
13
+
14
+ b = @label_gen.next
15
+ e = @label_gen.next
16
+
17
+ body = nil # declaration for ruby
18
+ with_jump_labels(b, e) { body = read_stmt }
19
+
20
+ v = []
21
+ v.push(Node.ast_dest(b))
22
+ v.push(Node.ast_if(cond, body, Node.ast_jump(e)))
23
+ v.push(Node.ast_jump(b))
24
+ v.push(Node.ast_dest(e))
25
+ Node.ast_compound_stmt(v)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,11 @@
1
+ module Rucc
2
+ class Pos
3
+ # @param [Integer] line
4
+ # @param [Integer] column
5
+ def initialize(line, column)
6
+ @line = line
7
+ @column = column
8
+ end
9
+ attr_reader :line, :column
10
+ end
11
+ end
@@ -0,0 +1,22 @@
1
+ module Rucc
2
+ # RMap -- Map with recursive search
3
+ class RMap
4
+ # @param [RMap, NilClass] parent
5
+ def initialize(parent = nil)
6
+ @parent = parent
7
+ @hash = {}
8
+ end
9
+
10
+ def [](k)
11
+ v = @hash[k]
12
+ if v.nil? && !@parent.nil?
13
+ v = @parent[k]
14
+ end
15
+ v
16
+ end
17
+
18
+ def []=(k, v)
19
+ @hash[k] = v
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,9 @@
1
+ module Rucc
2
+ module S
3
+ TYPEDEF = "S::TYPEDEF"
4
+ EXTERN = "S::EXTERN"
5
+ STATIC = "S::STATIC"
6
+ AUTO = "S::AUTO"
7
+ REGISTER = "S::REGISTER"
8
+ end
9
+ end
@@ -0,0 +1,15 @@
1
+ module Rucc
2
+ class StaticLabelGen
3
+ def initialize
4
+ @id = 0 # [Integer]
5
+ end
6
+
7
+ # @param [String]
8
+ # @return [String]
9
+ def next(name)
10
+ static_label = ".S#{@id}.#{name}"
11
+ @id += 1
12
+ static_label
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ module Rucc
2
+ module T
3
+ IDENT = "T::IDENT".freeze
4
+ KEYWORD = "T::KEYWORD".freeze
5
+ NUMBER = "T::NUMBER".freeze
6
+ CHAR = "T::CHAR".freeze
7
+ STRING = "T::STRING".freeze
8
+ EOF = "T::EOF".freeze
9
+ INVALID = "T::INVALID".freeze
10
+
11
+ # Only in preprocessor
12
+ NEWLINE = "T::NEWLINE".freeze
13
+ SPACE = "T::SPACE".freeze
14
+ MACRO_PARAM = "T::MACRO_PARAM".freeze
15
+
16
+ CPP_TOKENS = [NEWLINE, SPACE, MACRO_PARAM].freeze
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ module Rucc
2
+ class TempnameGen
3
+ def initialize
4
+ @id = 0 # [Integer]
5
+ end
6
+
7
+ # @return [String]
8
+ def next
9
+ tempname = ".T#{@id}"
10
+ @id += 1
11
+ tempname
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,114 @@
1
+ require "rucc/enc"
2
+ require "rucc/k"
3
+ require "rucc/op"
4
+ require "rucc/t"
5
+
6
+ module Rucc
7
+ class Token
8
+ # @param [T] kind
9
+ # @param [FileIO] file
10
+ # @param [Integer] count
11
+ # @param [Set] hideset
12
+ # @param [String, Keyword, Op] id
13
+ # @param [String] sval
14
+ # @param [Integer] c
15
+ # @param [ENC] enc
16
+ # @param [Boolean] is_vararg
17
+ # @param [Integer] position
18
+ def initialize(kind,
19
+ file: nil,
20
+ count: nil, # Token number in a file, counting from 0
21
+ line: nil, column: nil, # Token location in a file
22
+ hideset: nil, # used by the preprocessor for macro expansion
23
+ space: false, # true if the token has a leading space
24
+ bol: nil, # true if the token is at the beginning of a line
25
+ id: nil, # KEYWORD
26
+ sval: nil, c: nil, enc: nil, # STRING or CHAR
27
+ is_vararg: nil, position: nil # MACRO_PARAM
28
+ )
29
+ @kind = kind
30
+ @file = file
31
+ @count = count
32
+ @line = line; @column = column
33
+ @hideset = hideset
34
+ @space = space
35
+ @bol = bol
36
+
37
+ # value
38
+ @id = id # KEYWORD
39
+ @sval = sval; @c = c; @enc = enc; # STRING or CHAR
40
+ @is_vararg = is_vararg; @position = position # MACRO_PARAM
41
+
42
+ # Flag representing completion of macro expansion
43
+ @expanded = false
44
+ end
45
+ attr_reader :kind, :id, :sval, :c, :enc, :space, :hideset, :file, :count, :line, :column, :bol, :is_vararg, :position, :expanded
46
+ attr_writer :kind, :id, :sval, :enc, :space, :hideset, :line, :column, :bol, :expanded
47
+
48
+ # @return [String]
49
+ def to_s
50
+ case kind
51
+ when T::IDENT
52
+ return sval
53
+ when T::KEYWORD
54
+ case self
55
+ when Operator, Keyword
56
+ return str
57
+ else
58
+ return "#{id}"
59
+ end
60
+ when T::CHAR
61
+ return "#{encoding_prefix(enc)}'#{Util.quote_char(c)}'"
62
+ when T::NUMBER
63
+ return sval
64
+ when T::STRING
65
+ return "#{encoding_prefix(enc)}\"#{Util.quote_cstring(sval)}\""
66
+ when T::EOF
67
+ return "(eof)"
68
+ when T::INVALID
69
+ return "#{c}"
70
+ when T::NEWLINE
71
+ return "(newline)"
72
+ when T::SPACE
73
+ return "(space)"
74
+ when T::MACRO_PARAM
75
+ return "(macro-param)"
76
+ else
77
+ raise "internal error: unknown token kind: #{kind}"
78
+ end
79
+ end
80
+
81
+ private
82
+
83
+ # @param [ENC]
84
+ def encoding_prefix(enc)
85
+ case enc
86
+ when ENC::CHAR16 then return "u"
87
+ when ENC::CHAR32 then return "U"
88
+ when ENC::UTF8 then return "u8"
89
+ when ENC::WCHAR then return "L"
90
+ else return ""
91
+ end
92
+ end
93
+
94
+ class << self
95
+ # @param [Token] tok
96
+ # @param [String] id
97
+ # @return [Boolean]
98
+ def is_keyword?(tok, id)
99
+ tok.kind == T::KEYWORD && tok.id == id
100
+ end
101
+
102
+ # @param [Token] tok
103
+ # @param [String] s
104
+ # @return [Boolean]
105
+ def is_ident?(tok, s)
106
+ tok.kind == T::IDENT && tok.sval == s
107
+ end
108
+ end
109
+ end
110
+
111
+ Token::SPACE_TOKEN = Token.new(T::SPACE)
112
+ Token::NEWLINE_TOKEN = Token.new(T::NEWLINE)
113
+ Token::EOF_TOKEN = Token.new(T::EOF)
114
+ end
@@ -0,0 +1,68 @@
1
+ require "rucc/token"
2
+
3
+ module Rucc
4
+ class TokenGen
5
+ # @param [FileIOList] files
6
+ def initialize(files)
7
+ @files = files
8
+ @pos = nil
9
+ end
10
+ attr_reader :pos
11
+ attr_writer :pos
12
+
13
+ # @param [T] kind
14
+ # @param [Hash] value
15
+ # @return [Token]
16
+ def make_token(kind, value = {})
17
+ f = @files.current
18
+ Util.assert!{ !pos.nil? }
19
+ params = {
20
+ file: f,
21
+ count: f.ntok,
22
+ hideset: Set.new,
23
+ line: pos.line,
24
+ column: pos.column,
25
+ }
26
+ f.incr_ntok!
27
+ Token.new(kind, value.merge(params))
28
+ end
29
+
30
+ # @param [String] s
31
+ # @return [Token]
32
+ def make_number(s)
33
+ make_token(T::NUMBER, sval: s)
34
+ end
35
+
36
+ # @param [String] p
37
+ # @return [Token]
38
+ def make_ident(p)
39
+ make_token(T::IDENT, sval: p)
40
+ end
41
+
42
+ # @param [Integer] c
43
+ # @param [ENC] enc
44
+ # @return [Token]
45
+ def make_char(c, enc)
46
+ make_token(T::CHAR, c: c, enc: enc)
47
+ end
48
+
49
+ # @param [String] s
50
+ # @param [ENC] enc
51
+ # @return [Token]
52
+ def make_strtok(s, enc)
53
+ make_token(T::STRING, sval: s, enc: enc)
54
+ end
55
+
56
+ # @param [Char] id
57
+ # @return [Token]
58
+ def make_keyword(id)
59
+ make_token(T::KEYWORD, id: id)
60
+ end
61
+
62
+ # @param [Integer] c
63
+ # @return [Token]
64
+ def make_invalid(c)
65
+ make_token(T::INVALID, c: c)
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,304 @@
1
+ require "rucc/kind"
2
+ require "rucc/type/check"
3
+ require "rucc/type/conv"
4
+
5
+ module Rucc
6
+ class Type
7
+ extend Check
8
+ extend Conv
9
+
10
+ # @param [Kind] kind the kind of type
11
+ # @param [Integer] size
12
+ # @param [Integer] align
13
+ # @param [Boolean] usig true if unsigned
14
+ # @param [Integer] len array length
15
+ def initialize(kind,
16
+ size: nil, align: nil, usig: nil, isstatic: nil,
17
+ ptr: nil, # Pointer or Array
18
+ len: nil, # Array
19
+ fields: nil, offset: nil, # Struct
20
+ is_struct: nil, # true if Struct, false if Union
21
+ bitoff: nil, bitsize: nil, # Bitfield
22
+ rettype: nil, params: nil, hasva: nil, oldstyle: nil # Function
23
+ )
24
+ @kind = kind
25
+ @size = size; @align = align; @usig = usig; @isstatic = isstatic
26
+ @ptr = ptr # Pointer or Array
27
+ @len = len # Array
28
+ @fields = fields; @offset = offset # Struct
29
+ @is_struct = is_struct # true if Struct, false if Union
30
+ @bitoff = bitoff; @bitsize = bitsize # Bitfield
31
+ @rettype = rettype; @params = params; @hasva = hasva; @oldstyle = oldstyle # Function
32
+ end
33
+ attr_reader :kind,
34
+ :size, :align, :usig, :isstatic,
35
+ :ptr, # Pointer or Array
36
+ :len, # Array
37
+ :fields, :offset, # Struct
38
+ :is_struct, # true if Struct, false if Union
39
+ :bitoff, :bitsize, # Bitfield
40
+ :rettype, :params, :hasva, :oldstyle # Function
41
+ attr_writer :isstatic, :params, :hasva,
42
+ :size, :align, :usig,
43
+ :ptr, # Pointer or Array
44
+ :len, # Array
45
+ :fields, :offset, # Struct
46
+ :bitoff, :bitsize # Bitfield
47
+
48
+ # @return [String]
49
+ def to_s
50
+ to_s_impl({})
51
+ end
52
+
53
+ # @param [Hash] dict
54
+ # @return [String]
55
+ def to_s_impl(dict)
56
+ # TODO(south37) Consider nil case
57
+ # if (!ty)
58
+ # return "(nil)";
59
+ case kind
60
+ when Kind::VOID then return "void"
61
+ when Kind::BOOL then return "_Bool"
62
+ when Kind::CHAR then return decorate_int("char")
63
+ when Kind::SHORT then return decorate_int("short")
64
+ when Kind::INT then return decorate_int("int")
65
+ when Kind::LONG then return decorate_int("long")
66
+ when Kind::LLONG then return decorate_int("llong")
67
+ when Kind::FLOAT then return "float"
68
+ when Kind::DOUBLE then return "double"
69
+ when Kind::LDOUBLE then return "long double"
70
+ when Kind::PTR
71
+ return "*#{ptr.to_s_impl(dict)}"
72
+ when Kind::ARRAY
73
+ return "[#{len}]#{ptr.to_s_impl(dict)}"
74
+ when Kind::STRUCT
75
+ k = is_struct ? "struct" : "union"
76
+ if !dict[self.object_id].nil?
77
+ return "(#{k})"
78
+ end
79
+ dict[self.object_id] = true
80
+ if fields
81
+ s = "(#{k}"
82
+ fields.each do |_, fieldtype|
83
+ s << " (#{fieldtype.to_s_impl(dict)})"
84
+ end
85
+ s << ")"
86
+ return s
87
+ end
88
+ raise "Must not reach here" # TODO(south37) Confirm occurance
89
+ when Kind::FUNC
90
+ s = "("
91
+ if params
92
+ s << params.map { |param| param.to_s_impl(dict) }.join(",")
93
+ end
94
+ s << ")=>#{rettype.to_s_impl(dict)}"
95
+ return s
96
+ else
97
+ return "(Unknown ty: #{kind})"
98
+ end
99
+ end
100
+
101
+ # @param [String] name
102
+ # @return [String]
103
+ def decorate_int(name)
104
+ u = usig ? "u" : ""
105
+ if bitsize && bitsize > 0
106
+ return "#{u}#{name}:#{bitoff}:#{bitoff + bitsize}"
107
+ end
108
+ "#{u}#{name}"
109
+ end
110
+
111
+ # @param [Type] tmpl
112
+ def replace_by!(tmpl)
113
+ tmpl.instance_variables.each do |ivar|
114
+ self.instance_variable_set(ivar, tmpl.instance_variable_get(ivar))
115
+ end
116
+ end
117
+
118
+ class << self
119
+ # @param [Type] ty
120
+ # @return [Type]
121
+ def make_ptr_type(ty)
122
+ Type.new(Kind::PTR,
123
+ ptr: ty,
124
+ size: 8,
125
+ align: 8)
126
+ end
127
+
128
+ # @param [Type] ty
129
+ # @param [Integer] len
130
+ # @return [Type]
131
+ def make_array_type(ty, len)
132
+ if len < 0
133
+ size = -1
134
+ else
135
+ size = ty.size * len
136
+ end
137
+ Type.new(Kind::ARRAY,
138
+ ptr: ty,
139
+ size: size,
140
+ len: len,
141
+ align: ty.align)
142
+ end
143
+
144
+ # @param [Type] rettype
145
+ # @param [Array] paramtypes
146
+ # @param [Boolean] has_varargs
147
+ # @param [Boolean] oldstyle
148
+ # @return [Type]
149
+ def make_func_type(rettype, paramtypes, has_varargs, oldstyle)
150
+ Type.new(Kind::FUNC,
151
+ rettype: rettype,
152
+ params: paramtypes,
153
+ hasva: has_varargs,
154
+ oldstyle: oldstyle)
155
+ end
156
+
157
+ # @param [Kind] kind
158
+ # @param [Boolean] usig
159
+ # @return [Type]
160
+ def make_numtype(kind, usig)
161
+ size = align =
162
+ case kind
163
+ when Kind::VOID then 0
164
+ when Kind::BOOL then 1
165
+ when Kind::CHAR then 1
166
+ when Kind::SHORT then 2
167
+ when Kind::INT then 4
168
+ when Kind::LONG then 8
169
+ when Kind::LLONG then 8
170
+ when Kind::FLOAT then 4
171
+ when Kind::DOUBLE then 8
172
+ when Kind::LDOUBLE then 8
173
+ else
174
+ raise "internal error"
175
+ end
176
+ Type.new(kind, size: size, align: align, usig: usig)
177
+ end
178
+
179
+ # @return [Type]
180
+ def make_stub_type
181
+ Type.new(Kind::STUB, size: 0)
182
+ end
183
+
184
+ # @param [Boolean] is_struct
185
+ # @return [Type]
186
+ def make_rectype(is_struct)
187
+ Type.new(Kind::STRUCT, is_struct: is_struct)
188
+ end
189
+
190
+ # @param [ENC]
191
+ # @return [Type]
192
+ def char_type(enc)
193
+ case enc
194
+ when ENC::NONE, ENC::WCHAR
195
+ return Type::INT
196
+ when ENC::CHAR16
197
+ return Type::USHORT
198
+ when ENC::CHAR32
199
+ return Type::UINT
200
+ else
201
+ raise "internal error"
202
+ end
203
+ end
204
+
205
+ # @param [Type] t
206
+ # @param [Type] u
207
+ # @return [Boolean]
208
+ def same_arith_type(t, u)
209
+ t.kind == u.kind && t.usig == u.usig
210
+ end
211
+
212
+ # @param [Type] totype
213
+ # @param [Type] fromtype
214
+ def ensure_assignable!(totype, fromtype)
215
+ if (Type.is_arithtype(totype) || (totype.kind == Kind::PTR)) &&
216
+ (Type.is_arithtype(fromtype) || (fromtype.kind == Kind::PTR))
217
+ return
218
+ end
219
+ if is_same_struct?(totype, fromtype)
220
+ return
221
+ end
222
+ raise "incompatible kind: <#{totype}> <#{fromtype}>"
223
+ end
224
+
225
+ # @param [Type] a
226
+ # @param [Type] b
227
+ # @return [Boolean]
228
+ def is_same_struct?(a, b)
229
+ if a.kind != b.kind
230
+ return false
231
+ end
232
+
233
+ case a.kind
234
+ when Kind::ARRAY
235
+ return a.len == b.len && is_same_struct?(a.ptr, b.ptr)
236
+ when Kind::PTR
237
+ return is_same_struct?(a.ptr, b.ptr)
238
+ when Kind::STRUCT
239
+ if a.is_struct != b.is_struct
240
+ return false
241
+ end
242
+ ka = a.fields.values
243
+ kb = b.fields.values
244
+ if ka.size != kb.size
245
+ return false
246
+ end
247
+ ka.zip(kb).each do |(x, y)|
248
+ if !is_same_struct?(x, y)
249
+ return false
250
+ end
251
+ end
252
+ return true
253
+ else
254
+ return true
255
+ end
256
+ end
257
+
258
+ # @param [Type] a
259
+ # @param [Type] b
260
+ # @return [Boolean]
261
+ def type_compatible?(a, b)
262
+ if a.kind == Kind::STRUCT
263
+ return is_same_struct?(a, b)
264
+ end
265
+ if a.kind != b.kind
266
+ return false
267
+ end
268
+ if a.ptr && b.ptr
269
+ return type_compatible?(a.ptr, b.ptr)
270
+ end
271
+ if is_arithtype(a) && is_arithtype(b)
272
+ return same_arith_type(a, b)
273
+ end
274
+ true
275
+ end
276
+
277
+ # @param [Type, NilClass] ty
278
+ # @return [Type, NilClass]
279
+ def copy_incomplete_type(ty)
280
+ return nil if ty.nil?
281
+ (ty.len == -1) ? ty.dup : ty
282
+ end
283
+ end
284
+
285
+ # Objects representing basic types. All variables will be of one of these
286
+ # types or a derived type from one of them.
287
+ VOID = Type.new(Kind::VOID, size: 0, align: 0, usig: false)
288
+ BOOL = Type.new(Kind::BOOL, size: 1, align: 1, usig: true)
289
+ CHAR = Type.new(Kind::CHAR, size: 1, align: 1, usig: false)
290
+ SHORT = Type.new(Kind::SHORT, size: 2, align: 2, usig: false)
291
+ INT = Type.new(Kind::INT, size: 4, align: 4, usig: false)
292
+ LONG = Type.new(Kind::LONG, size: 8, align: 8, usig: false)
293
+ LLONG = Type.new(Kind::LLONG, size: 8, align: 8, usig: false)
294
+ UCHAR = Type.new(Kind::CHAR, size: 1, align: 1, usig: true)
295
+ USHORT = Type.new(Kind::SHORT, size: 2, align: 2, usig: true)
296
+ UINT = Type.new(Kind::INT, size: 4, align: 4, usig: true)
297
+ ULONG = Type.new(Kind::LONG, size: 8, align: 8, usig: true)
298
+ ULLONG = Type.new(Kind::LLONG, size: 8, align: 8, usig: true)
299
+ FLOAT = Type.new(Kind::FLOAT, size: 4, align: 4, usig: false)
300
+ DOUBLE = Type.new(Kind::DOUBLE, size: 8, align: 8, usig: false)
301
+ LDOUBLE = Type.new(Kind::LDOUBLE, size: 8, align: 8, usig: false)
302
+ ENUM = Type.new(Kind::ENUM, size: 4, align: 4, usig: false)
303
+ end
304
+ end