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,71 @@ | |
| 1 | 
            +
            module Rucc
         | 
| 2 | 
            +
              class Parser
         | 
| 3 | 
            +
                module For
         | 
| 4 | 
            +
                  private
         | 
| 5 | 
            +
                  # @return [Node]
         | 
| 6 | 
            +
                  def read_for_stmt
         | 
| 7 | 
            +
                    expect!('(')
         | 
| 8 | 
            +
                    beg = @label_gen.next
         | 
| 9 | 
            +
                    mid = @label_gen.next
         | 
| 10 | 
            +
                    lst = @label_gen.next
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                    orig = @localenv
         | 
| 13 | 
            +
                    @localenv = RMap.new(@localenv)
         | 
| 14 | 
            +
                    init = read_opt_decl_or_stmt
         | 
| 15 | 
            +
                    cond = read_expr_opt
         | 
| 16 | 
            +
                    if cond && Type.is_flotype(cond.ty)
         | 
| 17 | 
            +
                      cond = Node.ast_conv(Type::BOOL, cond)
         | 
| 18 | 
            +
                    end
         | 
| 19 | 
            +
                    expect!(';')
         | 
| 20 | 
            +
                    step = read_expr_opt
         | 
| 21 | 
            +
                    expect!(')')
         | 
| 22 | 
            +
                    body = nil  # declaration for ruby
         | 
| 23 | 
            +
                    with_jump_labels(mid, lst) { body = read_stmt }
         | 
| 24 | 
            +
                    @localenv = orig
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                    v = []
         | 
| 27 | 
            +
                    if !init.nil?
         | 
| 28 | 
            +
                      v.push(init)
         | 
| 29 | 
            +
                    end
         | 
| 30 | 
            +
                    v.push(Node.ast_dest(beg))
         | 
| 31 | 
            +
                    if !cond.nil?
         | 
| 32 | 
            +
                      v.push(Node.ast_if(cond, nil, Node.ast_jump(lst)))
         | 
| 33 | 
            +
                    end
         | 
| 34 | 
            +
                    if !body.nil?
         | 
| 35 | 
            +
                      v.push(body)
         | 
| 36 | 
            +
                    end
         | 
| 37 | 
            +
                    v.push(Node.ast_dest(mid))
         | 
| 38 | 
            +
                    if !step.nil?
         | 
| 39 | 
            +
                      v.push(step)
         | 
| 40 | 
            +
                    end
         | 
| 41 | 
            +
                    v.push(Node.ast_jump(beg))
         | 
| 42 | 
            +
                    v.push(Node.ast_dest(lst))
         | 
| 43 | 
            +
                    Node.ast_compound_stmt(v)
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  # @param [String] cont
         | 
| 47 | 
            +
                  # @param [String] brk
         | 
| 48 | 
            +
                  def with_jump_labels(cont, brk)
         | 
| 49 | 
            +
                    # Set jump lablels
         | 
| 50 | 
            +
                    ocontinue = @lcontinue
         | 
| 51 | 
            +
                    obreak    = @lbreak
         | 
| 52 | 
            +
                    @lcontinue = cont
         | 
| 53 | 
            +
                    @lbreak    = brk
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                    yield
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                    # Restore jump lablels
         | 
| 58 | 
            +
                    @lcontinue = ocontinue
         | 
| 59 | 
            +
                    @lbreak    = obreak
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                  # @return [Node, NilClass]
         | 
| 63 | 
            +
                  def read_opt_decl_or_stmt
         | 
| 64 | 
            +
                    return nil if next_token?(';')
         | 
| 65 | 
            +
                    list = []
         | 
| 66 | 
            +
                    read_decl_or_stmt(list)
         | 
| 67 | 
            +
                    Node.ast_compound_stmt(list)
         | 
| 68 | 
            +
                  end
         | 
| 69 | 
            +
                end
         | 
| 70 | 
            +
              end
         | 
| 71 | 
            +
            end
         | 
| @@ -0,0 +1,274 @@ | |
| 1 | 
            +
            module Rucc
         | 
| 2 | 
            +
              class Parser
         | 
| 3 | 
            +
                module Func
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                private
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  # @param [Type] basety
         | 
| 8 | 
            +
                  # @param(return) [Array] params
         | 
| 9 | 
            +
                  # @return [Type]
         | 
| 10 | 
            +
                  def read_declarator_func(basety, params)
         | 
| 11 | 
            +
                    if basety.kind == Kind::FUNC
         | 
| 12 | 
            +
                      raise "function returning a function"
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
                    if basety.kind == Kind::ARRAY
         | 
| 15 | 
            +
                      raise "function returning an array"
         | 
| 16 | 
            +
                    end
         | 
| 17 | 
            +
                    read_func_param_list(params, basety)
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  # @param [Array, NilClass] paramvars
         | 
| 21 | 
            +
                  # @param [Type] rettype
         | 
| 22 | 
            +
                  # @return [Type]
         | 
| 23 | 
            +
                  def read_func_param_list(paramvars, rettype)
         | 
| 24 | 
            +
                    # C11 6.7.6.3p10: A parameter list with just "void" specifies that
         | 
| 25 | 
            +
                    # the function has no parameters.
         | 
| 26 | 
            +
                    tok = get
         | 
| 27 | 
            +
                    if Token.is_keyword?(tok, K::VOID) && next_token?(')')
         | 
| 28 | 
            +
                      return Type.make_func_type(rettype, [], false, false)
         | 
| 29 | 
            +
                    end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                    # C11 6.7.6.3p14: K&R-style un-prototyped declaration or
         | 
| 32 | 
            +
                    # function definition having no parameters.
         | 
| 33 | 
            +
                    # We return a type representing K&R-style declaration here.
         | 
| 34 | 
            +
                    # If this is actually part of a declartion, the type will be fixed later.
         | 
| 35 | 
            +
                    if Token.is_keyword?(tok, ')')
         | 
| 36 | 
            +
                      return Type.make_func_type(rettype, [], true, true)
         | 
| 37 | 
            +
                    end
         | 
| 38 | 
            +
                    @lexer.unget_token(tok)
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    tok2 = peek
         | 
| 41 | 
            +
                    if next_token?(K::ELLIPSIS)
         | 
| 42 | 
            +
                      Util.errort!(tok2, "at least one parameter is required before \"...\"")
         | 
| 43 | 
            +
                    end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                    if is_type?(peek)
         | 
| 46 | 
            +
                      paramtypes = []
         | 
| 47 | 
            +
                      ellipsis = read_declarator_params(paramtypes, paramvars)
         | 
| 48 | 
            +
                      return Type.make_func_type(rettype, paramtypes, ellipsis, false)
         | 
| 49 | 
            +
                    end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                    if paramvars.nil?
         | 
| 52 | 
            +
                      Util.errort!(tok, "invalid function definition")
         | 
| 53 | 
            +
                    end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                    read_declarator_params_oldstyle(paramvars)
         | 
| 56 | 
            +
                    paramtypes = []
         | 
| 57 | 
            +
                    (0..(paramvars.size - 1)).each do
         | 
| 58 | 
            +
                      paramtypes.push Type::INT
         | 
| 59 | 
            +
                    end
         | 
| 60 | 
            +
                    Type.make_func_type(rettype, paramtypes, false, true)
         | 
| 61 | 
            +
                  end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                  # @param [Array] types
         | 
| 64 | 
            +
                  # @param [Array] vars
         | 
| 65 | 
            +
                  # @return [Boolean] ellipsis
         | 
| 66 | 
            +
                  def read_declarator_params(types, vars)
         | 
| 67 | 
            +
                    typeonly = vars.nil?
         | 
| 68 | 
            +
                    ellipsis = false
         | 
| 69 | 
            +
                    while true
         | 
| 70 | 
            +
                      tok = peek
         | 
| 71 | 
            +
                      if next_token?(K::ELLIPSIS)
         | 
| 72 | 
            +
                        if types.size == 0
         | 
| 73 | 
            +
                          Util.errort!(tok, "at least one parameter is required before \"...\"")
         | 
| 74 | 
            +
                        end
         | 
| 75 | 
            +
                        expect!(')')
         | 
| 76 | 
            +
                        ellipsis = true
         | 
| 77 | 
            +
                        return ellipsis
         | 
| 78 | 
            +
                      end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                      name = ""
         | 
| 81 | 
            +
                      ty = read_func_param(name, typeonly)
         | 
| 82 | 
            +
                      ensure_not_void!(ty)
         | 
| 83 | 
            +
                      types.push(ty)
         | 
| 84 | 
            +
                      if !typeonly
         | 
| 85 | 
            +
                        vars.push(Node.ast_lvar(ty, name, @localenv, @localvars))
         | 
| 86 | 
            +
                      end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                      tok = get
         | 
| 89 | 
            +
                      if Token.is_keyword?(tok, ')')
         | 
| 90 | 
            +
                        return ellipsis
         | 
| 91 | 
            +
                      end
         | 
| 92 | 
            +
                      if !Token.is_keyword?(tok, ',')
         | 
| 93 | 
            +
                        Util.errort!(tok, "comma expected, but got #{tok}")
         | 
| 94 | 
            +
                      end
         | 
| 95 | 
            +
                    end
         | 
| 96 | 
            +
                    raise "must not reach here"
         | 
| 97 | 
            +
                  end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                  # @param [<String>] name
         | 
| 100 | 
            +
                  # @param [Boolean] optional
         | 
| 101 | 
            +
                  # @return [Type]
         | 
| 102 | 
            +
                  def read_func_param(name, optional)
         | 
| 103 | 
            +
                    basety = Type::INT
         | 
| 104 | 
            +
                    if is_type?(peek)
         | 
| 105 | 
            +
                      basety, _ = read_decl_spec
         | 
| 106 | 
            +
                    elsif optional
         | 
| 107 | 
            +
                      Util.errort!(peek, "type expected, but got #{peek}")
         | 
| 108 | 
            +
                    end
         | 
| 109 | 
            +
                    ty = read_declarator(name, basety, nil, optional ? DECL::PARAM_TYPEONLY : DECL::PARAM)
         | 
| 110 | 
            +
                    # C11 6.7.6.3p7: Array of T is adjusted to pointer to T
         | 
| 111 | 
            +
                    # in a function parameter list.
         | 
| 112 | 
            +
                    if ty.kind == Kind::ARRAY
         | 
| 113 | 
            +
                      return Type.make_ptr_type(ty.ptr)
         | 
| 114 | 
            +
                    end
         | 
| 115 | 
            +
                    # C11 6.7.6.3p8: Function is adjusted to pointer to function
         | 
| 116 | 
            +
                    # in a function parameter list.
         | 
| 117 | 
            +
                    if ty.kind == Kind::FUNC
         | 
| 118 | 
            +
                      return Type.make_ptr_type(ty)
         | 
| 119 | 
            +
                    end
         | 
| 120 | 
            +
                    ty
         | 
| 121 | 
            +
                  end
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                  # Reads a K&R-style un-prototyped function parameter list.
         | 
| 124 | 
            +
                  #
         | 
| 125 | 
            +
                  # @param [<Node>] vars
         | 
| 126 | 
            +
                  def read_declarator_params_oldstyle(vars)
         | 
| 127 | 
            +
                    while true
         | 
| 128 | 
            +
                      tok = get
         | 
| 129 | 
            +
                      if tok.kind != T::IDENT
         | 
| 130 | 
            +
                        Util.errort!(tok, "identifier expected, but got #{tok}")
         | 
| 131 | 
            +
                      end
         | 
| 132 | 
            +
                      vars.push(Node.ast_lvar(Type::INT, tok.sval, @localenv, @localvars))
         | 
| 133 | 
            +
                      if next_token?(')')
         | 
| 134 | 
            +
                        return
         | 
| 135 | 
            +
                      end
         | 
| 136 | 
            +
                      if !next_token?(',')
         | 
| 137 | 
            +
                        Util.errort!(tok, "comma expected, but got #{get}")
         | 
| 138 | 
            +
                      end
         | 
| 139 | 
            +
                    end
         | 
| 140 | 
            +
                  end
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                  #
         | 
| 143 | 
            +
                  # Function definition
         | 
| 144 | 
            +
                  #
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                  # @return [Node]
         | 
| 147 | 
            +
                  def read_funcdef
         | 
| 148 | 
            +
                    basetype, sclass = read_decl_spec_opt
         | 
| 149 | 
            +
                    r = nil
         | 
| 150 | 
            +
             | 
| 151 | 
            +
                    with_func_context do
         | 
| 152 | 
            +
                      name = ""    # Used as return value
         | 
| 153 | 
            +
                      params = []  # Used as return value
         | 
| 154 | 
            +
                      functype = read_declarator(name, basetype, params, DECL::BODY)
         | 
| 155 | 
            +
                      if functype.oldstyle
         | 
| 156 | 
            +
                        if (params.size == 0)
         | 
| 157 | 
            +
                          functype.hasva = false
         | 
| 158 | 
            +
                        end
         | 
| 159 | 
            +
                        read_oldstyle_param_type(params)
         | 
| 160 | 
            +
                        functype.params = param_types(params)
         | 
| 161 | 
            +
                      end
         | 
| 162 | 
            +
                      functype.isstatic = (sclass == S::STATIC)
         | 
| 163 | 
            +
                      Node.ast_gvar(functype, name, @globalenv)
         | 
| 164 | 
            +
                      expect!('{')
         | 
| 165 | 
            +
                      r = read_func_body(functype, name, params)
         | 
| 166 | 
            +
                      backfill_labels!
         | 
| 167 | 
            +
                    end
         | 
| 168 | 
            +
             | 
| 169 | 
            +
                    r
         | 
| 170 | 
            +
                  end
         | 
| 171 | 
            +
             | 
| 172 | 
            +
                  def with_func_context(&block)
         | 
| 173 | 
            +
                    @localenv = RMap.new(@globalenv)
         | 
| 174 | 
            +
                    @gotos = []
         | 
| 175 | 
            +
                    @labels = RMap.new
         | 
| 176 | 
            +
             | 
| 177 | 
            +
                    yield
         | 
| 178 | 
            +
             | 
| 179 | 
            +
                    @localenv = nil
         | 
| 180 | 
            +
                    @gotos = nil
         | 
| 181 | 
            +
                    @labels = nil
         | 
| 182 | 
            +
                  end
         | 
| 183 | 
            +
             | 
| 184 | 
            +
                  # @param(return) [<Node>] params
         | 
| 185 | 
            +
                  def read_oldstyle_param_type(params)
         | 
| 186 | 
            +
                    vars = read_oldstyle_param_args
         | 
| 187 | 
            +
                    update_oldstyle_param_type(params, vars)
         | 
| 188 | 
            +
                  end
         | 
| 189 | 
            +
             | 
| 190 | 
            +
                  def read_oldstyle_param_args
         | 
| 191 | 
            +
                    orig = @localenv
         | 
| 192 | 
            +
                    @localenv = nil
         | 
| 193 | 
            +
                    r = []
         | 
| 194 | 
            +
                    while true
         | 
| 195 | 
            +
                      if Token.is_keyword?(peek, '{')
         | 
| 196 | 
            +
                        break
         | 
| 197 | 
            +
                      end
         | 
| 198 | 
            +
                      if !is_type?(peek)
         | 
| 199 | 
            +
                        Util.errort!(peek, "K&R-style declarator expected, but got #{peek}")
         | 
| 200 | 
            +
                      end
         | 
| 201 | 
            +
                      read_decl(r, false)
         | 
| 202 | 
            +
                    end
         | 
| 203 | 
            +
                    @localenv = orig
         | 
| 204 | 
            +
                    r
         | 
| 205 | 
            +
                  end
         | 
| 206 | 
            +
             | 
| 207 | 
            +
                  # @param(return) [Array] params
         | 
| 208 | 
            +
                  # @param [Node] vars
         | 
| 209 | 
            +
                  def update_oldstyle_param_type(params, vars)
         | 
| 210 | 
            +
                    vars.each do |decl|
         | 
| 211 | 
            +
                      Util.assert!{ decl.kind == AST::DECL }
         | 
| 212 | 
            +
                      var = decl.declvar
         | 
| 213 | 
            +
                      Util.assert!{ var.kind == AST::LVAR }
         | 
| 214 | 
            +
                      params.each do |param|
         | 
| 215 | 
            +
                        Util.assert!{ param.kind == AST::LVAR }
         | 
| 216 | 
            +
                        if (param.varname != var.varname)
         | 
| 217 | 
            +
                          next
         | 
| 218 | 
            +
                        end
         | 
| 219 | 
            +
                        param.ty = var.ty
         | 
| 220 | 
            +
                        return  # found
         | 
| 221 | 
            +
                      end
         | 
| 222 | 
            +
                      raise "missing parameter: #{var.varname}"
         | 
| 223 | 
            +
                    end
         | 
| 224 | 
            +
                  end
         | 
| 225 | 
            +
             | 
| 226 | 
            +
                  def backfill_labels!
         | 
| 227 | 
            +
                    @gotos.each do |src|
         | 
| 228 | 
            +
                      label = src.label
         | 
| 229 | 
            +
                      dest = @labels[label]
         | 
| 230 | 
            +
                      if dest.nil?
         | 
| 231 | 
            +
                        raise "stray #{src.kind == AST::GOTO ? "goto" : "unary &&"}: #{label}"
         | 
| 232 | 
            +
                      end
         | 
| 233 | 
            +
             | 
| 234 | 
            +
                      if dest.newlabel
         | 
| 235 | 
            +
                        src.newlabel = dest.newlabel
         | 
| 236 | 
            +
                      else
         | 
| 237 | 
            +
                        src.newlabel = dest.newlabel = @label_gen.next
         | 
| 238 | 
            +
                      end
         | 
| 239 | 
            +
                    end
         | 
| 240 | 
            +
                  end
         | 
| 241 | 
            +
             | 
| 242 | 
            +
                  # @param [Type] functype
         | 
| 243 | 
            +
                  # @param [String] fname
         | 
| 244 | 
            +
                  # @param [Array] params
         | 
| 245 | 
            +
                  # @return [Node]
         | 
| 246 | 
            +
                  def read_func_body(functype, fname, params)
         | 
| 247 | 
            +
                    r = nil
         | 
| 248 | 
            +
             | 
| 249 | 
            +
                    with_func_body_context(functype) do
         | 
| 250 | 
            +
                      funcname = Node.ast_string(ENC::NONE, fname)
         | 
| 251 | 
            +
                      @localenv["__func__"] = funcname
         | 
| 252 | 
            +
                      @localenv["__FUNCTION__"] = funcname
         | 
| 253 | 
            +
                      body = read_compound_stmt
         | 
| 254 | 
            +
                      r = Node.ast_func(functype, fname, params, body, @localvars)
         | 
| 255 | 
            +
                    end
         | 
| 256 | 
            +
             | 
| 257 | 
            +
                    r
         | 
| 258 | 
            +
                  end
         | 
| 259 | 
            +
             | 
| 260 | 
            +
                  # @param [Type] functype
         | 
| 261 | 
            +
                  def with_func_body_context(functype, &block)
         | 
| 262 | 
            +
                    @localenv = RMap.new(@localenv)
         | 
| 263 | 
            +
                    @localvars = []
         | 
| 264 | 
            +
                    @current_func_type = functype
         | 
| 265 | 
            +
             | 
| 266 | 
            +
                    yield
         | 
| 267 | 
            +
             | 
| 268 | 
            +
                    @localenv = nil
         | 
| 269 | 
            +
                    @localvars = nil
         | 
| 270 | 
            +
                    @current_func_type = nil
         | 
| 271 | 
            +
                  end
         | 
| 272 | 
            +
                end
         | 
| 273 | 
            +
              end
         | 
| 274 | 
            +
            end
         | 
| @@ -0,0 +1,54 @@ | |
| 1 | 
            +
            module Rucc
         | 
| 2 | 
            +
              class Parser
         | 
| 3 | 
            +
                module FuncCall
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                private
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  # @param [Node] fp
         | 
| 8 | 
            +
                  def read_funcall(fp)
         | 
| 9 | 
            +
                    if (fp.kind == AST::ADDR) && (fp.operand.kind == AST::FUNCDESG)
         | 
| 10 | 
            +
                      desg = fp.operand
         | 
| 11 | 
            +
                      args = read_func_args(desg.ty.params)
         | 
| 12 | 
            +
                      return Node.ast_funcall(desg.ty, desg.fname, args)
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
                    args = read_func_args(fp.ty.ptr.params)
         | 
| 15 | 
            +
                    Node.ast_funcptr_call(fp, args)
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  # @param [Array] params
         | 
| 19 | 
            +
                  # @return [Array]
         | 
| 20 | 
            +
                  def read_func_args(params)
         | 
| 21 | 
            +
                    args = []
         | 
| 22 | 
            +
                    i = 0
         | 
| 23 | 
            +
                    while true
         | 
| 24 | 
            +
                      break if next_token?(')')
         | 
| 25 | 
            +
                      arg = Node.conv(read_assignment_expr)
         | 
| 26 | 
            +
                      if i < params.size
         | 
| 27 | 
            +
                        paramtype = params[i]
         | 
| 28 | 
            +
                        i += 1
         | 
| 29 | 
            +
                      else
         | 
| 30 | 
            +
                        paramtype =
         | 
| 31 | 
            +
                          if Type.is_flotype(arg.ty)
         | 
| 32 | 
            +
                            Type::DOUBLE
         | 
| 33 | 
            +
                          elsif Type.is_inttype(arg.ty)
         | 
| 34 | 
            +
                            Type::INT
         | 
| 35 | 
            +
                          else
         | 
| 36 | 
            +
                            arg.ty
         | 
| 37 | 
            +
                          end
         | 
| 38 | 
            +
                      end
         | 
| 39 | 
            +
                      Type.ensure_assignable!(paramtype, arg.ty)
         | 
| 40 | 
            +
                      if paramtype.kind != arg.ty.kind
         | 
| 41 | 
            +
                        arg = Node.ast_conv(paramtype, arg)
         | 
| 42 | 
            +
                      end
         | 
| 43 | 
            +
                      args.push(arg)
         | 
| 44 | 
            +
                      tok = get
         | 
| 45 | 
            +
                      break if Token.is_keyword?(tok, ')')
         | 
| 46 | 
            +
                      if !Token.is_keyword?(tok, ',')
         | 
| 47 | 
            +
                        Util.errort(tok, "unexpected token: '#{tok}'")
         | 
| 48 | 
            +
                      end
         | 
| 49 | 
            +
                    end
         | 
| 50 | 
            +
                    args
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
            end
         | 
| @@ -0,0 +1,29 @@ | |
| 1 | 
            +
            module Rucc
         | 
| 2 | 
            +
              class Parser
         | 
| 3 | 
            +
                module Goto
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                private
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  # @return [Node]
         | 
| 8 | 
            +
                  def read_goto_stmt
         | 
| 9 | 
            +
                    if next_token?('*')
         | 
| 10 | 
            +
                      # [GNU] computed goto. "goto *p" jumps to the address pointed by p.
         | 
| 11 | 
            +
                      tok = peek
         | 
| 12 | 
            +
                      expr = read_cast_expr
         | 
| 13 | 
            +
                      if expr.ty.kind != Kind::PTR
         | 
| 14 | 
            +
                        Util.errort!(tok, "pointer expected for computed goto, but got #{expr}")
         | 
| 15 | 
            +
                      end
         | 
| 16 | 
            +
                      return Node.ast_computed_goto(expr)
         | 
| 17 | 
            +
                    end
         | 
| 18 | 
            +
                    tok = get
         | 
| 19 | 
            +
                    if !tok || (tok.kind != T::IDENT)
         | 
| 20 | 
            +
                      Util.errort!(tok, "identifier expected, but got #{tok}")
         | 
| 21 | 
            +
                    end
         | 
| 22 | 
            +
                    expect!(';')
         | 
| 23 | 
            +
                    r = Node.ast_goto(tok.sval)
         | 
| 24 | 
            +
                    @gotos.push(r)
         | 
| 25 | 
            +
                    r
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
            end
         | 
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            module Rucc
         | 
| 2 | 
            +
              class Parser
         | 
| 3 | 
            +
                module If
         | 
| 4 | 
            +
                private
         | 
| 5 | 
            +
                  def read_if_stmt
         | 
| 6 | 
            +
                    expect!('(')
         | 
| 7 | 
            +
                    cond = read_boolean_expr
         | 
| 8 | 
            +
                    expect!(')')
         | 
| 9 | 
            +
                    thn = read_stmt
         | 
| 10 | 
            +
                    if !next_token?(K::ELSE)
         | 
| 11 | 
            +
                      return Node.ast_if(cond, thn, nil)
         | 
| 12 | 
            +
                    end
         | 
| 13 | 
            +
                    els = read_stmt
         | 
| 14 | 
            +
                    Node.ast_if(cond, thn, els)
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def read_boolean_expr
         | 
| 18 | 
            +
                    cond = read_expr
         | 
| 19 | 
            +
                    Type.is_flotype(cond.ty) ? Node.ast_conv(Type::BOOL, cond) : cond
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
            end
         |