RosettaCodeData/Task/Compiler-AST-interpreter/Julia/compiler-ast-interpreter.jl
2024-10-16 18:07:41 -07:00

167 lines
3.7 KiB
Julia

struct Anode
node_type::String
left::Union{Nothing, Anode}
right::Union{Nothing, Anode}
value::Union{Nothing, String}
end
make_leaf(t, v) = Anode(t, nothing, nothing, v)
make_node(t, l, r) = Anode(t, l, r, nothing)
const OP2 = Dict("Multiply" => "*", "Divide" => "/", "Mod" => "%", "Add" => "+", "Subtract" => "-",
"Less" => "<", "Greater" => ">", "LessEqual" => "<=", "GreaterEqual" => ">=",
"Equal" => "==", "NotEqual" => "!=", "And" => "&&", "Or" => "||")
const OP1 = Dict("Not" => "!", "Minus" => "-")
tobool(i::Bool) = i
tobool(i::Int) = (i != 0)
tobool(s::String) = eval(Symbol(s)) != 0
const stac = Vector{Any}()
function call2(op, x, y)
if op in ["And", "Or"]
x, y = tobool(x), tobool(y)
end
eval(Meta.parse("push!(stac, $(x) $(OP2[op]) $(y))"))
return Int(floor(pop!(stac)))
end
call1(op, x) = (if op in ["Not"] x = tobool(x) end; eval(Meta.parse("$(OP1[op]) $(x)")))
evalpn(op, x, y = nothing) = (haskey(OP2, op) ? call2(op, x, y) : call1(op, x))
function load_ast(io)
line = strip(readline(io))
line_list = filter(x -> x != nothing, match(r"(?:(\w+)\s+(\d+|\w+|\".*\")|(\w+|;))", line).captures)
text = line_list[1]
if text == ";"
return nothing
end
node_type = text
if length(line_list) > 1
return make_leaf(line_list[1], line_list[2])
end
left = load_ast(io)
right = load_ast(io)
return make_node(line_list[1], left, right)
end
function interp(x)
if x == nothing return nothing
elseif x.node_type == "Integer" return parse(Int, x.value)
elseif x.node_type == "Identifier" return "_" * x.value
elseif x.node_type == "String" return replace(replace(x.value, "\"" => ""), "\\n" => "\n")
elseif x.node_type == "Assign" s = "$(interp(x.left)) = $(interp(x.right))"; eval(Meta.parse(s)); return nothing
elseif x.node_type in keys(OP2) return evalpn(x.node_type, interp(x.left), interp(x.right))
elseif x.node_type in keys(OP1) return evalpn(x.node_type, interp(x.left))
elseif x.node_type == "If" tobool(eval(interp(x.left))) ? interp(x.right.left) : interp(x.right.right); return nothing
elseif x.node_type == "While" while tobool(eval(interp(x.left))) interp(x.right) end; return nothing
elseif x.node_type == "Prtc" print(Char(eval(interp(x.left)))); return nothing
elseif x.node_type == "Prti" s = interp(x.left); print((i = tryparse(Int, s)) == nothing ? eval(Symbol(s)) : i); return nothing
elseif x.node_type == "Prts" print(eval(interp(x.left))); return nothing
elseif x.node_type == "Sequence" interp(x.left); interp(x.right); return nothing
else
throw("unknown node type: $x")
end
end
const testparsed = """
Sequence
Sequence
Sequence
Sequence
Sequence
;
Assign
Identifier count
Integer 1
Assign
Identifier n
Integer 1
Assign
Identifier limit
Integer 100
While
Less
Identifier n
Identifier limit
Sequence
Sequence
Sequence
Sequence
Sequence
;
Assign
Identifier k
Integer 3
Assign
Identifier p
Integer 1
Assign
Identifier n
Add
Identifier n
Integer 2
While
And
LessEqual
Multiply
Identifier k
Identifier k
Identifier n
Identifier p
Sequence
Sequence
;
Assign
Identifier p
NotEqual
Multiply
Divide
Identifier n
Identifier k
Identifier k
Identifier n
Assign
Identifier k
Add
Identifier k
Integer 2
If
Identifier p
If
Sequence
Sequence
;
Sequence
Sequence
;
Prti
Identifier n
;
Prts
String \" is prime\\n\"
;
Assign
Identifier count
Add
Identifier count
Integer 1
;
Sequence
Sequence
Sequence
;
Prts
String \"Total primes found: \"
;
Prti
Identifier count
;
Prts
String \"\\n\"
; """
const lio = IOBuffer(testparsed)
interp(load_ast(lio))