Compiler/AST interpreter: Difference between revisions

(Undo revision 275911 by Wherrera (talk))
Line 1,366:
</lang>
Passes all tests.
 
=={{header|Julia}}==
<lang 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))
</lang>{{output}}<pre>
3 is prime
5 is prime
7 is prime
11 is prime
13 is prime
17 is prime
19 is prime
23 is prime
29 is prime
31 is prime
37 is prime
41 is prime
43 is prime
47 is prime
53 is prime
59 is prime
61 is prime
67 is prime
71 is prime
73 is prime
79 is prime
83 is prime
89 is prime
97 is prime
101 is prime
Total primes found: 26
</pre>
 
 
=={{header|Perl}}==
4,102

edits