Compiler/code generator: Difference between revisions

Line 2,516:
GENERATE EMIT BYE</lang>
Passes all tests.
 
 
=={{header|Julia}}==
<lang julia>import Base.show
 
mutable struct Asm32
offset::Int32
code::String
arg::Int32
targ::Int32
end
Asm32(code, arg = 0) = Asm32(0, code, arg, 0)
 
show(io::IO, a::Asm32) = print(io, lpad("$(a.offset)", 6), lpad(a.code, 8),
a.targ > 0 ? (lpad("($(a.arg))", 8) * lpad("$(a.targ)", 4)) :
(a.code in ["store", "fetch"] ? lpad("[$(a.arg)]", 8) :
(a.code in ["push"] ? lpad("$(a.arg)", 8) : "")))
 
const ops32 = Dict{String,String}("Multiply" => "mul", "Divide" => "div", "Mod" => "mod", "Add" => "add",
"Subtract" => "sub", "Less" => "lt", "Greater" => "gt", "LessEqual" => "le", "GreaterEqual" => "ge",
"Equal" => "eq", "NotEqual" => "ne", "And" => "and", "or" => "or", "Not" => "not", "Minus" => "neg",
"Prtc" => "prtc", "Prti" => "prti", "Prts" => "prts")
 
function compiletoasm(io)
identifiers = Vector{String}()
strings = Vector{String}()
labels = Vector{Int}()
 
function cpile(io, islefthandside = false)
arr = Vector{Asm32}()
jlabel() = (push!(labels, length(labels) + 1); labels[end])
m = match(r"^(\w+|;)\s*([\d\w\"\\ \S]+)?", strip(readline(io)))
x, val = m == nothing ? Pair(";", 0) : m.captures
if x == ";" return arr
elseif x == "Assign"
lhs = cpile(io, true)
rhs = cpile(io)
append!(arr, rhs)
append!(arr, lhs)
if length(arr) > 100 exit() end
elseif x == "Integer" push!(arr, Asm32("push", parse(Int32, val)))
elseif x == "String"
if !(val in strings)
push!(strings, val)
end
push!(arr, Asm32("push", findfirst(x -> x == val, strings) - 1))
elseif x == "Identifier"
if !(val in identifiers)
if !islefthandside
throw("Identifier $val referenced before it is assigned")
end
push!(identifiers, val)
end
push!(arr, Asm32(islefthandside ? "store" : "fetch", findfirst(x -> x == val, identifiers) - 1))
elseif haskey(ops32, x)
append!(arr, cpile(io))
append!(arr, cpile(io))
push!(arr, Asm32(ops32[x]))
elseif x == "If"
append!(arr, cpile(io))
x, y = jlabel(), jlabel()
push!(arr, Asm32("jz", x))
append!(arr, cpile(io))
push!(arr, Asm32("jmp", y))
a = cpile(io)
if length(a) < 1
push!(a, Asm32("nop", 0))
end
a[1].offset = x
append!(arr, a)
push!(arr, Asm32(y, "nop", 0, 0)) # placeholder
elseif x == "While"
x, y = jlabel(), jlabel()
a = cpile(io)
if length(a) < 1
push!(a, Asm32("nop", 0))
end
a[1].offset = x
append!(arr, a)
push!(arr, Asm32("jz", y))
append!(arr, cpile(io))
push!(arr, Asm32("jmp", x), Asm32(y, "nop", 0, 0))
elseif x == "Sequence"
append!(arr, cpile(io))
append!(arr, cpile(io))
else
throw("unknown node type: $x")
end
arr
end
 
# compile AST
asmarr = cpile(io)
push!(asmarr, Asm32("halt"))
# move address markers to working code and prune nop code
for (i, acode) in enumerate(asmarr)
if acode.code == "nop" && acode.offset != 0 && i < length(asmarr)
asmarr[i + 1].offset = asmarr[i].offset
end
end
filter!(x -> x.code != "nop", asmarr)
# renumber offset column with acual offsets
pos = 0
jmps = Dict{Int, Int}()
for acode in asmarr
if acode.offset > 0
jmps[acode.offset] = pos
end
acode.offset = pos
pos += acode.code in ["push", "store", "fetch", "jz", "jmp"] ? 5 : 1
end
# fixup jump destinations
for acode in asmarr
if acode.code in ["jz", "jmp"]
if haskey(jmps, acode.arg)
acode.targ = jmps[acode.arg]
acode.arg = acode.targ - acode.offset -1
else
throw("unknown jump location: $acode")
end
end
end
# print Datasize and Strings header
println("Datasize: $(length(identifiers)) Strings: $(length(strings))\n" *
join(strings, "\n") )
# print assembly lines
foreach(println, asmarr)
end
 
const testAST = raw"""
Sequence
Sequence
;
Assign
Identifier count
Integer 1
While
Less
Identifier count
Integer 10
Sequence
Sequence
;
Sequence
Sequence
Sequence
;
Prts
String "count is: "
;
Prti
Identifier count
;
Prts
String "\n"
;
Assign
Identifier count
Add
Identifier count
Integer 1 """
 
iob = IOBuffer(testAST) # use an io buffer here for testing, but could use stdin instead of iob
 
compiletoasm(iob)
</lang>{{output}}<pre>
Datasize: 1 Strings: 2
"count is: "
"\n"
0 push 1
5 store [0]
10 fetch [0]
15 push 10
20 lt
21 jz (43) 65
26 push 0
31 prts
32 fetch [0]
37 prti
38 push 1
43 prts
44 fetch [0]
49 push 1
54 add
55 store [0]
60 jmp (-51) 10
65 halt
</pre>
 
=={{header|Perl}}==
4,104

edits