stuff
This commit is contained in:
parent
fc3eaf7abe
commit
ae23e9fbe6
160
compiler.rb
160
compiler.rb
@ -1,9 +1,3 @@
|
|||||||
# TODO: Make compilation two-phase:
|
|
||||||
=begin
|
|
||||||
Phase one will accept an array of tokens and update the tables accordingly.
|
|
||||||
Phase two wil take the data from the tables and do the actual compilation.
|
|
||||||
=end
|
|
||||||
|
|
||||||
$types=[:int,:void]
|
$types=[:int,:void]
|
||||||
$functable={}
|
$functable={}
|
||||||
$cfunc=nil
|
$cfunc=nil
|
||||||
@ -17,15 +11,58 @@ class String
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def is_var(var)
|
||||||
|
return false if var.class!=Symbol
|
||||||
|
vartable=$functable[$cfunc][:vars]
|
||||||
|
argtable=$functable[$cfunc][:args]
|
||||||
|
if vartable.include? var or argtable.include? var
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def get_index(var)
|
def get_index(var)
|
||||||
vartable=$functable[$cfunc][:vars]
|
vartable=$functable[$cfunc][:vars]
|
||||||
|
argtable=$functable[$cfunc][:args]
|
||||||
if vartable.include? var
|
if vartable.include? var
|
||||||
return vartable.find_index(var)
|
return vartable.find_index(var),"local"
|
||||||
else
|
else
|
||||||
|
if argtable.include? var
|
||||||
|
return argtable.find_index(var),"argument"
|
||||||
|
end
|
||||||
raise CompilationError,"No such variable #{var}"
|
raise CompilationError,"No such variable #{var}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def push(obj)
|
||||||
|
if obj.class == Symbol
|
||||||
|
index,segment=get_index(obj)
|
||||||
|
$outfile.puts "push #{segment} #{index}"
|
||||||
|
elsif obj.class == String
|
||||||
|
if obj.is_integer?
|
||||||
|
$outfile.puts "push constant #{obj.to_i}"
|
||||||
|
elsif is_var(obj.to_sym)
|
||||||
|
index,segment=get_index(obj.to_sym)
|
||||||
|
$outfile.puts "push #{segment} #{index}"
|
||||||
|
else
|
||||||
|
raise CompilationError, "Cannot push #{obj}, is not a variable or a number."
|
||||||
|
end
|
||||||
|
elsif obj.is_a? Numeric
|
||||||
|
$outfile.puts "push constant #{obj}"
|
||||||
|
else
|
||||||
|
raise CompilationError, "Cannot push #{obj}, is not a variable or a number."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def pop(var)
|
||||||
|
if var.class != Symbol and !is_var(var)
|
||||||
|
raise CompilationError, "Cannot push #{var}, is not a variable."
|
||||||
|
end
|
||||||
|
index,segment=get_index(var)
|
||||||
|
$outfile.puts "pop #{segment} #{index}"
|
||||||
|
end
|
||||||
|
|
||||||
def tokenize_line(line)
|
def tokenize_line(line)
|
||||||
split_line=line.split(" ")
|
split_line=line.split(" ")
|
||||||
cmd=split_line.shift.to_sym
|
cmd=split_line.shift.to_sym
|
||||||
@ -33,61 +70,109 @@ def tokenize_line(line)
|
|||||||
if $types.include? cmd
|
if $types.include? cmd
|
||||||
if /(\w+)\((.*)\) \{/.match(split_line.join(" "))
|
if /(\w+)\((.*)\) \{/.match(split_line.join(" "))
|
||||||
tokens.push(:func)
|
tokens.push(:func)
|
||||||
|
tokens.push(cmd)
|
||||||
tokens.push($1.to_sym)
|
tokens.push($1.to_sym)
|
||||||
tokens.push($2)
|
args=[]
|
||||||
|
$2.split(",").each do |arg|
|
||||||
|
temp=arg.split(" ")
|
||||||
|
args.push(temp[1].to_sym)
|
||||||
|
end
|
||||||
|
tokens.push(args)
|
||||||
else
|
else
|
||||||
tokens.push(:newvar)
|
tokens.push(:newvar)
|
||||||
tokens.push(cmd)
|
tokens.push(cmd)
|
||||||
tokens.push(split_line[0].to_sym)
|
tokens.push(split_line[0].to_sym)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
if /(\w+)\((.*)\)/.match(cmd)
|
||||||
|
tokens.push(:call)
|
||||||
|
tokens.push($1.to_sym)
|
||||||
|
args=[]
|
||||||
|
$2.split(",").each do |arg|
|
||||||
|
args.push(arg.to_sym)
|
||||||
|
end
|
||||||
|
tokens.push(args)
|
||||||
|
end
|
||||||
if split_line[0] == "="
|
if split_line[0] == "="
|
||||||
tokens.push(:assignment)
|
tokens.push(:assignment)
|
||||||
tokens.push(cmd.to_sym)
|
tokens.push(cmd)
|
||||||
tokens.push(split_line[1])
|
tokens.push(split_line[1])
|
||||||
end
|
end
|
||||||
if cmd == "}"
|
if cmd == "}"
|
||||||
tokens.push(:endfunc)
|
tokens.push(:endfunc)
|
||||||
end
|
end
|
||||||
|
if cmd == :return
|
||||||
|
tokens.push(:return)
|
||||||
|
tokens.push(split_line[0])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
return tokens
|
return tokens
|
||||||
end
|
end
|
||||||
|
|
||||||
def phase_one(tokens)
|
def phase_one(tokens)
|
||||||
if $cfunc==nil and tokens[0] != :func
|
if $cfunc==nil and tokens[0] != :func
|
||||||
raise CompilationError, "Code must be inside a fuction"
|
raise CompilationError, "Code must be inside a fuction, for line #{tokens}"
|
||||||
end
|
end
|
||||||
case tokens[0]
|
case tokens[0]
|
||||||
when :func
|
when :func
|
||||||
$functable[tokens[1]]={:vars=>[],:code=>[]}
|
$functable[tokens[2]]={:vars=>[],:code=>[], :type=>tokens[1], :args=>tokens[3]}
|
||||||
$cfunc=tokens[1]
|
$cfunc=tokens[2]
|
||||||
when :endfunc
|
when :endfunc
|
||||||
$cfunc=nil
|
$cfunc=nil
|
||||||
when :newvar
|
when :newvar
|
||||||
$functable[$cfunc][:vars].push(tokens[2])
|
$functable[$cfunc][:vars].push(tokens[2])
|
||||||
else
|
else
|
||||||
$functable[$cfunc][:code].push(tokens)
|
$functable[$cfunc][:code].push(tokens) if tokens != []
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def phase_two
|
def phase_two
|
||||||
$functable.each do |func,info|
|
$functable.each do |func,info|
|
||||||
|
$cfunc=func
|
||||||
vars=info[:vars]
|
vars=info[:vars]
|
||||||
$outfile.puts "function Main.#{func.to_s} #{vars.length}"
|
$outfile.puts "function Main.#{func.to_s} #{vars.length}"
|
||||||
info[:code].each do |line|
|
info[:code].each do |line|
|
||||||
#puts "Parsing line #{line}"
|
|
||||||
action=line.shift
|
action=line.shift
|
||||||
case action
|
case action
|
||||||
when :assignment
|
when :assignment
|
||||||
index=get_index(line[0])
|
if line[1].is_integer? or is_var(line[1])
|
||||||
if line[1].is_integer?
|
push(line[1])
|
||||||
$outfile.puts "push constant #{line[1].to_i}"
|
|
||||||
$outfile.puts "pop local #{index}"
|
|
||||||
else
|
else
|
||||||
index1=get_index(line[1])
|
parsed_line=tokenize_line(line[1])
|
||||||
$outfile.puts "push local #{index1}"
|
parsed_line=[""] if parsed_line==nil
|
||||||
|
if parsed_line[0]==:call
|
||||||
|
parsed_line[2].each do |arg|
|
||||||
|
push(arg)
|
||||||
|
end
|
||||||
|
nargs=$functable[parsed_line[1]][:args].length
|
||||||
|
$outfile.puts "call Main.#{parsed_line[1]} #{nargs}"
|
||||||
|
else
|
||||||
|
if line[1].include? "+"
|
||||||
|
operand=line[1].split("+")
|
||||||
|
op="add"
|
||||||
|
end
|
||||||
|
if line[1].include? "-"
|
||||||
|
operand=line[1].split("-")
|
||||||
|
op="sub"
|
||||||
|
end
|
||||||
|
push(operand[0])
|
||||||
|
push(operand[1])
|
||||||
|
$outfile.puts(op)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
pop(line[0])
|
||||||
|
when :call
|
||||||
|
line[1].each do |arg|
|
||||||
|
push(arg)
|
||||||
|
end
|
||||||
|
nargs=$functable[line[0]][:args].length
|
||||||
|
$outfile.puts "call Main.#{line[0]} #{nargs}"
|
||||||
|
when :return
|
||||||
|
push(line[0])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if info[:type]==:void
|
||||||
|
push(0)
|
||||||
end
|
end
|
||||||
$outfile.puts "return"
|
$outfile.puts "return"
|
||||||
$outfile.puts(" ")
|
$outfile.puts(" ")
|
||||||
@ -102,17 +187,36 @@ def write_init
|
|||||||
sysfile.puts("goto halt")
|
sysfile.puts("goto halt")
|
||||||
sysfile.puts(" ")
|
sysfile.puts(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
if !File.exists? "vmprog"
|
if !File.exists? "vmprog"
|
||||||
Dir.mkdir("vmprog")
|
Dir.mkdir("vmprog")
|
||||||
|
write_init()
|
||||||
end
|
end
|
||||||
|
|
||||||
Dir.chdir("vmprog")
|
Dir.chdir("vmprog")
|
||||||
|
|
||||||
$outfile=File.new("Main.vm","w")
|
$outfile=File.new("Main.vm","w")
|
||||||
write_init()
|
|
||||||
phase_one(tokenize_line("int main() {"))
|
prog=<<-END
|
||||||
phase_one(tokenize_line("int x"))
|
void main() {
|
||||||
phase_one(tokenize_line("x = 10"))
|
int x
|
||||||
phase_one(tokenize_line("int y"))
|
x = 10
|
||||||
phase_one(tokenize_line("y = 10"))
|
int y
|
||||||
phase_one(tokenize_line("}"))
|
y = x+17
|
||||||
|
int z
|
||||||
|
z = testfunc(y)
|
||||||
|
}
|
||||||
|
int testfunc(int c) {
|
||||||
|
int x
|
||||||
|
x = c-7
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
END
|
||||||
|
|
||||||
|
prog.each_line do |line|
|
||||||
|
phase_one(tokenize_line(line))
|
||||||
|
end
|
||||||
|
|
||||||
puts $functable
|
puts $functable
|
||||||
phase_two
|
|
||||||
|
phase_two()
|
||||||
|
@ -1,7 +1,21 @@
|
|||||||
function Main.main 2
|
function Main.main 3
|
||||||
push constant 10
|
push constant 10
|
||||||
pop local 0
|
pop local 0
|
||||||
push constant 10
|
push local 0
|
||||||
|
push constant 17
|
||||||
|
add
|
||||||
pop local 1
|
pop local 1
|
||||||
|
push local 1
|
||||||
|
call Main.testfunc 1
|
||||||
|
pop local 2
|
||||||
|
push constant 0
|
||||||
|
return
|
||||||
|
|
||||||
|
function Main.testfunc 1
|
||||||
|
push argument 0
|
||||||
|
push constant 7
|
||||||
|
sub
|
||||||
|
pop local 0
|
||||||
|
push local 0
|
||||||
return
|
return
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user