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
         |