From f7e63cbe215f35ce66e95caa11fd5d4563702e3c Mon Sep 17 00:00:00 2001 From: sjs Date: Wed, 20 May 2009 13:28:44 -0700 Subject: [PATCH] [NEW] do statement, d 10 a = a * a e --- compiler.rb | 97 ++++++++++++++++++++++++++++++++--------------------- test.code | 24 +++++++------ 2 files changed, 72 insertions(+), 49 deletions(-) diff --git a/compiler.rb b/compiler.rb index 391d04b..529a8d3 100644 --- a/compiler.rb +++ b/compiler.rb @@ -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("") 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 diff --git a/test.code b/test.code index 5dfcd36..9de781d 100644 --- a/test.code +++ b/test.code @@ -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