mirror of
https://github.com/samsonjs/compiler.git
synced 2026-04-27 14:57:45 +00:00
clean up block by moving keywords into a lookup table.
This commit is contained in:
parent
0db6becd33
commit
3422f201d1
2 changed files with 57 additions and 47 deletions
100
compiler.rb
100
compiler.rb
|
|
@ -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
4
test/test_overflow.code
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
a=2*2*2*2*2*2*2*2*2*2
|
||||||
|
a=a*a*a*2*2
|
||||||
|
|
||||||
|
|
||||||
Loading…
Reference in a new issue