import { Tokenizer, IToken } from '../tokenizer/tokenizer'import { Stmt, DeclareStmt, Program, Function, Block, IfStmt, ReturnStmt } from './statement'import { Expr, FunctionCallExpr, AssignExpr, Args } from './expression'import { Terminal, Identifier, Numeral } from './terminal'import { expressionParser } from './exprParser'/*** 自顶部向下递归+lookahead一个token的parser* Program -> Stmts* Stmts -> Stmt Stmts | ε* Stmt -> AssignExpr | IfStmt | WhileStmt | Function | Block | ...* xxStmt -> Expr | Stmt | Terminal* Expr -> Terminal*/export class Parser {public tokens: Array<IToken> //token流public lookahead: IToken //下一个tokenprivate index: number //第index个token//语法分析函数parse(sourceCode): Program {//从词法分析器拿到tokensthis.tokens = new Tokenizer(sourceCode).tokens// 增加一个哨兵,用于判断结尾this.tokens.push({ type: 'eof', value: null })this.index = 0this.lookahead = this.tokens[this.index++]const program: Program = this.parseProgram()program.buildLexicalScope()return program}//向前读一个token:封装index,避免危险操作read(): void {if (this.lookahead.type !== 'eof') {this.lookahead = this.tokens[this.index++]}}//校验token,并向前读一个match(value): string {if (this.lookahead.value === value) {this.read()return value}throw `syntax error @line ${this.lookahead.lineNo} : expect ${value} here but ${this.lookahead.value} found.`}//校验类型(静态语言),并向前读一个matchType(type): void {if (this.lookahead.type === type) {this.read()}throw 'syntax error'}//解析表达式parseExpr(): Expr | Terminal {return new expressionParser(this).exprParser()}/*** Stmts -> Stmt Stmts | ε*/parseStmts(): Array<Stmt | Expr | Terminal> {const stmts = []while (this.lookahead.type !== 'eof' && this.lookahead.value !== '}') {stmts.push(this.parseStmt())}return stmts}/*** Program -> Stmts*/parseProgram(): Program {return new Program(this.parseStmts())}/*** Stmt -> AssignExpr | IfStmt | WhileStmt | Function | Block | ...* AssignExpr -> var <id> = Expr* IfStmt -> if Expr Block else IfStmt | if Expr Block | Stmt*/parseStmt(): Stmt | Expr | Terminal {if (this.lookahead.type === 'id' || this.lookahead.type === 'number') {return this.parseExpr()}switch (this.lookahead.value) {case 'var':return this.parseDeclareStmt()case 'function':return this.parseFunctionStmt()case 'if':return this.parseIfStmt()case 'return':return this.parseReturnStmt()default:console.log(this.lookahead)throw `syntax error @line ${this.lookahead.lineNo} : not impl. ${this.lookahead.value}`}}parseBlock(): Block {this.match('{')const stmts = this.parseStmts()this.match('}')return new Block(stmts)}/*** FunctionStmt -> function {id}(...ARGS) BLOCK*/parseFunctionStmt(): Function {this.match('function')if (this.lookahead.type !== 'id') {throw 'syntax error'}const id = this.lookahead.valuethis.match(id)this.match('(')const args = this.parseFuncArguments()this.match(')')const block: Block = this.parseBlock()return new Function(new Identifier(id), args, block)}/*** ReturnStmt -> return Expr*/parseReturnStmt(): ReturnStmt {this.match('return')const expr = this.parseExpr()return new ReturnStmt(expr)}/*** Args -> <id> | <id>,Args | ε*/parseFuncArguments(): Args {let list = []if (this.lookahead.type === 'id') {const id = this.lookahead.valuethis.match(id)list.push(new Identifier(id))if (this.lookahead.value === ',') {this.match(',')list = list.concat(this.parseFuncArguments())}}// else {// return []// }return new Args(list, 'function')}/*** fn(args)函数调用的参数解析*/parseArguments(): Args {let list = []let expr: Expr | Terminal = nullwhile ((expr = this.parseExpr())) {list.push(expr)}return new Args(list)}/*** IfStmt -> if Expr Block | if Expr Block else IfStmt | if Expr Block else Block*/parseIfStmt(): IfStmt {this.match('if')const expr = this.parseExpr()const ifBlock = this.parseBlock()if (this.lookahead.value === 'else') {this.match('else')// @ts-ignoreif (this.lookahead.value === 'if') {const ifStmt = this.parseIfStmt()return new IfStmt(expr, ifBlock, ifStmt)}else {const elseBlock = this.parseBlock()return new IfStmt(expr, ifBlock, null, elseBlock)}} else {return new IfStmt(expr, ifBlock)}}/*** DeclareStmt -> var id = expr*/parseDeclareStmt(): DeclareStmt {this.match('var')if (this.lookahead.type !== 'id') {throw 'syntax error'}const id = new Identifier(this.lookahead.value)this.match(this.lookahead.value)this.match('=')const right = this.parseExpr()return new DeclareStmt(id, right)}/*** factor -> number | string | id*/parseFactor(): Terminal | Expr {if (this.lookahead.type === 'number') {const value = this.match(this.lookahead.value)return new Numeral(value)}else if (this.lookahead.type === 'id') {const value = this.match(this.lookahead.value)if (this.lookahead.value === '(') {this.match('(')const args = this.parseArguments()this.match(')')return new FunctionCallExpr(new Identifier(value), args)}else if (this.lookahead.value === '=') {this.match('=')const expr = this.parseExpr()return new AssignExpr(new Identifier(value), expr)}return new Identifier(value)} else if (this.lookahead.type === 'string') {throw 'not impl.'} else {throw `syntax error, expect a factor but ${this.lookahead.value} found`}}}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。