jaycc
Version:
### the Javascript C Compiler
256 lines (200 loc) • 6.14 kB
text/typescript
/* 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 };