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

View file

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