Compiler/AST interpreter: Difference between revisions

Line 2,135:
Total primes found: 26
</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}}==
Anonymous user