module Rucc::Parser::Switch
Private Instance Methods
check_case_duplicates!()
click to toggle source
C11 6.8.4.2p3: No two case constant expressions have the same value.
# File lib/rucc/parser/switch.rb, line 89 def check_case_duplicates! len = @cases.size x = @cases[len - 1] @cases[0..-2].each do |y| if (x.e < y.b) || (y.e < x.b) next end if (x.b == x.e) raise "duplicate case value: #{x.b}" # error("duplicate case value: %d", x->beg) end raise "duplicate case value: #{x.b} ... #{x.e}" # error("duplicate case value: #{x.b} ... #{x.e}") end end
make_switch_jump(var, c)
click to toggle source
@param [Node] var @param [Case] c @return [Node]
# File lib/rucc/parser/switch.rb, line 54 def make_switch_jump(var, c) if c.b == c.e cond = Node.ast_binop(Type::INT, OP::EQ, var, Node.ast_inttype(Type::INT, c.b)) else # [GNU] case i ... j is compiled to if (i <= cond && cond <= j) goto <label>. x = Node.ast_binop(Type::INT, OP::LE, Node.ast_inttype(Type::INT, c.b), var) y = Node.ast_binop(Type::INT, OP::LE, var, Node.ast_inttype(Type::INT, c.e)) cond = Node.ast_binop(Type::INT, OP::LOGAND, x, y) end Node.ast_if(cond, Node.ast_jump(c.label), nil) end
read_case_label(tok)
click to toggle source
@return [Node]
# File lib/rucc/parser/switch.rb, line 67 def read_case_label(tok) if !@cases Util.errort!(tok, "stray case label") end label = @label_gen.next b = read_intexpr if next_token?(K::ELLIPSIS) e = read_intexpr expect!(':') if b > e Util.errort!(tok, "case region is not in correct order: #{b} ... #{e}") end @cases.push(Case.make_case(b, e, label)) else expect!(':') @cases.push(Case.make_case(b, b, label)) end check_case_duplicates! read_label_tail(Node.ast_dest(label)) end
read_default_label(tok)
click to toggle source
@param [Token] tok @return [Node]
# File lib/rucc/parser/switch.rb, line 107 def read_default_label(tok) expect!(':'); if @defaultcase Util.errort!(tok, "duplicate default") end @defaultcase = @label_gen.next read_label_tail(Node.ast_dest(@defaultcase)) end
read_switch_stmt()
click to toggle source
@return [Node]
# File lib/rucc/parser/switch.rb, line 10 def read_switch_stmt expect!('(') expr = Node.conv(read_expr) ensure_inttype!(expr) expect!(')') e = @label_gen.next v = [] with_switch_context(e) do body = read_stmt var = Node.ast_lvar(expr.ty, @tempname_gen.next, @localenv, @localvars) v.push(Node.ast_binop(expr.ty, '=', var, expr)) @cases.each do |c| v.push(make_switch_jump(var, c)) end v.push(Node.ast_jump(@defaultcase ? @defaultcase : e)) if body v.push(body) end v.push(Node.ast_dest(e)) end Node.ast_compound_stmt(v) end
with_switch_context(brk) { || ... }
click to toggle source
# File lib/rucc/parser/switch.rb, line 34 def with_switch_context(brk, &block) # Set switch context ocases = @cases odefaultcase = @defaultcase obreak = @lbreak @cases = [] @defaultcase = nil @lbreak = brk yield # Restore switch context @cases = ocases @defaultcase = odefaultcase @lbreak = obreak end