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,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
|
data/lib/rucc/libc.rb
ADDED
@@ -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
|
data/lib/rucc/m.rb
ADDED
data/lib/rucc/macro.rb
ADDED
@@ -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
|
data/lib/rucc/node.rb
ADDED
@@ -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
|