[NEW] do statement, d 10 a = a * a e

This commit is contained in:
sjs 2009-05-20 13:28:44 -07:00
parent dd6d342dd4
commit f7e63cbe21
2 changed files with 72 additions and 49 deletions

View file

@ -26,13 +26,11 @@ class Compiler
@vars = {} # symbol table @vars = {} # symbol table
@num_labels = 0 # used to generate unique labels @num_labels = 0 # used to generate unique labels
@num_labels_with_suffix = Hash.new(0) @num_labels_with_suffix = Hash.new(0)
@num_conditions = 0
@break_stack = [] # for breaking out of loops
# reserved words (... constant?) # reserved words (... constant?)
# #
# if, else, end, while, until, repeat, break # if, else, end, while, until, repeat, for, do, break
@keywords = %w[i l e w u r b] @keywords = %w[i l e w u r f d b]
# seed the lexer # seed the lexer
get_char get_char
@ -133,53 +131,48 @@ class Compiler
x86_mov("dword [#{name}]", :eax) x86_mov("dword [#{name}]", :eax)
end end
# Parse a statement.
def statement
case @look
when 'i'
if_else_stmt
when 'w'
while_stmt
when 'u'
until_stmt
when 'r'
repeat_stmt
when 'f'
for_stmt
when 'b'
break_stmt
else
assignment
newline
end
end
# Parse a code block. # Parse a code block.
def block(label=nil) def block(label=nil)
@break_stack.push(label) if label
until @look == 'l' || @look == 'e' || eof? until @look == 'l' || @look == 'e' || eof?
statement case @look
when 'i'
if_else_stmt(label)
when 'w'
while_stmt
when 'u'
until_stmt
when 'r'
repeat_stmt
when 'f'
for_stmt
when 'd'
do_stmt
when 'b'
break_stmt(label)
else
assignment
newline
end
skip_any_whitespace skip_any_whitespace
end end
@break_stack.pop if label
end end
# Parse an if-else statement. # Parse an if-else statement.
def if_else_stmt def if_else_stmt(label)
match('i') match('i')
condition condition
skip_any_whitespace skip_any_whitespace
else_label = unique_label(:end_or_else) else_label = unique_label(:end_or_else)
end_label = else_label # only generated if else clause present end_label = else_label # only generated if else clause present
x86_jz(else_label) x86_jz(else_label)
block block(label)
if @look == 'l' if @look == 'l'
match('l') match('l')
skip_any_whitespace skip_any_whitespace
end_label = unique_label(:endif) # now we need the 2nd label end_label = unique_label(:endif) # now we need the 2nd label
x86_jmp(end_label) x86_jmp(end_label)
emit_label(else_label) emit_label(else_label)
block block(label)
end end
match('e') match('e')
emit_label(end_label) emit_label(end_label)
@ -257,19 +250,41 @@ class Compiler
x86_add(:esp, 4) # clean up the stack x86_add(:esp, 4) # clean up the stack
end end
def break_stmt # d 5
# ...
# e
def do_stmt
match('d')
start_label = unique_label(:do)
end_label = unique_label(:enddo)
expression
skip_any_whitespace
x86_mov(:ecx, :eax)
x86_push(:ecx)
counter = '[esp]'
emit_label(start_label)
x86_mov(counter, :ecx)
block(end_label)
x86_mov(:ecx, counter)
match('e')
x86_loop(start_label)
x86_sub(:esp, 4)
emit_label(end_label)
x86_add(:esp, 4)
end
def break_stmt(label)
match('b') match('b')
if @break_stack.empty? if label
x86_jmp(label)
else
expected(:'break to be somewhere useful', expected(:'break to be somewhere useful',
:got => :'a break without a loop') :got => :'a break outside a loop')
end end
x86_jmp(@break_stack.last)
end end
# Evaluates any expression for now. There are no boolean operators. # Evaluates any expression for now. There are no boolean operators.
def condition def condition
# @num_conditions += 1
# emit("<condition ##{@num_conditions}>")
expression expression
x86_cmp(:eax, 0) # 0 is false, anything else is true x86_cmp(:eax, 0) # 0 is false, anything else is true
skip_whitespace skip_whitespace
@ -415,7 +430,7 @@ class Compiler
end end
# Get an identifier. # Parse a name (identifier).
def get_name def get_name
expected(:identifier) unless alpha?(@look) expected(:identifier) unless alpha?(@look)
name = many(method(:alnum?)) name = many(method(:alnum?))
@ -425,7 +440,7 @@ class Compiler
name name
end end
# Get a number. # Parse a number.
def get_num def get_num
expected(:integer) unless digit?(@look) expected(:integer) unless digit?(@look)
many(method(:digit?)) many(method(:digit?))
@ -539,4 +554,8 @@ class Compiler
def x86_cmp(a, b) def x86_cmp(a, b)
emit("cmp #{a}, #{b}") emit("cmp #{a}, #{b}")
end end
def x86_loop(label)
emit("loop #{label}")
end
end end

View file

@ -3,28 +3,28 @@ aa=10
somethinglong=65536 somethinglong=65536
x=5*(3-5) x=5*(3-5)
c=a-1 c=a-1
d=-1 g=-1
g=x*2+2 h=x*2+2
h=g-27/9 j=h-27/9
j=h-8/2 k=j-8/2
k=j-4*(5+5+5) m=k-4*(5+5+5)
m=k+85 n=m+85
i 1 i 1
d=3 x=3
i 1 c=4 i 1 c=4
e e
e e
i1d=3 i1x=3
i1c=4 i1c=4
ee ee
i 1 i 1
d=3 x=3
i 1 c=4 i 1 c=4
e e
l l
d=2 x=2
e e
w 0 w 0
@ -50,4 +50,8 @@ f x = 1 >> 5
s = s + x s = s + x
e e
d 10
a = a * a
e
xitcode=a-a xitcode=a-a