Compiler/AST interpreter: Difference between revisions
Content added Content deleted
Line 2,135: | Line 2,135: | ||
Total primes found: 26 |
Total primes found: 26 |
||
</pre> |
</pre> |
||
=={{header|Nim}}== |
|||
Using AST produced by the parser from the task “syntax analyzer”. |
|||
<lang Nim>import os, strutils, streams, tables |
|||
import ast_parser |
|||
type |
|||
ValueKind = enum valNil, valInt, valString |
|||
# Representation of a value. |
|||
Value = object |
|||
case kind: ValueKind |
|||
of valNil: nil |
|||
of valInt: intVal: int |
|||
of valString: stringVal: string |
|||
# Range of binary operators. |
|||
BinaryOperator = range[nMultiply..nOr] |
|||
# Table of variables. |
|||
var variables: Table[string, Value] |
|||
type RunTimeError = object of CatchableError |
|||
#--------------------------------------------------------------------------------------------------- |
|||
template newInt(val: typed): Value = |
|||
## Create an integer value. |
|||
Value(kind: valInt, intVal: val) |
|||
#--------------------------------------------------------------------------------------------------- |
|||
proc interp(node: Node): Value = |
|||
## Interpret code starting at "node". |
|||
if node.isNil: |
|||
return Value(kind: valNil) |
|||
case node.kind |
|||
of nInteger: |
|||
result = Value(kind: valInt, intVal: node.intVal) |
|||
of nIdentifier: |
|||
if node.name notin variables: |
|||
raise newException(RunTimeError, "Variable {node.name} is not initialized.") |
|||
result = variables[node.name] |
|||
of nString: |
|||
result = Value(kind: valString, stringVal: node.stringVal) |
|||
of nAssign: |
|||
variables[node.left.name] = interp(node.right) |
|||
of nNegate: |
|||
result = newInt(-interp(node.left).intVal) |
|||
of nNot: |
|||
result = newInt(not interp(node.left).intVal) |
|||
of BinaryOperator.low..BinaryOperator.high: |
|||
let left = interp(node.left) |
|||
let right = interp(node.right) |
|||
case BinaryOperator(node.kind) |
|||
of nMultiply: |
|||
result = newInt(left.intVal * right.intVal) |
|||
of nDivide: |
|||
result = newInt(left.intVal div right.intVal) |
|||
of nMod: |
|||
result = newInt(left.intVal mod right.intVal) |
|||
of nAdd: |
|||
result = newInt(left.intVal + right.intVal) |
|||
of nSubtract: |
|||
result = newInt(left.intVal - right.intVal) |
|||
of nLess: |
|||
result = newInt(ord(left.intVal < right.intVal)) |
|||
of nLessEqual: |
|||
result = newInt(ord(left.intVal <= right.intVal)) |
|||
of nGreater: |
|||
result = newInt(ord(left.intVal > right.intVal)) |
|||
of nGreaterEqual: |
|||
result = newInt(ord(left.intVal >= right.intVal)) |
|||
of nEqual: |
|||
result = newInt(ord(left.intVal == right.intVal)) |
|||
of nNotEqual: |
|||
result = newInt(ord(left.intVal != right.intVal)) |
|||
of nAnd: |
|||
result = newInt(left.intVal and right.intVal) |
|||
of nOr: |
|||
result = newInt(left.intVal or right.intVal) |
|||
of nIf: |
|||
if interp(node.left).intVal != 0: |
|||
discard interp(node.right.left) |
|||
else: |
|||
discard interp(node.right.right) |
|||
of nWhile: |
|||
while interp(node.left).intVal != 0: |
|||
discard interp(node.right) |
|||
of nPrtc: |
|||
stdout.write(chr(interp(node.left).intVal)) |
|||
of nPrti: |
|||
stdout.write(interp(node.left).intVal) |
|||
of nPrts: |
|||
stdout.write(interp(node.left).stringVal) |
|||
of nSequence: |
|||
discard interp(node.left) |
|||
discard interp(node.right) |
|||
#--------------------------------------------------------------------------------------------------- |
|||
proc loadAst(stream: Stream): Node = |
|||
## Load a linear AST and build a binary tree. |
|||
let line = stream.readLine().strip() |
|||
if line.startsWith(';'): |
|||
return nil |
|||
var fields = line.split(' ', 1) |
|||
let kind = parseEnum[NodeKind](fields[0]) |
|||
if kind in {nIdentifier, nString, nInteger}: |
|||
if fields.len < 2: |
|||
raise newException(ValueError, "Missing value field for " & fields[0]) |
|||
else: |
|||
fields[1] = fields[1].strip() |
|||
case kind |
|||
of nIdentifier: |
|||
return Node(kind: nIdentifier, name: fields[1]) |
|||
of nString: |
|||
return Node(kind: nString, stringVal: unescape(fields[1]).replace("\\n", "\n")) |
|||
of nInteger: |
|||
return Node(kind: nInteger, intVal: parseInt(fields[1])) |
|||
else: |
|||
if fields.len > 1: |
|||
raise newException(ValueError, "Extra field for " & fields[0]) |
|||
let left = stream.loadAst() |
|||
let right = stream.loadAst() |
|||
result = newNode(kind, left, right) |
|||
#——————————————————————————————————————————————————————————————————————————————————————————————————— |
|||
var stream: Stream |
|||
var toClose = false |
|||
if paramCount() < 1: |
|||
stream = newFileStream(stdin) |
|||
else: |
|||
stream = newFileStream(paramStr(1)) |
|||
toClose = true |
|||
let ast = loadAst(stream) |
|||
if toClose: stream.close() |
|||
discard ast.interp()</lang> |
|||
=={{header|Perl}}== |
=={{header|Perl}}== |