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}}==