Compiler/AST interpreter: Difference between revisions
Content added Content deleted
(Corrected a bug with "\\n" and "\n" due to wrong behavior of "unescape". Used regular expression and replacements instead.) |
(Added Wren) |
||
Line 2,964: | Line 2,964: | ||
Output for primes program from above. Also tested on programs in [[Compiler/Sample programs]]. |
Output for primes program from above. Also tested on programs in [[Compiler/Sample programs]]. |
||
<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|Wren}}== |
|||
{{trans|Go}} |
|||
{{libheader|Wren-dynamic}} |
|||
{{libheader|Wren-fmt}} |
|||
{{libheader|Wren-ioutil}} |
|||
<lang ecmascript>import "/dynamic" for Enum, Struct, Tuple |
|||
import "/fmt" for Conv |
|||
import "/ioutil" for FileUtil |
|||
var nodes = [ |
|||
"Ident", |
|||
"String", |
|||
"Integer", |
|||
"Sequence", |
|||
"If", |
|||
"Prtc", |
|||
"Prts", |
|||
"Prti", |
|||
"While", |
|||
"Assign", |
|||
"Negate", |
|||
"Not", |
|||
"Mul", |
|||
"Div", |
|||
"Mod", |
|||
"Add", |
|||
"Sub", |
|||
"Lss", |
|||
"Leq", |
|||
"Gtr", |
|||
"Geq", |
|||
"Eql", |
|||
"Neq", |
|||
"And", |
|||
"Or" |
|||
] |
|||
var Node = Enum.create("Node", nodes) |
|||
var Tree = Struct.create("Tree", ["nodeType", "left", "right", "value"]) |
|||
// depeNodency: Ordered by Node value, must remain in same order as Node enum |
|||
var Atr = Tuple.create("Atr", ["enumText", "nodeType"]) |
|||
var atrs = [ |
|||
Atr.new("Identifier", Node.Ident), |
|||
Atr.new("String", Node.String), |
|||
Atr.new("Integer", Node.Integer), |
|||
Atr.new("Sequence", Node.Sequence), |
|||
Atr.new("If", Node.If), |
|||
Atr.new("Prtc", Node.Prtc), |
|||
Atr.new("Prts", Node.Prts), |
|||
Atr.new("Prti", Node.Prti), |
|||
Atr.new("While", Node.While), |
|||
Atr.new("Assign", Node.Assign), |
|||
Atr.new("Negate", Node.Negate), |
|||
Atr.new("Not", Node.Not), |
|||
Atr.new("Multiply", Node.Mul), |
|||
Atr.new("Divide", Node.Div), |
|||
Atr.new("Mod", Node.Mod), |
|||
Atr.new("Add", Node.Add), |
|||
Atr.new("Subtract", Node.Sub), |
|||
Atr.new("Less", Node.Lss), |
|||
Atr.new("LessEqual", Node.Leq), |
|||
Atr.new("Greater", Node.Gtr), |
|||
Atr.new("GreaterEqual", Node.Geq), |
|||
Atr.new("Equal", Node.Eql), |
|||
Atr.new("NotEqual", Node.Neq), |
|||
Atr.new("And", Node.And), |
|||
Atr.new("Or", Node.Or), |
|||
] |
|||
var stringPool = [] |
|||
var globalNames = [] |
|||
var globalValues = {} |
|||
var reportError = Fn.new { |msg| Fiber.abort("error : %(msg)") } |
|||
var makeNode = Fn.new { |nodeType, left, right| Tree.new(nodeType, left, right, 0) } |
|||
var makeLeaf = Fn.new { |nodeType, value| Tree.new(nodeType, null, null, value) } |
|||
// interpret the parse tree |
|||
var interp // recursive function |
|||
interp = Fn.new { |x| |
|||
if (!x) return 0 |
|||
var nt = x.nodeType |
|||
if (nt == Node.Integer) return x.value |
|||
if (nt == Node.Ident) return globalValues[x.value] |
|||
if (nt == Node.String) return x.value |
|||
if (nt == Node.Assign) { |
|||
var n = interp.call(x.right) |
|||
globalValues[x.left.value] = n |
|||
return n |
|||
} |
|||
if (nt == Node.Add) return interp.call(x.left) + interp.call(x.right) |
|||
if (nt == Node.Sub) return interp.call(x.left) - interp.call(x.right) |
|||
if (nt == Node.Mul) return interp.call(x.left) * interp.call(x.right) |
|||
if (nt == Node.Div) return (interp.call(x.left) / interp.call(x.right)).truncate |
|||
if (nt == Node.Mod) return interp.call(x.left) % interp.call(x.right) |
|||
if (nt == Node.Lss) return Conv.btoi(interp.call(x.left) < interp.call(x.right)) |
|||
if (nt == Node.Gtr) return Conv.btoi(interp.call(x.left) > interp.call(x.right)) |
|||
if (nt == Node.Leq) return Conv.btoi(interp.call(x.left) <= interp.call(x.right)) |
|||
if (nt == Node.Eql) return Conv.btoi(interp.call(x.left) == interp.call(x.right)) |
|||
if (nt == Node.Neq) return Conv.btoi(interp.call(x.left) != interp.call(x.right)) |
|||
if (nt == Node.And) return Conv.btoi(Conv.itob(interp.call(x.left)) && Conv.itob(interp.call(x.right))) |
|||
if (nt == Node.Or) return Conv.btoi(Conv.itob(interp.call(x.left)) || Conv.itob(interp.call(x.right))) |
|||
if (nt == Node.Negate) return -interp.call(x.left) |
|||
if (nt == Node.Not) return (interp.call(x.left) == 0) ? 1 : 0 |
|||
if (nt == Node.If) { |
|||
if (interp.call(x.left) != 0) { |
|||
interp.call(x.right.left) |
|||
} else { |
|||
interp.call(x.right.right) |
|||
} |
|||
return 0 |
|||
} |
|||
if (nt == Node.While) { |
|||
while (interp.call(x.left) != 0) interp.call(x.right) |
|||
return 0 |
|||
} |
|||
if (nt == Node.Prtc) { |
|||
System.write(String.fromByte(interp.call(x.left))) |
|||
return 0 |
|||
} |
|||
if (nt == Node.Prti) { |
|||
System.write(interp.call(x.left)) |
|||
return 0 |
|||
} |
|||
if (nt == Node.Prts) { |
|||
System.write(stringPool[interp.call(x.left)]) |
|||
return 0 |
|||
} |
|||
if (nt == Node.Sequence) { |
|||
interp.call(x.left) |
|||
interp.call(x.right) |
|||
return 0 |
|||
} |
|||
reportError.call("interp: unknown tree type %(x.nodeType)") |
|||
} |
|||
var getEnumValue = Fn.new { |name| |
|||
for (atr in atrs) { |
|||
if (atr.enumText == name) return atr.nodeType |
|||
} |
|||
reportError.call("Unknown token %(name)") |
|||
} |
|||
var fetchStringOffset = Fn.new { |s| |
|||
var d = "" |
|||
s = s[1...-1] |
|||
var i = 0 |
|||
while (i < s.count) { |
|||
if (s[i] == "\\" && (i+1) < s.count) { |
|||
if (s[i+1] == "n") { |
|||
d = d + "\n" |
|||
i = i + 1 |
|||
} else if (s[i+1] == "\\") { |
|||
d = d + "\\" |
|||
i = i + 1 |
|||
} |
|||
} else { |
|||
d = d + s[i] |
|||
} |
|||
i = i + 1 |
|||
} |
|||
s = d |
|||
for (i in 0...stringPool.count) { |
|||
if (s == stringPool[i]) return i |
|||
} |
|||
stringPool.add(s) |
|||
return stringPool.count - 1 |
|||
} |
|||
var fetchVarOffset = Fn.new { |name| |
|||
for (i in 0...globalNames.count) { |
|||
if (globalNames[i] == name) return i |
|||
} |
|||
globalNames.add(name) |
|||
return globalNames.count - 1 |
|||
} |
|||
var lines = [] |
|||
var lineCount = 0 |
|||
var lineNum = 0 |
|||
var loadAst // recursive function |
|||
loadAst = Fn.new { |
|||
var nodeType = 0 |
|||
var s = "" |
|||
if (lineNum < lineCount) { |
|||
var line = lines[lineNum].trimEnd(" \t") |
|||
lineNum = lineNum + 1 |
|||
var tokens = line.split(" ").where { |s| s != "" }.toList |
|||
var first = tokens[0] |
|||
if (first[0] == ";") return null |
|||
nodeType = getEnumValue.call(first) |
|||
var le = tokens.count |
|||
if (le == 2) { |
|||
s = tokens[1] |
|||
} else if (le > 2) { |
|||
var idx = line.indexOf("\"") |
|||
s = line[idx..-1] |
|||
} |
|||
} |
|||
if (s != "") { |
|||
var n |
|||
if (nodeType == Node.Ident) { |
|||
n = fetchVarOffset.call(s) |
|||
} else if (nodeType == Node.Integer) { |
|||
n = Num.fromString(s) |
|||
} else if (nodeType == Node.String) { |
|||
n = fetchStringOffset.call(s) |
|||
} else { |
|||
reportError.call("Unknown node type: %(s)") |
|||
} |
|||
return makeLeaf.call(nodeType, n) |
|||
} |
|||
var left = loadAst.call() |
|||
var right = loadAst.call() |
|||
return makeNode.call(nodeType, left, right) |
|||
} |
|||
lines = FileUtil.readLines("ast.txt") |
|||
lineCount = lines.count |
|||
var x = loadAst.call() |
|||
interp.call(x)</lang> |
|||
{{out}} |
|||
<pre> |
<pre> |
||
3 is prime |
3 is prime |