type IntStr* = object case kind*:bool: of true: s*: string of false: i*: int64 InsKind* = enum Set, Sub, Add, Label, Jump, UJump Ins* = object case kind*: InsKind: of Label: largs*: array[1, IntStr] of Add: aargs*: array[3, IntStr] of Sub: sargs*: array[3, IntStr] of Jump: jargs*: array[2, IntStr] of UJump: uargs*: array[1, IntStr] of Set: seargs*: array[2, IntStr] Code* = seq[Ins] ==================================== import IR, tables, parser, lexer type CompilationError = Exception IRCompiler = object code: Code tempvar: int #expression shit proc compileSub(comp: var IRCompiler, a: Ast): IntStr proc compileAdd(comp: var IRCompiler, a: Ast): IntStr proc compileValue(comp: var IRCompiler, a: Ast): IntStr proc compileInt(comp: var IRCompiler, a: Ast): IntStr proc compileChar(comp: var IRCompiler, a: Ast): IntStr proc compileIdent(comp: var IRCompiler, a: Ast): IntStr proc compileExpr(comp: var IRCompiler, a: Ast): IntStr #statement shit proc compileWhile(comp: var IRCompiler, a: Ast) proc compileAssign(comp: var IRCompiler, a: Ast) proc compileStatement(comp: var IRCompiler, a: Ast) proc IRcompile*(comp: var IRCompiler, a: Ast) #compile expression proc compileExpr(comp: var IRCompiler, a: Ast): IntStr = case a.kind: of NodeSub: return compileSub(comp, a) of NodeAdd: return compileAdd(comp, a) of NodeInt, NodeChar, NodeIdent: return compileValue(comp, a) else: raise newException(CompilationError, "WTF, dat no expr") #converts sub to IR proc compileSub(comp: var IRCompiler, a: Ast): IntStr = var a1 = compileExpr(comp, a.left) #do the first arg var a2 = compileExpr(comp, a.right) #do the second arg comp.code.add(Ins(kind: Sub, sargs: [IntStr(kind: true, s: $comp.tempvar), a1, a2])) #add the instruction result = IntStr(kind: true, s: $comp.tempvar) inc(comp.tempvar) #increse the comp.tempvar #convert add to IR proc compileAdd(comp: var IRCompiler, a: Ast): IntStr = var a1 = compileExpr(comp, a.left) #do the first arg var a2 = compileExpr(comp, a.right) #do the second arg comp.code.add(Ins(kind: Add, aargs: [IntStr(kind: true, s: $comp.tempvar), a1, a2])) #add the instruction result = IntStr(kind: true, s: $comp.tempvar) inc(comp.tempvar) #increse the comp.tempvar #decide which kind of value it is. proc compileValue(comp: var IRCompiler, a: Ast): IntStr = case a.kind: of NodeInt: return compileInt(comp, a) of NodeChar: return compileChar(comp, a) of NodeIdent: return compileIdent(comp, a) else: raise newException(CompilationError, "sonny, you sure you sane overthere?") #compile int value proc compileInt(comp: var IRCompiler, a: Ast): IntStr = comp.code.add(Ins(kind: Set, seargs: [IntStr(kind: true, s: $comp.tempvar), IntStr(kind: false, i: a.val)])) result = IntStr(kind: true, s: $comp.tempvar) inc(comp.tempvar) #compile char value proc compileChar(comp: var IRCompiler, a: Ast): IntStr = comp.code.add(Ins(kind: Set, seargs: [IntStr(kind: true, s: $comp.tempvar), IntStr(kind: false, i: int(a.cval))])) result = IntStr(kind: true, s: $comp.tempvar) inc(comp.tempvar) #compile ident value proc compileIdent(comp: var IRCompiler, a: Ast): IntStr = result = IntStr(kind: true, s: a.str) #[ when isMainModule: var x = lex("(- (+ (+ (a) ('a')) (10)) (10000))") var c: IRCompiler discard compileExpr(c, exprp(x)) for i in c.code: echo i ]# #compile a while loop proc compileWhile(comp: var IRCompiler, a: Ast) = var i = compileExpr(comp, a.right) comp.code.add(Ins(kind: UJump, uargs: [IntStr(kind: true, s: $comp.tempvar)])) var nj = $comp.tempvar inc(comp.tempvar) comp.code.add(Ins(kind: Label, largs: [IntStr(kind: true, s: $comp.tempvar)])) var toj = $comp.tempvar inc(comp.tempvar) IRcompile(comp, a.left) comp.code.add(Ins(kind: Label, largs: [IntStr(kind: true, s: nj)])) comp.code.add(Ins(kind: Jump, jargs: [IntStr(kind: true, s: toj), i])) #compile assign proc compileAssign(comp: var IRCompiler, a: Ast) = var i = compileExpr(comp, a.left) var j = compileExpr(comp, a.right) comp.code.add(Ins(kind: Set, seargs: [i, j])) #pick a statement kind bitch proc compileStatement(comp: var IRCompiler, a: Ast) = case a.kind: of NodeWhile: compileWhile(comp, a) of NodeAssign: compileAssign(comp, a) else: raise newException(CompilationError, "Not a ******* statement bitch") #yeah baby, whole prog proc IRcompile*(comp: var IRCompiler, a: Ast) = var n = a while n.left != nil: compileStatement(comp, n.left) n = n.right when isMainModule: var l = lex("var (a) = (10) while (a) { var (a) = (- (a) (1)) var (b) = (10) while (b) {var (b) = (- (b) (1))}}") var c = programp(l) var comp: IRcompiler IRcompile(comp, c) for i in comp.code: echo i +++++++++++++++++++++++++++++++++++++++++++++++++++++= import parser, tables, lexer type Env = object h: Table[string, int64] proc evalexpr(a: Ast, e: Env): int64 = case a.kind: of NodeChar: return int64(a.cval) of NodeInt: return a.val of NodeIdent: if e.h.hasKey(a.str): return e.h[a.str] else: newException(FuckUpError, "You ****** up, friend.") of NodeAdd: return evalexpr(a.left, e) + evalexpr(a.right, e) of NodeSub: return evalexpr(a.left, e) - evalexpr(a.right, e) else: raise newException(FuckUpError, "You ****** up, friend.") return proc evalprogram(a: Ast, e: var Env) = var x = a while x.left != nil: case x.left.kind: of NodeWhile: while evalexpr(x.left.right, e) > 0: evalprogram(x.left.left, e) of NodeAssign: e.h[x.left.left.str] = evalexpr(x.left.right, e) else: raise newException(FuckUpError, "Really buddy?") x = x.right var p = lex("var (a) = (0) var (b) = (1) while (1) { var (c) = (b) var (b) = (+ (b) (a)) var (a) = (c)} ") var a = programp(p) var e: Env evalprogram(a, e) __________________________+++++++++++++++++++++++==== program = statement* "EOF" statement = assign | while while = "while" expr "{" statement+ "}" assign = "var" ident "=" expr expr = arith | ident | value value = int | char arith = add | sub add = "(" "+" expr expr ")" sub = "(" "-" expr expr ")" ident = "(" alpha+ ")" int = "(" "-"? digit+ ")" char = "(" 'alpha' ")" alpha = 'A'..'z' digit = '0'..'9' _________________________________________________________________________________________________________________ import re, strutils type TokenTypes* = enum TokenChar, TokenVar, TokenIdent, TokenInt, TokenLParen, TokenRParen, TokenAdd, TokenSub, TokenEquals, TokenLBracket, TokenRBracket, TokenWhile Token* = object case kind*:TokenTypes: of TokenIdent: str*: string of TokenInt: i*: int64 of TokenChar: c*: uint8 else:discard Parser* = object code*: seq[Token] current*: int proc makeParser(s: seq[string]): Parser proc lex*(str: string): Parser = var temp: seq[string] for i in (str.replace("{", " { ").replace("(", " ( ").replace(")", " ) ").replace("}", " } ").replace("=", " = ").replace("+", " + ").replace("-", " - ")).split(" "): if i != "\n" and i != " " and i != "" and i != "\t": temp.add(i) return makeParser(temp) proc makeParser(s: seq[string]): Parser = for i in s: if i.match(re(r"(-?)[0-9]+")): result.code.add(Token(kind: TokenInt, i: parseInt(i))) continue if i[0] == '\'' and i[2] == '\'' and i.len() == 3: result.code.add(Token(kind: TokenChar, c: uint8(i[1]))) continue case i: of "var": result.code.add(Token(kind: TokenVar)) of "+": result.code.add(Token(kind: TokenAdd)) of "-": result.code.add(Token(kind: TokenSub)) of "=": result.code.add(Token(kind: TokenEquals)) of "while": result.code.add(Token(kind: TokenWhile)) of "{": result.code.add(Token(kind: TokenLBracket)) of "(": result.code.add(Token(kind: TokenLParen)) of ")": result.code.add(Token(kind: TokenRParen)) of "}": result.code.add(Token(kind: TokenRBracket)) else: if i.match(re"[A-z]+"): result.code.add(Token(kind: TokenIdent, str: i)) else: raise newException(Exception, "****** up with the vars, did we now?") proc getTok*(p: var Parser, x: int = 0): Token = return p.code[p.current + x] proc advanceTok*(p: var Parser, x: int = 1) = p.current += x ---------------------------------------------------------------------------------------------- import lexer type FuckUpError* = Exception SyntaxError* = Exception NodeKind* = enum NodeProgram, NodeWhile, NodeIdent, NodeInt, NodeChar, NodeAdd, NodeSub, NodeAssign Ast* = ref object case kind*:NodeKind: of NodeInt: val*: int64 of NodeIdent: str*: string of NodeChar: cval*: uint8 else:discard left*: Ast right*: Ast #for arith, left before right #for assign, left is the ident, right is the expr #for while, left is the code, right is the expr #for prog, left is the statement, right is the rest of them. #Forward decs #statement functions proc programp*(p: var Parser): Ast proc statementp(p: var Parser): Ast proc assignp(p: var Parser): Ast proc whilep(p: var Parser): Ast # expression parsing functions proc exprp(p: var Parser): Ast proc arithp(p: var Parser): Ast proc identp(p: var Parser): Ast proc intp(p: var Parser): Ast proc charp(p: var Parser): Ast proc addp(p: var Parser): Ast proc subp(p: var Parser): Ast proc printprog(a: Ast, x: bool = false) #Implementations proc programp*(p: var Parser): Ast = if p.current >= p.code.len(): raise newException(SyntaxError, "You sure you are calling programp right, sonny?") var n = Ast(kind: NodeProgram) result = n #collects all the statements in the program while p.current < p.code.len(): n.left = statementp(p) new(n.right) n = n.right #printexpr() #echo "" #printexpr(result) #echo "" proc statementp(p: var Parser): Ast = #find out what sort of statement it is case p.getTok().kind: of TokenVar: result = assignp(p) of TokenWhile: result = whilep(p) else: echo p.getTok() raise newException(SyntaxError, "You sure you are trying to get a statement, sonny?") proc assignp(p: var Parser): Ast = #move past tokenVar advanceTok(p) doAssert getTok(p).kind == TokenLParen #initialize result result = Ast(kind: NodeAssign) #get the identifier result.left = exprp(p) #move past tokenEquals doAssert getTok(p).kind == TokenEquals advanceTok(p) doAssert getTok(p).kind == TokenLParen #get the expression result.right = exprp(p) proc whilep(p: var Parser): Ast = #move past tokenWhile advanceTok(p) doAssert getTok(p).kind == TokenLParen #initialize result var n = Ast(kind: NodeWhile) #obtain the expression n.right = exprp(p) #move past TokenLBracket doAssert getTok(p).kind == TokenLBracket advanceTok(p) #obtain the body statements result = n new(n.left) n = n.left while getTok(p).kind != TokenRBracket: #printexpr(result) #echo "" n.left = statementp(p) new(n.right) n = n.right #printexpr(result) #echo "" #move past TokenRBracket doAssert getTok(p).kind == TokenRBracket advanceTok(p) proc exprp(p: var Parser): Ast = #pick a kind of expression if getTok(p).kind != TokenLParen: raise newException(SyntaxError, "You sure you passed an expression, sonny?") case getTok(p, 1).kind: of TokenAdd, TokenSub: return arithp(p) of TokenIdent: return identp(p) of TokenInt: return intp(p) of TokenChar: return charp(p) else: echo getTok(p, 1) raise newException(SyntaxError, "You sure you passed an expression, sonny?") proc arithp(p: var Parser): Ast = case getTok(p, 1).kind: of TokenSub: return subp(p) of TokenAdd: return addp(p) else: echo getTok(p, 1) raise newException(SyntaxError, "That is ******* weird. How did that happen?") proc addp(p: var Parser): Ast = #get past lparen advanceTok(p) #get past tokenAdd advanceTok(p) #do the bulk of it result = Ast(kind: NodeAdd) result.left = exprp(p) doAssert getTok(p).kind == TokenLParen result.right = exprp(p) #get past rparen doAssert getTok(p).kind == TokenRParen advanceTok(p) #the left is always the first to be parsed & evaled proc subp(p: var Parser): Ast = #get past lparen advanceTok(p) #get past tokenSub advanceTok(p) #do the bulk of it result = Ast(kind: NodeSub) result.left = exprp(p) doAssert getTok(p).kind == TokenLParen result.right = exprp(p) #get past rparen doAssert getTok(p).kind == TokenRParen advanceTok(p) #the left is always the first to be parsed & evaled proc identp(p: var Parser): Ast = #get past lparen doAssert p.getTok().kind == TokenLParen advanceTok(p) result = Ast(kind: NodeIdent, str: getTok(p).str) #advance past ident advanceTok(p) #advance past TokenRParen doAssert getTok(p).kind == TokenRParen advanceTok(p) proc intp(p: var Parser): Ast = #get past lparen doAssert p.getTok().kind == TokenLParen advanceTok(p) result = Ast(kind: NodeInt, val: getTok(p).i) #advance past uint advanceTok(p) #advance past TokenRParen doAssert getTok(p).kind == TokenRParen advanceTok(p) proc charp(p: var Parser): Ast = #get past lparen doAssert p.getTok().kind == TokenLParen advanceTok(p) result = Ast(kind: NodeChar, cval: getTok(p).c) #advance past char advanceTok(p) #advance past TokenRParen doAssert getTok(p).kind == TokenRParen advanceTok(p) #Prints out the expr Ast passed to it proc printprog(a: Ast, x: bool = false) = if a.left != nil and a.right != nil: if x: echo "program" case a.kind: of NodeProgram: printprog(a.left) printprog(a.right) of NodeWhile: stdout.write "while " printprog(a.right) stdout.write " { " printprog(a.left) stdout.write " } " of NodeAdd: stdout.write " ( " stdout.write " + " printprog(a.left) printprog(a.right) stdout.write " ) " of NodeSub: stdout.write " ( " stdout.write " - " printprog(a.left) printprog(a.right) stdout.write " ) " of NodeAssign: stdout.write " ( " stdout.write " = " printprog(a.left) printprog(a.right) stdout.write " ) " else:discard case a.kind: of NodeIdent: stdout.write " " & a.str & " " of NodeInt: stdout.write " " & $a.val & " " of NodeChar: stdout.write " " & char(a.cval) & " " else:discard when isMainModule: var l = lex(""" var (n) = (+ (b) (+ (a) (10))) while (a) { var (b) = (10) } var (x) = (+ (10) (10)) while (x) { var (x) = (- (x) (1)) } while (x) { var (n) = ('a') } while (n) { var (x) = (+ (n) (10)) } """) printprog(programp(l), true) echo ""