clean up block by moving keywords into a lookup table.

This commit is contained in:
Sami Samhuri 2010-02-08 23:37:27 -08:00
parent 0db6becd33
commit 3422f201d1
2 changed files with 57 additions and 47 deletions

View file

@ -27,10 +27,18 @@ class Compiler
include Assembler::Registers include Assembler::Registers
Keywords = %w[ Keywords = {
if else end while until repeat for to do break 'if' => :if_else_stmt,
print 'while' => :while_stmt,
] 'until' => :until_stmt,
'repeat' => :repeat_stmt,
'for' => :for_stmt,
'do' => :do_stmt,
'break' => :break_stmt,
'print' => :print_stmt,
'else' => nil,
'end' => nil
}
attr_reader :asm attr_reader :asm
@ -41,6 +49,9 @@ class Compiler
@value = nil # Value of last read token. @value = nil # Value of last read token.
@input = input # Stream to read from. @input = input # Stream to read from.
@asm = asm # assembler @asm = asm # assembler
@keywords = Keywords.clone
@keyword_names = @keywords.keys
@label_stack = []
# seed the lexer # seed the lexer
get_char get_char
@ -380,6 +391,13 @@ class Compiler
# statements and controls structures # # statements and controls structures #
###################################### ######################################
def keyword
unless action = @keywords[@value]
raise "unsupported keyword: #{@value}"
end
send(action)
end
# Parse an assignment statement. Value is in eax. # Parse an assignment statement. Value is in eax.
def assignment def assignment
name = @value name = @value
@ -390,59 +408,35 @@ class Compiler
end end
# Parse a code block. # Parse a code block.
# def block
# TODO replace the case..when with a lookup table @indent += 1
# (might be exposed in the language later)
def block(label=nil)
scan scan
until @value == 'else' || @value == 'end' || eof? until @value == 'else' || @value == 'end' || eof?
if @token == :keyword if @token == :keyword
case @value keyword
when 'if'
if_else_stmt(label)
when 'while'
while_stmt
when 'until'
until_stmt
when 'repeat'
repeat_stmt
when 'for'
for_stmt
when 'do'
do_stmt
when 'break'
break_stmt(label)
when 'print'
print_stmt
else
raise "unsupported keyword: #{@value}"
end
else else
assignment assignment
end end
scan scan
end end
@indent -= 1
end end
# Parse an if-else statement. # Parse an if-else statement.
def if_else_stmt(label) def if_else_stmt
else_label = asm.mklabel(:end_or_else) else_label = asm.mklabel(:end_or_else)
end_label = else_label # only generated if else clause end_label = else_label # only generated if else clause
# present # present
condition condition
skip_any_whitespace skip_any_whitespace
asm.jz(else_label) asm.jz(else_label)
@indent += 1 block
block(label)
@indent -= 1
if @token == :keyword && @value == 'else' if @token == :keyword && @value == 'else'
skip_any_whitespace skip_any_whitespace
end_label = asm.mklabel(:endif) # now we need the 2nd label end_label = asm.mklabel(:endif) # now we need the 2nd label
asm.jmp(end_label) asm.jmp(end_label)
asm.deflabel(else_label) asm.deflabel(else_label)
@indent += 1 block
block(label)
@indent -= 1
end end
match_word('end') match_word('end')
asm.deflabel(end_label) asm.deflabel(end_label)
@ -457,12 +451,8 @@ class Compiler
start_label = asm.mklabel(:"#{name}_loop") start_label = asm.mklabel(:"#{name}_loop")
end_label = asm.mklabel(:"end_#{name}") end_label = asm.mklabel(:"end_#{name}")
asm.deflabel(start_label) asm.deflabel(start_label)
yield(end_label) yield(end_label)
pushing_label(end_label) { block }
@indent += 1
block(end_label)
@indent -= 1
match_word('end') match_word('end')
asm.jmp(start_label) asm.jmp(start_label)
asm.deflabel(end_label) asm.deflabel(end_label)
@ -534,9 +524,7 @@ class Compiler
asm.push(ECX) asm.push(ECX)
@indent += 1 pushing_label(end_label) { block }
block(end_label)
@indent -= 1
asm.pop(ECX) asm.pop(ECX)
@ -556,9 +544,9 @@ class Compiler
asm.add(ESP, 4) asm.add(ESP, 4)
end end
def break_stmt(label) def break_stmt
if label if top_label
asm.jmp(label) asm.jmp(top_label)
else else
expected(:'break to be somewhere useful', expected(:'break to be somewhere useful',
:got => :'a break outside a loop') :got => :'a break outside a loop')
@ -798,7 +786,7 @@ class Compiler
def get_name def get_name
expected(:identifier) unless alpha?(@look) expected(:identifier) unless alpha?(@look)
@value = many(:alnum?) @value = many(:alnum?)
@token = Keywords.include?(@value) ? :keyword : :identifier @token = @keyword_names.include?(@value) ? :keyword : :identifier
@value @value
end end
@ -889,6 +877,24 @@ class Compiler
puts @value puts @value
end end
def pushing_label(label)
push_label(label)
yield
pop_label
end
def push_label(label)
@label_stack.push(label)
end
def top_label
@label_stack[-1]
end
def pop_label
@label_stack.pop
end
# hook(:print_token, # hook(:print_token,
# :get_name, :get_newline, :get_number, :get_op, :get_boolean) # :get_name, :get_newline, :get_number, :get_op, :get_boolean)

4
test/test_overflow.code Normal file
View file

@ -0,0 +1,4 @@
a=2*2*2*2*2*2*2*2*2*2
a=a*a*a*2*2