module Rucc::Parser::Func
Private Instance Methods
backfill_labels!()
click to toggle source
# File lib/rucc/parser/func.rb, line 226 def backfill_labels! @gotos.each do |src| label = src.label dest = @labels[label] if dest.nil? raise "stray #{src.kind == AST::GOTO ? "goto" : "unary &&"}: #{label}" end if dest.newlabel src.newlabel = dest.newlabel else src.newlabel = dest.newlabel = @label_gen.next end end end
read_declarator_func(basety, params)
click to toggle source
@param [Type] basety @param(return) [Array] params @return [Type]
# File lib/rucc/parser/func.rb, line 10 def read_declarator_func(basety, params) if basety.kind == Kind::FUNC raise "function returning a function" end if basety.kind == Kind::ARRAY raise "function returning an array" end read_func_param_list(params, basety) end
read_declarator_params(types, vars)
click to toggle source
@param [Array] types @param [Array] vars @return [Boolean] ellipsis
# File lib/rucc/parser/func.rb, line 66 def read_declarator_params(types, vars) typeonly = vars.nil? ellipsis = false while true tok = peek if next_token?(K::ELLIPSIS) if types.size == 0 Util.errort!(tok, "at least one parameter is required before \"...\"") end expect!(')') ellipsis = true return ellipsis end name = "" ty = read_func_param(name, typeonly) ensure_not_void!(ty) types.push(ty) if !typeonly vars.push(Node.ast_lvar(ty, name, @localenv, @localvars)) end tok = get if Token.is_keyword?(tok, ')') return ellipsis end if !Token.is_keyword?(tok, ',') Util.errort!(tok, "comma expected, but got #{tok}") end end raise "must not reach here" end
read_declarator_params_oldstyle(vars)
click to toggle source
Reads a K&R-style un-prototyped function parameter list.
@param [<Node>] vars
# File lib/rucc/parser/func.rb, line 126 def read_declarator_params_oldstyle(vars) while true tok = get if tok.kind != T::IDENT Util.errort!(tok, "identifier expected, but got #{tok}") end vars.push(Node.ast_lvar(Type::INT, tok.sval, @localenv, @localvars)) if next_token?(')') return end if !next_token?(',') Util.errort!(tok, "comma expected, but got #{get}") end end end
read_func_body(functype, fname, params)
click to toggle source
@param [Type] functype @param [String] fname @param [Array] params @return [Node]
# File lib/rucc/parser/func.rb, line 246 def read_func_body(functype, fname, params) r = nil with_func_body_context(functype) do funcname = Node.ast_string(ENC::NONE, fname) @localenv["__func__"] = funcname @localenv["__FUNCTION__"] = funcname body = read_compound_stmt r = Node.ast_func(functype, fname, params, body, @localvars) end r end
read_func_param(name, optional)
click to toggle source
@param [<String>] name @param [Boolean] optional @return [Type]
# File lib/rucc/parser/func.rb, line 102 def read_func_param(name, optional) basety = Type::INT if is_type?(peek) basety, _ = read_decl_spec elsif optional Util.errort!(peek, "type expected, but got #{peek}") end ty = read_declarator(name, basety, nil, optional ? DECL::PARAM_TYPEONLY : DECL::PARAM) # C11 6.7.6.3p7: Array of T is adjusted to pointer to T # in a function parameter list. if ty.kind == Kind::ARRAY return Type.make_ptr_type(ty.ptr) end # C11 6.7.6.3p8: Function is adjusted to pointer to function # in a function parameter list. if ty.kind == Kind::FUNC return Type.make_ptr_type(ty) end ty end
read_func_param_list(paramvars, rettype)
click to toggle source
@param [Array, NilClass] paramvars @param [Type] rettype @return [Type]
# File lib/rucc/parser/func.rb, line 23 def read_func_param_list(paramvars, rettype) # C11 6.7.6.3p10: A parameter list with just "void" specifies that # the function has no parameters. tok = get if Token.is_keyword?(tok, K::VOID) && next_token?(')') return Type.make_func_type(rettype, [], false, false) end # C11 6.7.6.3p14: K&R-style un-prototyped declaration or # function definition having no parameters. # We return a type representing K&R-style declaration here. # If this is actually part of a declartion, the type will be fixed later. if Token.is_keyword?(tok, ')') return Type.make_func_type(rettype, [], true, true) end @lexer.unget_token(tok) tok2 = peek if next_token?(K::ELLIPSIS) Util.errort!(tok2, "at least one parameter is required before \"...\"") end if is_type?(peek) paramtypes = [] ellipsis = read_declarator_params(paramtypes, paramvars) return Type.make_func_type(rettype, paramtypes, ellipsis, false) end if paramvars.nil? Util.errort!(tok, "invalid function definition") end read_declarator_params_oldstyle(paramvars) paramtypes = [] (0..(paramvars.size - 1)).each do paramtypes.push Type::INT end Type.make_func_type(rettype, paramtypes, false, true) end
read_funcdef()
click to toggle source
@return [Node]
# File lib/rucc/parser/func.rb, line 147 def read_funcdef basetype, sclass = read_decl_spec_opt r = nil with_func_context do name = "" # Used as return value params = [] # Used as return value functype = read_declarator(name, basetype, params, DECL::BODY) if functype.oldstyle if (params.size == 0) functype.hasva = false end read_oldstyle_param_type(params) functype.params = param_types(params) end functype.isstatic = (sclass == S::STATIC) Node.ast_gvar(functype, name, @globalenv) expect!('{') r = read_func_body(functype, name, params) backfill_labels! end r end
read_oldstyle_param_args()
click to toggle source
# File lib/rucc/parser/func.rb, line 190 def read_oldstyle_param_args orig = @localenv @localenv = nil r = [] while true if Token.is_keyword?(peek, '{') break end if !is_type?(peek) Util.errort!(peek, "K&R-style declarator expected, but got #{peek}") end read_decl(r, false) end @localenv = orig r end
read_oldstyle_param_type(params)
click to toggle source
@param(return) [<Node>] params
# File lib/rucc/parser/func.rb, line 185 def read_oldstyle_param_type(params) vars = read_oldstyle_param_args update_oldstyle_param_type(params, vars) end
update_oldstyle_param_type(params, vars)
click to toggle source
@param(return) [Array] params @param [Node] vars
# File lib/rucc/parser/func.rb, line 209 def update_oldstyle_param_type(params, vars) vars.each do |decl| Util.assert!{ decl.kind == AST::DECL } var = decl.declvar Util.assert!{ var.kind == AST::LVAR } params.each do |param| Util.assert!{ param.kind == AST::LVAR } if (param.varname != var.varname) next end param.ty = var.ty return # found end raise "missing parameter: #{var.varname}" end end
with_func_body_context(functype) { || ... }
click to toggle source
@param [Type] functype
# File lib/rucc/parser/func.rb, line 261 def with_func_body_context(functype, &block) @localenv = RMap.new(@localenv) @localvars = [] @current_func_type = functype yield @localenv = nil @localvars = nil @current_func_type = nil end
with_func_context() { || ... }
click to toggle source
# File lib/rucc/parser/func.rb, line 172 def with_func_context(&block) @localenv = RMap.new(@globalenv) @gotos = [] @labels = RMap.new yield @localenv = nil @gotos = nil @labels = nil end