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,27 @@
1
+ module Rucc
2
+ class Lexer
3
+ class Preprocessor
4
+ module CondInclCtx
5
+ THEN = "CondInclCtx::THEN"
6
+ ELIF = "CondInclCtx::ELIF"
7
+ ELSE = "CondInclCtx::ELSE"
8
+ end
9
+
10
+ class CondIncl
11
+ # @param [CondInclCtx]
12
+ # @param [String, NilClass] include_guard
13
+ # @param [FileIO, NilClass] file
14
+ # @param [Boolean] wastrue
15
+ def initialize(ctx, wastrue:)
16
+ @ctx = ctx
17
+ @wastrue = wastrue
18
+
19
+ @include_guard = nil
20
+ @file = nil
21
+ end
22
+ attr_reader :ctx, :wastrue, :include_guard, :file
23
+ attr_writer :ctx, :wastrue, :include_guard, :file
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,54 @@
1
+ module Rucc
2
+ class Lexer
3
+ class Preprocessor
4
+ module Constructor
5
+ # @param [String] name
6
+ # @param [Token] value
7
+ def define_obj_macro(name, value)
8
+ @macros[name] = make_obj_macro([value])
9
+ end
10
+
11
+ # @param [<Token>] body
12
+ # @return [Macro]
13
+ def make_obj_macro(body)
14
+ Macro.new(M::OBJ, body: body)
15
+ end
16
+
17
+ # @param [<Token>] body
18
+ # @param [Integer] nargs
19
+ # @param [Boolean] is_varg
20
+ def make_func_macro(body, nargs, is_varg)
21
+ Macro.new(M::FUNC, body: body, nargs: nargs, is_varg: is_varg)
22
+ end
23
+
24
+ # @param [Proc] fn
25
+ def make_special_macro(fn)
26
+ Macro.new(M::SPECIAL, fn: fn)
27
+ end
28
+
29
+ # @param [Boolean] wastrue
30
+ def make_cond_incl(wastrue)
31
+ CondIncl.new(CondInclCtx::THEN, wastrue: wastrue)
32
+ end
33
+
34
+ # @param [Integer] position
35
+ # @param [Boolean] is_vararg
36
+ def make_macro_token(position, is_vararg)
37
+ Token.new(T::MACRO_PARAM,
38
+ is_vararg: is_vararg,
39
+ hideset: nil,
40
+ position: position,
41
+ space: false,
42
+ bol: false,
43
+ )
44
+ end
45
+
46
+ # @param [Token] tok
47
+ # @return [Token]
48
+ def copy_token(tok)
49
+ tok.dup
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,31 @@
1
+ module Rucc
2
+ class Lexer
3
+ class Preprocessor
4
+ module Pragma
5
+
6
+ private
7
+
8
+ # @param [Token] tok
9
+ def parse_pragma_operand(tok)
10
+ s = tok.sval
11
+ case s
12
+ when "once"
13
+ path = File.expand_path(tok.file.name)
14
+ @once[path] = 1
15
+ when "enable_warning"
16
+ @enable_warning = true
17
+ when "disable_warning"
18
+ @enable_warning = false
19
+ else
20
+ Util.errort!(tok, "unknown #pragma: #{s}")
21
+ end
22
+ end
23
+
24
+ def read_pragma
25
+ tok = read_ident
26
+ parse_pragma_operand(tok)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,110 @@
1
+ module Rucc
2
+ class Lexer
3
+ class Preprocessor
4
+ module SpecialMacro
5
+
6
+ private
7
+
8
+ def define_special_macros!
9
+ define_special_macro "__DATE__", :handle_date_macro
10
+ define_special_macro "__TIME__", :handle_time_macro
11
+ define_special_macro "__FILE__", :handle_file_macro
12
+ define_special_macro "__LINE__", :handle_line_macro
13
+ define_special_macro "_Pragma", :handle_pragma_macro
14
+
15
+ # [GNU] Non-standard macros
16
+ define_special_macro "__BASE_FILE__", :handle_base_file_macro
17
+ define_special_macro "__COUNTER__", :handle_counter_macro
18
+ define_special_macro "__INCLUDE_LEVEL__", :handle_include_level_macro
19
+ define_special_macro "__TIMESTAMP__", :handle_timestamp_macro
20
+ end
21
+
22
+ # @param [Symbol] fn handler name of special macro
23
+ def define_special_macro(name, fn)
24
+ # @param [Token] tok
25
+ handler = -> (tok) { self.send(fn, tok) }
26
+ @macros[name] = make_special_macro(handler)
27
+ end
28
+
29
+ ##
30
+ # Handlers
31
+ ##
32
+
33
+ # @param [Token] tmpl
34
+ def handle_date_macro(tmpl)
35
+ s = @now.strftime("%b %e %Y")
36
+ make_token_pushback(tmpl, T::STRING, s)
37
+ end
38
+
39
+ # @param [Token] tmpl
40
+ def handle_time_macro(tmpl)
41
+ s = @now.strftime("%T")
42
+ make_token_pushback(tmpl, T::STRING, s)
43
+ end
44
+
45
+ # @param [Token] tmpl
46
+ def handle_timestamp_macro(tmpl)
47
+ # [GNU] __TIMESTAMP__ is expanded to a string that describes the date
48
+ # and time of the last modification time of the current source file.
49
+ s = tmpl.file.mtime.strftime("%a %b %e %T %Y")
50
+ make_token_pushback(tmpl, T::STRING, s)
51
+ end
52
+
53
+ # @param [Token] tmpl
54
+ def handle_file_macro(tmpl)
55
+ make_token_pushback(tmpl, T::STRING, tmpl.file.name)
56
+ end
57
+
58
+ # @param [Token] tmpl
59
+ def handle_line_macro(tmpl)
60
+ make_token_pushback(tmpl, T::NUMBER, sprintf("%d", tmpl.file.line))
61
+ end
62
+
63
+ # @param [Token] tmpl
64
+ def handle_pragma_macro(tmpl)
65
+ expect!('(')
66
+ operand = read_token
67
+ if operand.kind != T::STRING
68
+ Util.errort!(operand, "_Pragma takes a string literal, but got #{operand}")
69
+ end
70
+ expect!(')')
71
+ parse_pragma_operand(operand)
72
+ make_token_pushback(tmpl, T::NUMBER, "1")
73
+ end
74
+
75
+ # @param [Token] tmpl
76
+ def handle_base_file_macro(tmpl)
77
+ make_token_pushback(tmpl, T::STRING, @impl.infile.name)
78
+ end
79
+
80
+ # @param [Token] tmpl
81
+ def handle_counter_macro(tmpl)
82
+ @counter ||= 0
83
+ i = @counter
84
+ make_token_pushback(tmpl, T::NUMBER, "%d" % i)
85
+ @counter += 1
86
+ end
87
+
88
+ # @param [Token] tmpl
89
+ def handle_include_level_macro(tmpl)
90
+ make_token_pushback(tmpl, T::NUMBER, "%d" % (@impl.stream_depth - 1))
91
+ end
92
+
93
+ ##
94
+ # Helper
95
+ ##
96
+
97
+ # @param [Token] tmpl
98
+ # @param [T] kind
99
+ # @param [String] sval
100
+ def make_token_pushback(tmpl, kind, sval)
101
+ tok = tmpl.dup
102
+ tok.kind = kind
103
+ tok.sval = sval
104
+ tok.enc = ENC::NONE
105
+ unget_token(tok)
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,47 @@
1
+ module Rucc
2
+ # Emulate libc
3
+ module Libc
4
+ class << self
5
+ # same with isspace in libc
6
+ # @param [Char] c
7
+ def isspace(c)
8
+ "\x20\x0c\x0a\x0d\x09\x0b".freeze.include?(c)
9
+ end
10
+
11
+ # same with isdigit in libc
12
+ # @param [Char] c
13
+ def isdigit(c)
14
+ "0123456789".freeze.include?(c)
15
+ end
16
+
17
+ # same with isdigit in libc
18
+ # @param [Char] c
19
+ def isxdigit(c)
20
+ "0123456789abcdefABCDEF".freeze.include?(c)
21
+ end
22
+
23
+ # same with isalpha in libc
24
+ # @param [Char] c
25
+ def isalpha(c)
26
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".freeze.include?(c)
27
+ end
28
+
29
+ # same with isalnum in libc
30
+ # @param [Char] c
31
+ def isalnum(c)
32
+ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".freeze.include?(c)
33
+ end
34
+
35
+ # TODO(south37) Impl same logic with ispunct in libc
36
+ # @param [Char] c
37
+ def ispunct(c)
38
+ '!"#$%&\'()*+,-./:;<=>?@[\]^_`{|}~'.include?(c)
39
+ end
40
+
41
+ # TODO(south37) Impl same logic with isprint in libc
42
+ def isprint(c)
43
+ isalnum(c) || ispunct(c) || isspace(c)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,7 @@
1
+ module Rucc
2
+ module M
3
+ OBJ = "Macro::OBJ"
4
+ FUNC = "Macro::FUNC"
5
+ SPECIAL = "Macro::SPECIAL"
6
+ end
7
+ end
@@ -0,0 +1,24 @@
1
+ require "rucc/m"
2
+
3
+ module Rucc
4
+ class Macro
5
+ # @param [M] kind
6
+ # @param [<Token>] body
7
+ # @param [Integer] nargs
8
+ # @param [Boolean] is_varg
9
+ # @param [Proc] fn used only for special macro
10
+ def initialize(kind,
11
+ body: nil,
12
+ nargs: nil,
13
+ is_varg: nil,
14
+ fn: nil
15
+ )
16
+ @kind = kind
17
+ @body = body
18
+ @nargs = nargs
19
+ @is_varg = is_varg
20
+ @fn = fn
21
+ end
22
+ attr_reader :kind, :body, :nargs, :is_varg, :fn
23
+ end
24
+ end
@@ -0,0 +1,530 @@
1
+ require "rucc/node/conv"
2
+ require "rucc/utf"
3
+
4
+ module Rucc
5
+ module AST
6
+ LITERAL = "AST::LITERAL"
7
+ LVAR = "AST::LVAR"
8
+ GVAR = "AST::GVAR"
9
+ TYPEDEF = "AST::TYPEDEF"
10
+ FUNCALL = "AST::FUNCALL"
11
+ FUNCPTR_CALL = "AST::FUNCPTR_CALL"
12
+ FUNCDESG = "AST::FUNCDESG"
13
+ FUNC = "AST::FUNC"
14
+ DECL = "AST::DECL"
15
+ INIT = "AST::INIT"
16
+ CONV = "AST::CONV"
17
+ ADDR = "AST::ADDR"
18
+ DEREF = "AST::DEREF"
19
+ IF = "AST::IF"
20
+ TERNARY = "AST::TERNARY"
21
+ DEFAULT = "AST::DEFAULT"
22
+ RETURN = "AST::RETURN"
23
+ COMPOUND_STMT = "AST::COMPOUND_STMT"
24
+ STRUCT_REF = "AST::STRUCT_REF"
25
+ GOTO = "AST::GOTO"
26
+ COMPUTED_GOTO = "AST::COMPUTED_GOTO"
27
+ LABEL = "AST::LABEL"
28
+ end
29
+
30
+ # AST node
31
+ class Node
32
+ extend Conv
33
+
34
+ # @param [AST] kind
35
+ # @param [Type] ty
36
+ def initialize(kind,
37
+ ty: nil,
38
+ ival: nil, # Integer
39
+ fval: nil, flabel: nil, # Float or double
40
+ varname: nil, # Local/global variable
41
+ loff: nil, lvarinit: nil, # Local variable
42
+ glabel: nil, # Global variable
43
+ left: nil, right: nil, # Binary operator
44
+ operand: nil, # Unary operator
45
+ fname: nil, # Function call or function declaration
46
+ args: nil, ftype: nil, # Function call
47
+ fptr: nil, # Function pointer or function designator
48
+ params: nil, localvars: nil, body: nil, # Function declaration
49
+ sval: nil, slabel: nil, # String
50
+ declvar: nil, declinit: nil, # Declaration
51
+ initval: nil, initoff: nil, totype: nil, # Initializer
52
+ cond: nil, thn: nil, els: nil, # If statement or ternary operator
53
+ label: nil, newlabel: nil, # Goto and label
54
+ retval: nil, # Return statement
55
+ stmts: nil, # Compound statement
56
+ struct: nil, field: nil, fieldtype: nil # Struct reference
57
+ )
58
+ @kind = kind
59
+ @ty = ty
60
+ @ival = ival # Integer
61
+ @fval = fval; @flabel = flabel # Float or double
62
+ @varname = varname # Local/global variable
63
+ @loff = loff; @lvarinit = lvarinit # Local variable
64
+ @glabel = glabel # Global variable
65
+ @left = left; @right = right # Binary operator
66
+ @operand = operand # Unary operator
67
+ @fname = fname # Function call or function declaration
68
+ @args = args; @ftype = ftype # Function call
69
+ @fptr = fptr # Function pointer or function designator
70
+ @params = params; @localvars = localvars; @body = body # Function declaration
71
+ @sval = sval; @slabel = slabel # String
72
+ @declvar = declvar; @declinit = declinit # Declaration
73
+ @initval = initval; @initoff = initoff; @totype = totype # Initializer
74
+ @cond = cond; @thn = thn; @els = els # If statement or ternary operator
75
+ @label = label; @newlabel = newlabel # Goto and label
76
+ @retval = retval # Return statement
77
+ @stmts = stmts # Compound statement
78
+ @struct = struct; @field = field; @fieldtype = fieldtype # Struct reference
79
+ end
80
+ attr_reader :kind, :ty,
81
+ :ival, # Integer
82
+ :fval, :flabel, # Float or double
83
+ :varname, # Local/global variable
84
+ :loff, :lvarinit, # Local variable
85
+ :glabel, # Global variable
86
+ :left, :right, # Binary operator
87
+ :operand, # Unary operator
88
+ :sval, :slabel, # String
89
+ :fname, # Function
90
+ :args, :ftype, # Function call
91
+ :fptr, # Function pointer or function designator
92
+ :params, :localvars, :body, # Function Declaration
93
+ :declvar, :declinit, # Declaration
94
+ :initval, :initoff, :totype, # Initializer
95
+ :cond, :thn, :els, # If statement or ternary operator
96
+ :label, :newlabel, # Goto and label
97
+ :retval, # Return statement
98
+ :stmts, # Compound statement
99
+ :struct, :field, :fieldtype # Struct reference
100
+ attr_writer :ty, :flabel, :loff, :lvarinit, :slabel, :newlabel
101
+
102
+ # @return [String]
103
+ def to_s
104
+ case kind
105
+ when AST::LITERAL
106
+ case ty.kind
107
+ when Kind::CHAR
108
+ if ival == "\n" then return "'\\n'" # '\n'
109
+ elsif ival == "\\" then return "'\\\\'" # '\\'
110
+ elsif ival == "\0" then return "'\\0'" # '\0'
111
+ else return "'#{ival.chr}'" # cf. 'a'
112
+ end
113
+ when Kind::INT
114
+ return ival.to_s
115
+ when Kind::FLOAT, Kind::DOUBLE, Kind::LDOUBLE
116
+ return fval.to_s
117
+ when Kind::LONG, Kind::LLONG
118
+ return "#{ival}L"
119
+ when Kind::ARRAY # Consider string literal
120
+ return "\"#{Util.quote_cstring(sval)}\""
121
+ else
122
+ raise "internal error"
123
+ end
124
+ when AST::LABEL
125
+ return "#{label}:"
126
+ when AST::LVAR
127
+ s = "lv=#{varname}"
128
+ if lvarinit
129
+ s << "(#{lvarinit})"
130
+ end
131
+ return s
132
+ when AST::GVAR
133
+ return "gv=#{varname}"
134
+ when AST::FUNCALL, AST::FUNCPTR_CALL
135
+ return "(#{ty})#{kind == AST::FUNCALL ? fname : Node.node_or_nil_to_s(node)}(#{args.map { |arg| Node.node_or_nil_to_s(arg) }.join(",")})"
136
+ when AST::FUNCDESG
137
+ return "(funcdesg #{fname})"
138
+ when AST::FUNC
139
+ return "(#{ty})#{fname}(#{params.map { |param| "#{param.ty} #{Node.node_or_nil_to_s(param)}" }.join(",")})#{Node.node_or_nil_to_s(body)}"
140
+ when AST::GOTO
141
+ return "goto(#{label})"
142
+ when AST::DECL
143
+ s = "(decl #{declvar.ty} #{declvar.varname}"
144
+ if declinit
145
+ s << " #{declinit.join(" ")}"
146
+ end
147
+ s << ")"
148
+ return s
149
+ when AST::INIT
150
+ return "#{initval}@#{initoff}"
151
+ when AST::CONV
152
+ return "(conv #{operand}=>#{ty})"
153
+ when AST::IF
154
+ s = "(if #{Node.node_or_nil_to_s(cond)} #{Node.node_or_nil_to_s(thn)}"
155
+ if els
156
+ s << " #{els}"
157
+ end
158
+ s << ")"
159
+ return s
160
+ when AST::TERNARY
161
+ return "(? #{Node.node_or_nil_to_s(cond)} #{Node.node_or_nil_to_s(thn)} #{Node.node_or_nil_to_s(els)})"
162
+ when AST::RETURN
163
+ return "(return #{retval})"
164
+ when AST::COMPOUND_STMT
165
+ return "{#{stmts.map { |stmt| "#{stmt};" }.join}}"
166
+ when AST::STRUCT_REF
167
+ return "#{struct}.#{field}"
168
+ when AST::ADDR then return "(addr #{operand})"
169
+ when AST::DEREF then return "(deref #{operand})"
170
+ when OP::SAL then return "(<< #{left} #{right})"
171
+ when OP::SAR, OP::SHR then return "(>> #{left} #{right})"
172
+ when OP::GE then return "(>= #{left} #{right})"
173
+ when OP::LE then return "(<= #{left} #{right})"
174
+ when OP::NE then return "(!= #{left} #{right})"
175
+ when OP::PRE_INC then return "(pre++ #{operand})"
176
+ when OP::PRE_DEC then return "(pre-- #{operand})"
177
+ when OP::POST_INC then return "(post++ #{operand})"
178
+ when OP::POST_DEC then return "(post-- #{operand})"
179
+ when OP::LOGAND then return "(and #{left} #{right})"
180
+ when OP::LOGOR then return "(or #{left} #{right})"
181
+ when '!' then return "(! #{operand})"
182
+ when '&' then return "(& #{left} #{right})"
183
+ when '|' then return "(| #{left} #{right})"
184
+ when OP::CAST
185
+ return "((#{operand.ty})=>(#{ty}) #{operand})"
186
+ when OP::LABEL_ADDR
187
+ return "&&#{label}"
188
+ when OP::EQ
189
+ return "(== #{left} #{right})"
190
+ else
191
+ return "(#{kind} #{left} #{right})"
192
+ end
193
+
194
+ raise "Must not reach here!"
195
+ end
196
+
197
+ class << self
198
+ # @param [Node, NilClass] node
199
+ def node_or_nil_to_s(node)
200
+ return '(nil)' if node.nil?
201
+ node.to_s
202
+ end
203
+
204
+ # @param [Type] ty
205
+ # @param [Integer] val
206
+ def ast_inttype(ty, val)
207
+ Util.assert!{ val.is_a?(Integer) }
208
+ Node.new(AST::LITERAL, ty: ty, ival: val)
209
+ end
210
+
211
+ # @param [Type] ty
212
+ # @param [Double] val
213
+ # @return [Node]
214
+ def ast_floattype(ty, val)
215
+ Node.new(AST::LITERAL,
216
+ ty: ty,
217
+ fval: val)
218
+ end
219
+
220
+ # @param [ENC] enc
221
+ def ast_string(enc, str)
222
+ case enc
223
+ when ENC::NONE, ENC::UTF8
224
+ ty = Type.make_array_type(Type::CHAR, str.bytes.size + 1)
225
+ body = str
226
+ when ENC::CHAR16
227
+ b = UTF.to_utf16(str)
228
+ ty = Type.make_array_type(Type::USHORT, (b.bytes.size / Type::USHORT.size) + 1)
229
+ body = b + "\0" # NOTE: Add only \0 (\0\0 - \0)
230
+ when ENC::CHAR32, ENC::WCHAR
231
+ b = UTF.to_utf32(str)
232
+ ty = Type.make_array_type(Type::UINT, (b.bytes.size / Type::UINT.size) + 1)
233
+ body = b + "\0\0\0" # NOTE: Add only \0\0\0 (\0\0\0\0 - \0)
234
+ else
235
+ raise "Invalid encoding"
236
+ end
237
+ Node.new(AST::LITERAL,
238
+ ty: ty,
239
+ sval: body)
240
+ end
241
+
242
+ # @param [Type] ty
243
+ # @param [String] fname
244
+ # @param [Array] params
245
+ # @param [Node] body
246
+ # @param [Array] localvars
247
+ # @return [Node]
248
+ def ast_func(ty, fname, params, body, localvars)
249
+ Node.new(AST::FUNC,
250
+ ty: ty,
251
+ fname: fname,
252
+ params: params,
253
+ localvars: localvars,
254
+ body: body)
255
+ end
256
+
257
+ # @param [Node] fptr
258
+ # @param [<Node>] args
259
+ # @return [Node]
260
+ def ast_funcptr_call(fptr, args)
261
+ Util.assert!{ fptr.ty.kind == Kind::PTR }
262
+ Util.assert!{ fptr.ty.ptr.kind == Kind::FUNC }
263
+ Node.new(AST::FUNCPTR_CALL,
264
+ ty: fptr.ty.ptr.rettype,
265
+ fptr: fptr,
266
+ args: args)
267
+ end
268
+
269
+ # @param [Type] ty
270
+ # @param [String] fname
271
+ def ast_funcdesg(ty, fname)
272
+ Node.new(AST::FUNCDESG,
273
+ ty: ty,
274
+ fname: fname)
275
+ end
276
+
277
+ # @param [Type] ftype
278
+ # @param [String] fname
279
+ # @param [Array] args
280
+ # @return [Node]
281
+ def ast_funcall(ftype, fname, args)
282
+ Node.new(AST::FUNCALL,
283
+ ty: ftype.rettype,
284
+ fname: fname,
285
+ args: args,
286
+ ftype: ftype)
287
+ end
288
+
289
+ # @param [String] kind
290
+ # @param [Type] ty
291
+ # @param [Node] operand
292
+ def ast_uop(kind, ty, operand)
293
+ Node.new(kind,
294
+ ty: ty,
295
+ operand: operand)
296
+ end
297
+
298
+ # @param [Type] ty
299
+ # @param [String] kind
300
+ # @param [Node] left
301
+ # @param [Node] right
302
+ # @return [Node]
303
+ def ast_binop(ty, kind, left, right)
304
+ Node.new(kind,
305
+ ty: ty,
306
+ left: left,
307
+ right: right)
308
+ end
309
+
310
+ # @param [String] op
311
+ # @param [Node] lhs
312
+ # @param [Node] rhs
313
+ # @return [Node]
314
+ def binop(op, lhs, rhs)
315
+ if (lhs.ty.kind == Kind::PTR) && (rhs.ty.kind == Kind::PTR)
316
+ if !valid_pointer_binop?(op)
317
+ raise "internal pointer arith"
318
+ end
319
+ # C11 6.5.6.9: Pointer subtractions have type ptrdiff_t.
320
+ if (op == '-'.freeze)
321
+ return Node.ast_binop(Type::LONG, op, lhs, rhs)
322
+ end
323
+ # C11 6.5.8.6, 6.5.9.3: Pointer comparisons have type int.
324
+ return Node.ast_binop(Type::INT, op, lhs, rhs);
325
+ end
326
+
327
+ # NOTE: Set pointer node as left
328
+ if lhs.ty.kind == Kind::PTR
329
+ return Node.ast_binop(lhs.ty, op, lhs, rhs)
330
+ end
331
+ if rhs.ty.kind == Kind::PTR
332
+ return Node.ast_binop(rhs.ty, op, rhs, lhs)
333
+ end
334
+
335
+ Util.assert!{ Type.is_arithtype(lhs.ty) }
336
+ Util.assert!{ Type.is_arithtype(rhs.ty) }
337
+ r = Type.usual_arith_conv(lhs.ty, rhs.ty)
338
+ Node.ast_binop(r, op, wrap(r, lhs), wrap(r, rhs))
339
+ end
340
+
341
+ # @param [OP] op
342
+ # @return [Boolean]
343
+ def valid_pointer_binop?(op)
344
+ case op
345
+ when '-', '<', '>', OP::EQ, OP::NE, OP::GE, OP::LE
346
+ return true
347
+ else
348
+ return false
349
+ end
350
+ end
351
+
352
+ # @param [Type] t
353
+ # @param [Node] node
354
+ # @return [Node]
355
+ def wrap(t, node)
356
+ if Type.same_arith_type(t, node.ty)
357
+ return node
358
+ end
359
+ Node.ast_uop(AST::CONV, t, node)
360
+ end
361
+
362
+ # @param [Node] cond
363
+ # @param [Node] thn
364
+ # @param [Node] els
365
+ # @return [Node]
366
+ def ast_if(cond, thn, els)
367
+ Node.new(AST::IF,
368
+ cond: cond,
369
+ thn: thn,
370
+ els: els)
371
+ end
372
+
373
+ # @param [Type] ty
374
+ # @param [Node] cond
375
+ # @param [Node] thn
376
+ # @param [Node] els
377
+ # @return [Node]
378
+ def ast_ternary(ty, cond, thn, els)
379
+ Node.new(AST::TERNARY,
380
+ ty: ty,
381
+ cond: cond,
382
+ thn: thn,
383
+ els: els)
384
+ end
385
+
386
+ # @param [String] label
387
+ # @return [Node]
388
+ def ast_label(label)
389
+ Node.new(AST::LABEL, label: label)
390
+ end
391
+
392
+ # @param [String] label
393
+ # @return [Node]
394
+ def ast_dest(label)
395
+ Node.new(AST::LABEL,
396
+ label: label,
397
+ newlabel: label)
398
+ end
399
+
400
+ # @param [String] label
401
+ def ast_label_addr(label)
402
+ Node.new(OP::LABEL_ADDR,
403
+ ty: Type.make_ptr_type(Type::VOID),
404
+ label: label)
405
+ end
406
+
407
+ # @param [String] label
408
+ # @return [Node]
409
+ def ast_jump(label)
410
+ Node.new(AST::GOTO,
411
+ label: label,
412
+ newlabel: label)
413
+ end
414
+
415
+ # @param [String] label
416
+ # @return [Node]
417
+ def ast_goto(label)
418
+ Node.new(AST::GOTO,
419
+ label: label)
420
+ end
421
+
422
+ # @param [Node] expr
423
+ # @return [Node]
424
+ def ast_computed_goto(expr)
425
+ Node.new(AST::COMPUTED_GOTO,
426
+ operand: expr)
427
+ end
428
+
429
+ # @param [Node, NilClass] retval
430
+ def ast_return(retval)
431
+ Node.new(AST::RETURN,
432
+ retval: retval)
433
+ end
434
+
435
+ # @param [Type] totype
436
+ # @param [Node] val
437
+ # @return [Node]
438
+ def ast_conv(totype, val)
439
+ Node.new(AST::CONV,
440
+ ty: totype,
441
+ operand: val)
442
+ end
443
+
444
+ # @param [Node] var
445
+ # @param [Array] init
446
+ def ast_decl(var, init)
447
+ Node.new(AST::DECL,
448
+ declvar: var,
449
+ declinit: init)
450
+ end
451
+
452
+ # @param [Node] val
453
+ # @param [Type] totype
454
+ # @param [Integer] off
455
+ # @return [Node]
456
+ def ast_init(val, totype, off)
457
+ Node.new(AST::INIT,
458
+ initval: val,
459
+ initoff: off,
460
+ totype: totype)
461
+ end
462
+
463
+ # @param [Array] stmts
464
+ # @return [Node]
465
+ def ast_compound_stmt(stmts)
466
+ Node.new(AST::COMPOUND_STMT, stmts: stmts)
467
+ end
468
+
469
+ # @param [Type] ty
470
+ # @param [String] name
471
+ # @return [Node]
472
+ def ast_typedef(ty, name, env)
473
+ r = Node.new(AST::TYPEDEF, ty: ty)
474
+ env[name] = r
475
+ r
476
+ end
477
+
478
+ # @param [Type] ty
479
+ # @param [Node] struct
480
+ # @param [String] name
481
+ # @return [Node]
482
+ def ast_struct_ref(ty, struct, name)
483
+ Node.new(AST::STRUCT_REF,
484
+ ty: ty,
485
+ struct: struct,
486
+ field: name)
487
+ end
488
+
489
+ # @param [Type] ty
490
+ # @param [String] name
491
+ # @param [RMap] localenv
492
+ # @param [Array] localvars
493
+ # @return [Node]
494
+ def ast_lvar(ty, name, localenv, localvars)
495
+ r = Node.new(AST::LVAR, ty: ty, varname: name)
496
+ if localenv
497
+ localenv[name] = r
498
+ end
499
+ if localvars
500
+ localvars.push(r)
501
+ end
502
+ r
503
+ end
504
+
505
+ # @param [Type] ty
506
+ # @param [String] name
507
+ # @param [RMap] globalenv
508
+ def ast_gvar(ty, name, globalenv)
509
+ r = Node.new(AST::GVAR, ty: ty, varname: name, glabel: name)
510
+ globalenv[name] = r
511
+ r
512
+ end
513
+
514
+ # @param [Type] ty
515
+ # @param [String] name
516
+ # @param [RMap] localenv
517
+ # @param [String] glabel
518
+ # @return [String]
519
+ def ast_static_lvar(ty, name, localenv, glabel)
520
+ r = Node.new(AST::GVAR,
521
+ ty: ty,
522
+ varname: name,
523
+ glabel: glabel)
524
+ Util.assert!{ localenv }
525
+ localenv[name] = r
526
+ r
527
+ end
528
+ end
529
+ end
530
+ end