interpreter.nim
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
import streams, strutils, tables import parser type TMinInterpreter* = object stack: TMinStack parser*: TMinParser currSym: TMinValue filename: string TMinOperator* = proc (i: var TMinInterpreter) TMinError* = enum errParser, errGeneric, errEmptyStack, errNoQuotation, errUndefined const ERRORS: array [TMinError, string] = [ "A parsing error occurred", "A generic error occurred", "The stack is empty", "Quotation not found on the stack", "Symbol undefined" ] var SYMBOLS* = initTable[string, TMinOperator]() var TYPES* = initTable[string, TMinKind]() TYPES["int"] = minInt TYPES["float"] = minFloat TYPES["string"] = minString TYPES["symbol"] = minSymbol TYPES["quotation"] = minQuotation proc newMinInterpreter*(): TMinInterpreter = var s:TMinStack = newSeq[TMinValue](0) var p:TMinParser var i:TMinInterpreter = TMinInterpreter(filename: "input", parser: p, stack: s, currSym: TMinValue(first: 0, last: 0, line: 0, kind: minSymbol, symVal: "")) return i proc error*(i: TMinInterpreter, status: TMinError, message = "") = var msg = if message == "": ERRORS[status] else: message stderr.writeln("$1[$2,$3] `$4`: Error - $5" %[i.filename, $i.currSym.line, $i.currSym.last, i.currSym.symVal, msg]) quit(int(status)) proc open*(i: var TMinInterpreter, stream:PStream, filename: string) = i.parser.open(stream, filename) proc close*(i: var TMinInterpreter) = i.parser.close(); proc push*(i: var TMinInterpreter, val: TMinValue) = i.stack.add(val) proc pop*(i: var TMinInterpreter): TMinValue = if i.stack.len > 0: return i.stack.pop else: i.error(errEmptyStack) proc peek*(i: TMinInterpreter): TMinValue = if i.stack.len > 0: return i.stack[i.stack.len-1] else: i.error(errEmptyStack) proc interpret*(i: var TMinInterpreter) = var val: TMinValue while i.parser.token != tkEof: try: val = i.parser.parseMinValue except: i.error errParser, getCurrentExceptionMsg() if val.kind == minSymbol: i.currSym = val if SYMBOLS.hasKey val.symVal: SYMBOLS[val.symVal](i) else: i.error(errUndefined, "Undefined symbol: '"&val.symVal&"'") else: i.push val |