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,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
|
data/lib/rucc/pos.rb
ADDED
data/lib/rucc/rmap.rb
ADDED
@@ -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
|
data/lib/rucc/s.rb
ADDED
data/lib/rucc/t.rb
ADDED
@@ -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
|
data/lib/rucc/token.rb
ADDED
@@ -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
|
data/lib/rucc/type.rb
ADDED
@@ -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
|