UNPKG

jaycc

Version:

### the Javascript C Compiler

256 lines (200 loc) 6.14 kB
/* parser.tsplus */ import { closecurly, closeround, eof, eq, keyword, numberconst, opencurly, openround, semicolon, type Keyword, type Numberconst, type Token } from './lexer.js'; import { identifier as tokenid } from './lexer.js'; import { identifier as astid, Program } from './ast.js'; import { REX } from './rex.js'; import { ASTfunction, Codeblock, datatype, Etype, numberconstant, Returnstm, SyntaxException, type AST, type Datatype, type Expr, type Identifier, type Numberconstant, type Stm } from './ast.js'; interface Iparser { constructor:Function; curtokens:Token[]; savedtokens:Token[]; fail:(msg:string)=>never; parse:()=>AST; expression:()=>AST; returnstm:()=>AST; statement:()=>AST; codeblock:()=>AST; datatype:()=>AST; fun:()=>AST; program:()=>AST; } class Parser implements Iparser { public curtokens:Token[]; public savedtokens:Token[]; constructor(ts:Token[]) { this.curtokens = this.savedtokens = ts; } public fail(msg:string = 'Parse error'): never { this.curtokens = this.savedtokens; throw new SyntaxException(msg); return void 0 as never; } public expression(): AST { let numconst:Numberconst; let node:Numberconstant; let t:Token; t = this.curtokens.shift() || this.fail(); if (eq(t, numberconst())) numconst = t.contents as Numberconst; else return this.fail(); node = numberconstant(numconst); this.savedtokens = this.curtokens; return node; } public returnstm(): AST { let kw:Keyword; let e:Expr; let node:Returnstm; let t:Token; t = this.curtokens.shift() || this.fail(); if ((eq(t, keyword()) && (t.contents === 'return'))) kw = t.contents; else return this.fail(); e = this.expression(); node = new Returnstm(e); this.savedtokens = this.curtokens; return node; } public statement(): AST { let r:Returnstm; let node:Stm; let t:Token; r = this.returnstm(); t = this.curtokens.shift() || this.fail(); if (eq(t, semicolon())) node = r; else return this.fail(); this.savedtokens = this.curtokens; return node; } public codeblock(): AST { let t:Token; let ts:Token[]; let ss:Stm[]; let s:Stm; let node:Codeblock; let parses:number; let err:boolean; let fatal:boolean; parses = 0; err = false; fatal = false; ss = []; t = this.curtokens.shift() || this.fail(); if (!eq(t, opencurly())) this.fail(); ts = new Array(...this.curtokens); while (!err) { try { ts = new Array(...this.curtokens); s = this.statement(); ss.push(s); parses++; this.savedtokens = this.curtokens; } catch { err = true; this.curtokens = ts; } if (fatal) this.fail(); } if (!parses) return this.fail(); t = this.curtokens.shift() || this.fail(); if (!eq(t, closecurly())) this.fail(); node = new Codeblock(ss); return node; } public datatype(): AST { let node:Datatype; let t:Token; let kw:Keyword; let et:Etype; t = this.curtokens.shift() || this.fail(); if (((eq(t, keyword())) && t.contents === 'int')) kw = t.contents; else this.fail(); et = Etype.Int; node = datatype(et); this.savedtokens = this.curtokens; return node; } public fun(): AST { let d:Datatype; let i:Identifier; let c:Codeblock; let node:ASTfunction; let t:Token; d = this.datatype(); t = this.curtokens.shift() || this.fail(); if (eq(t, tokenid())) i = astid(t.contents as string) else return this.fail(); t = this.curtokens.shift() || this.fail(); if (!eq(t, openround())) return this.fail(); t = this.curtokens.shift() || this.fail(); if (!eq(t, closeround())) return this.fail(); this.savedtokens = this.curtokens; c = this.codeblock(); this.savedtokens = this.curtokens; node = new ASTfunction(d, i, c); return node; } public program(): AST { let f:ASTfunction; let fs:ASTfunction[]; let p:Program; let parsed:number; let err:boolean; let t:Token; let ts:Token[]; err = false; parsed = 0; fs = []; ts = new Array(...this.curtokens); while (!err) { try { ts = new Array(...this.curtokens); f = this.fun(); this.savedtokens = this.curtokens; fs.push(f); parsed++; } catch { err = true; this.curtokens = ts; } } if (!parsed) this.fail(); t = this.curtokens.shift() || this.fail(); if ((!eq(t, eof())) || (this.curtokens.length)) this.fail(); p = new Program(fs); return p; } public parse(): AST { let a:AST; a = this.program(); return a; } } export { Parser };