UNPKG

@parser-generator/grammar-interpreter

Version:

A Parser Generator that supports LL,SLR,LR1,LALR

917 lines (915 loc) 33.1 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const definition_1 = require("@parser-generator/definition"); const shim_1 = require("@light0x00/shim"); // import { cloneDeep, groupBy ,Dictionary} from "lodash"; const cloneDeep_1 = __importDefault(require("lodash/cloneDeep")); const groupBy_1 = __importDefault(require("lodash/groupBy")); const core_1 = require("@parser-generator/core"); const definition_2 = require("@parser-generator/definition"); // import { } from "@parser-generator/definition"; /*************************************** Lexical Analysis ****************************************/ var Tag; (function (Tag) { Tag["BLANK"] = "BLANK"; Tag["CRLF"] = "CRLF"; Tag["EOF"] = "EOF"; Tag["NIL"] = "NIL"; Tag["HEAD"] = "HEAD"; Tag["SCRIPT"] = "SCRIPT"; Tag["STRING"] = "STRING"; Tag["STRING_SINGLE_QUOTES"] = "STRING_SINGLE_QUOTES"; Tag["STRING_DOUBLE_QUOTES"] = "STRING_DOUBLE_QUOTES"; Tag["NUMBER"] = "NUMBER"; Tag["WORD"] = "WORD"; Tag["SINGLE"] = "SINGLE"; Tag["ID"] = "ID"; Tag["KEYWORD"] = "KEYWORD"; Tag["ASSOC"] = "ASSOC"; })(Tag = exports.Tag || (exports.Tag = {})); class Token { constructor(tag) { this._lineNo = -1; this._colNo = -1; this._tag = tag; } setPos(lineNo, colNo) { this._lineNo = lineNo; this._colNo = colNo; } get lineNo() { return this._lineNo; } get colNo() { return this._colNo; } get tag() { return this._tag; } toString() { return this.value + `(${this._lineNo},${this._colNo})`; } } class Special extends Token { constructor(tag) { super(tag); } get value() { return this._tag; } } class Word extends Token { constructor(tag, lexeme) { super(tag); this.lexeme = lexeme; } get value() { return this.lexeme; } } class Number extends Token { constructor(lexeme) { super(Tag.NUMBER); this.lexeme = lexeme; } get value() { return this.lexeme; } } /("|')(?<value>(\\(\1)|[^\1])*)?(\1)/.exec(`'\\"\\'aa'`); class GrammarLexer extends definition_2.CommonAbstractRegexpLexer { constructor(text) { super(text, [ { regexp: /\n+/y, type: Tag.CRLF, }, { regexp: /\s+/y, type: Tag.BLANK, }, { regexp: /#(?<value>\w+)/y, type: Tag.HEAD }, { regexp: /[A-Z_a-z]\w*/y, type: Tag.WORD }, { regexp: /<%(?<value>(.|\s)+?)%>/y, type: Tag.SCRIPT }, { regexp: /'(?<value>(\\(')|[^'])*)?'/y, type: Tag.STRING }, { regexp: /"(?<value>(\\(")|[^"])*)?"/y, type: Tag.STRING }, { regexp: /([1-9]\d*\.\d+)|(0\.\d+)/y, type: Tag.NUMBER }, { regexp: /(0(?![0-9]))|([1-9]\d*(?!\.))/y, type: Tag.NUMBER }, { regexp: /(.)/y, type: Tag.SINGLE } ]); this.lineNo = 1; this.colNo = 0; this.reserves = new Map(); this.reserves.set("left", new Word(Tag.ASSOC, "left")); this.reserves.set("right", new Word(Tag.ASSOC, "right")); this.reserves.set("NIL", new Special(Tag.NIL)); } getEOF() { if (this.eofToken == undefined) { this.eofToken = new Special(Tag.EOF); this.eofToken.setPos(this.lineNo, this.colNo); } return this.eofToken; } createToken(lexeme, type, match) { let token; switch (type) { case Tag.CRLF: this.lineNo += lexeme.length; this.colNo = 0; break; case Tag.BLANK: break; case Tag.WORD: { let re = this.reserves.get(lexeme); if (re == undefined) token = new Word(Tag.ID, lexeme); else token = cloneDeep_1.default(re); break; } case Tag.HEAD: token = new Word(Tag.HEAD, match.groups["value"]); break; case Tag.SCRIPT: { token = new Word(Tag.SCRIPT, match.groups["value"]); token.setPos(this.lineNo, this.colNo); //处理行列计数 let { rows, cols } = shit(lexeme); this.lineNo += rows; this.colNo = (rows > 0) ? cols : this.colNo += cols; break; } case Tag.NUMBER: token = new Number(parseFloat(lexeme)); break; case Tag.STRING: { let lexeme; if (match[0].startsWith("\"")) { lexeme = match.groups["value"].replace(/\\"/g, "\""); } else { lexeme = match.groups["value"].replace(/\\'/g, "'"); } token = new Word(Tag.STRING, lexeme); } break; case Tag.SINGLE: token = new Word(Tag.SINGLE, lexeme); break; default: throw new Error(`unknown type ${type}`); } if (type != Tag.SCRIPT) { //script 类型单独处理 if (token != undefined) token.setPos(this.lineNo, this.colNo); this.colNo += lexeme.length; } return token; } onMatchFaild(text, lastIndex) { throw new Error(`unrecognized charactor(${this.lineNo},${this.colNo}):${text[lastIndex]} `); } } exports.GrammarLexer = GrammarLexer; //返回指定字符串的换行符数量,最后一行的列数 function shit(str) { let rows = 0; let cols = 0; let isLastRow = true; for (let i = str.length - 1; i >= 0; i--) { if (str[i] == "\n") { rows++; isLastRow = false; } else if (isLastRow) cols++; } return { rows, cols }; } /*************************************** AST ****************************************/ class ASTree { } class ProgramNode extends ASTree { constructor(gNode, paNode, blocks) { super(); // traits: SymbolTraits; this.traits = new Map(); this.grammarNode = gNode; this.blocks = blocks; // if (paNode == undefined) // this.traits = new Map<SSymbol, SymbolTrait>(); // else // this.traits = paNode.traits; } accpet(visitor) { for (let c of this.blocks) { c.accpet(visitor); } visitor.visitProgramNode(this); } } exports.ProgramNode = ProgramNode; class ScriptNode extends ASTree { constructor(t) { super(); this.script = t.value; } accpet(visitor) { visitor.visitScriptNode(this); } } class PrecAssocNode extends ASTree { constructor(children) { super(); this.children = children; } accpet(visitor) { visitor.visitPrecAssocNode(this); } } class PrecassocItemNode extends ASTree { constructor(tokens) { super(); shim_1.assert(tokens[0] != undefined); this.symbol = tokens[0]; // this.leftAssoc = (tokens[1]?.value??"right") == "left"; // this.prec = (tokens[2]?.value??-1) as number; console.log(tokens); if (tokens[1] != undefined) this.leftAssoc = tokens[1].value == "left"; else this.leftAssoc = false; if (tokens[2] != undefined) this.prec = tokens[2].value; else this.prec = -1; } accpet(visitor) { throw new Error("Method not implemented."); } } class Env { constructor() { this.syms = new Map(); //反向索引 this.rsyms = new Map(); //记录变量对应的对象 的变量名 this.prods = new Map(); //记录Production对象对应的变量名 this.rprods = new Map(); //记录Production对象对应的变量名 this.registerSym("NIL", definition_1.NIL); this.registerSym("EOF", definition_1.EOF); } //Symbol registerSym(varName, sym) { this.syms.set(varName, sym); this.rsyms.set(sym, varName); } getSym(varName) { return this.syms.get(varName); } hasSym(varName) { return this.syms.has(varName); } getSymVarName(sym) { return this.rsyms.get(sym); } //Production registerProd(prod, varName) { this.rprods.set(prod, varName); this.prods.set(varName, prod); } getProdVarName(prod) { shim_1.assert(this.rprods.has(prod), `Undeclared production ${prod}`); return this.rprods.get(prod); } getProd(varName) { shim_1.assert(this.prods.has(varName), `Undeclared productio ${varName}`); return this.prods.get(varName); } } class GrammarNode extends ASTree { // Directory <ProductionNode[]> constructor(tNodes, ntNodes, prodNodes) { super(); this._env = new Env(); //属性 this.nts = []; this.tpNodes = tNodes; this.prodNodes = prodNodes; this.ntNodes = ntNodes; /* 初始化文法变量 */ //terminal proto for (let { token: t } of tNodes) { let v = t.value; if (this.env.hasSym(v)) throw new Error(`Duplicate declared variable ${v} at (${t.lineNo},${t.colNo})`); this.env.registerSym(v, new definition_1.TokenPro(v)); } //non-terminal for (let i = 0; i < ntNodes.length; i++) { let nt = ntNodes[i].token; let varName = ntNodes[i].varName; if (this.env.hasSym(varName)) throw new Error(`Duplicate declared variable ${varName} at (${nt.lineNo},${nt.colNo})`); let ntProto; if (i == 0) this.startSym = ntProto = new definition_1.NonTerminal(varName, true); else ntProto = new definition_1.NonTerminal(varName); this.env.registerSym(varName, ntProto); this.nts.push(ntProto); } //产生式按所属非终结符分组 this.prodNodeGroups = groupBy_1.default(this.prodNodes, (p) => p.ntVarName); //为产生式分配id和变量名 let prodIdCount = 0; for (let key in this.prodNodeGroups) { let group = this.prodNodeGroups[key]; for (let pNode of group) { pNode.pid = prodIdCount++; pNode.varName = "p" + pNode.pid; pNode.env = this.env; } } } get env() { return this._env; } accpet(visitor) { for (let tpNode of this.tpNodes) { visitor.visitTokenProNode(tpNode); } for (let ntNode of this.ntNodes) { visitor.visitNonterminalNode(ntNode); } for (let pNode of this.prodNodes) { visitor.visitProductionNode(pNode); } visitor.visitGrammarNode(this); } } class TokenProNode extends ASTree { constructor(token) { super(); this.token = token; this.varName = token.value; } accpet(visitor) { visitor.visitTokenProNode(this); } } class ProductionNode extends ASTree { constructor(nt, body) { super(); this.left = nt; this.ntVarName = nt.value; //pre if (body[0].tag == Tag.SCRIPT) this.preAction = body[0]; //post if (body[body.length - 1].tag == Tag.SCRIPT) this.postAction = body[body.length - 1]; //body this.rawBody = new Array(); let start = this.preAction == undefined ? 0 : 1; let end = this.postAction == undefined ? body.length - 1 : body.length - 2; for (let i = start; i <= end; i++) { let symbol = body[i]; let action; if (i + 1 <= end && body[i + 1].tag == Tag.SCRIPT) { action = body[i + 1]; i++; } this.rawBody.push({ symToken: symbol, action: action }); } } accpet(visitor) { visitor.visitProductionNode(this); } } class NonTerminalNode extends ASTree { constructor(token, prods) { super(); this._varName = token.value; this.token = token; this.prods = prods; let defaultPostAction; for (let p of prods) { if (defaultPostAction == undefined && p.postAction != undefined) { defaultPostAction = p.postAction; break; } } // if (defaultPostAction == undefined) // console.warn(`The nonterminal "${this.varName}" doesn't have post-action,it's required for parser!`); //没有归约动作的产生式 优先向后寻找 如果后方没有 则使用默认的 for (let i = 0; i < prods.length; i++) { if (prods[i].postAction == undefined) { for (let k = i + 1; k < prods.length; k++) { if (prods[k].postAction != undefined) { prods[i].postAction = prods[k].postAction; break; } } if (prods[i].postAction == undefined) prods[i].postAction = defaultPostAction; } } } get varName() { return this._varName; } accpet(visitor) { visitor.visitNonterminalNode(this); } } function pos(t) { return `(${t.lineNo},${t.colNo})`; } /*************************************** Syntax Analysis ****************************************/ const TOKEN_KEY = "TOKEN_PROTOTYPES"; const GRAMMAR_KEY = "GRAMMAR"; const SPA_KEY = "SYMBOL_ASSOC_PREC"; function parse(lexer) { /**************************************** 文法草案 {} 重复0次多多次 [] 0次或一次 program -> SCRIPT | HEAD { SCRIPT | HEAD } token -> ID {,ID} precassoc -> precassoc_item { precassoc_item } precassoc_item -> symbol ('left' | 'right') NUMBER grammar -> nt { nt } nt -> ID '-' '>' prod { | prod } ';' prod -> [ SCRIPT ] symbol SCRIPT { symbol SCRIPT } symbol -> ID | token | string ****************************************/ return program(); function misMatch(expection, actuality) { throw new Error(`Expected token is ${expection}, but actually ${actuality}`); } function program() { /* Block: - GRAMMAR (Required) - TOKEN_PROTO - SCRIPT - PREC_ASSOC */ //如果生成代码时需要保证每个块的顺序 则用链表存储顺序 let blocks = new Array(); let grammarNode; let precAssocNode; let terminalProtoNodes; blocks.push(...scriptBlock()); //token 声明 if (lexer.peek().value == TOKEN_KEY) { lexer.next(); terminalProtoNodes = tokenDeclarationsBlock(); } else { terminalProtoNodes = []; } blocks.push(...scriptBlock()); //文法 if (lexer.peek().value == GRAMMAR_KEY) { lexer.next(); grammarNode = grammarBlock(terminalProtoNodes); blocks.push(grammarNode); } else { misMatch(GRAMMAR_KEY, lexer.peek().value); } blocks.push(...scriptBlock()); //优先级 结合性 if (lexer.peek().value == SPA_KEY) { lexer.next(); precAssocNode = precAssocBlock(); if (precAssocNode != undefined) blocks.push(precAssocNode); } else { precAssocNode = new PrecAssocNode([]); } blocks.push(...scriptBlock()); if (lexer.peek().tag != Tag.EOF) { throw new Error(`Unexpected block "${lexer.peek().value}" at ` + pos(lexer.peek())); } return new ProgramNode(grammarNode, precAssocNode, blocks); } function scriptBlock() { let scriptNodes = []; while (lexer.peek().tag == Tag.SCRIPT) scriptNodes.push(new ScriptNode(lexer.next())); return scriptNodes; } function tokenDeclarationsBlock() { let protos = []; while (1) { if (lexer.peek().tag != Tag.ID) break; protos.push(new TokenProNode(lexer.next())); if (lexer.peek().value != ",") break; lexer.next(); } return protos; } function precAssocBlock() { let items = new Array(); while (isSymbol(lexer.peek())) { let sym = lexer.next(); let assoc, prec; if (lexer.peek().tag == Tag.ASSOC) { assoc = lexer.next(); // throw new Error(`expect left or right at (${pos(lexer.peek())})`); } if (lexer.peek().tag == Tag.NUMBER) { prec = lexer.next(); // throw new Error(`expect a number at (${pos(lexer.peek())})`); } if (assoc === undefined && prec === undefined) { throw new Error(`expect a left/right or number at (${pos(lexer.peek())})`); } items.push(new PrecassocItemNode([sym, assoc, prec])); } if (items.length > 0) return new PrecAssocNode(items); } function isSymbol(token) { return token.tag == Tag.STRING || token.tag == Tag.ID; } function grammarBlock(terminalProtoNodes) { let rawGrammar = new Array(); let ntDecls = new Array(); //文法中声明的所有非终结符(左侧) let nt; while ((nt = nonTerminal()) != undefined) { rawGrammar.push(nt); ntDecls.push(nt.key); } shim_1.assert(rawGrammar.length > 0, "The grammar should have at least one non-terminal "); let ntNodes = new Array(); let prodNodes = new Array(); //每一个非终结符 for (let { key, prods } of rawGrammar) { let ntPNodes = new Array(); //非终结符的每一个产生式 for (let p of prods) { ntPNodes.push(new ProductionNode(key, p)); } ntNodes.push(new NonTerminalNode(key, ntPNodes)); prodNodes.push(...ntPNodes); } return new GrammarNode(terminalProtoNodes, ntNodes, prodNodes); } function matchNext(tag, val) { let look = lexer.next(); let tagMis = look.tag != tag; let valMis = val != undefined && look.value != val; if (tagMis) { let msg = valMis ? `expect ${tag} ${val} at ${pos(look)}` : `expect ${tag} at ${pos(look)}`; throw new Error(msg); } } function nonTerminal() { if (lexer.peek().tag != Tag.ID) return undefined; //左侧 let nt = lexer.next(); //箭头 matchNext(Tag.SINGLE, "-"); matchNext(Tag.SINGLE, ">"); //右侧 let prods = []; while (1) { let curProd = production(); //下一个是产生式 if (lexer.peek().value == "|") { prods.push(curProd); curProd = []; lexer.next(); } //已经到达当前非终结符末尾 else if (lexer.peek().value == ";") { prods.push(curProd); lexer.next(); break; } else { throw new Error(`Unexpected symbol "${lexer.peek().value}" at ` + pos(lexer.peek())); } } return { key: nt, prods }; } function production() { let body = new Array(); let isScript = false; let isNil = false; //是否是空产生式体 while (1) { if (lexer.peek().tag == Tag.ID || lexer.peek().tag == Tag.STRING) { if (isNil) { throw new Error("The NIL production can't have any symbol,expected \";\" at" + pos(lexer.peek())); } isScript = false; body.push(lexer.next()); } else if (lexer.peek().tag == Tag.NIL) { isScript = false; isNil = true; body.push(lexer.next()); } else if (lexer.peek().tag == Tag.SCRIPT) { if (isScript) throw new Error("The production body cannot have multiple continuous script," + pos(lexer.peek())); body.push(lexer.next()); isScript = true; } else { break; } } return body; } } exports.parse = parse; class EvalVisitor { constructor(context) { this.traits = new Map(); this.nts = []; this.prods = []; this.context = context; } get grammar() { if (this._grammar == undefined) { let { parser } = this.context; if (parser == "LL") this._grammar = new definition_1.Grammar(this.nts, this.prods, this.startSym, this.traits); //根据配置决定初始化 else this._grammar = new definition_1.AugmentedGrammar(this.nts, this.prods, this.startSym, this.traits); //根据配置决定初始化 } return this._grammar; } visitProgramNode(node) { // } visitScriptNode(node) { // } visitGrammarNode(node) { this.startSym = node.startSym; this.nts = node.nts; this.env = node.env; } visitTokenProNode(node) { // } visitNonterminalNode(node) { // } visitProductionNode(node) { let nt = node.env.getSym(node.ntVarName); let body = new Array(); for (let { symToken } of node.rawBody) { if (symToken.tag == Tag.STRING) { body.push(new definition_1.SymbolWrapper(symToken.value)); } else if (symToken.tag == Tag.ID || symToken.tag == Tag.NIL) { let proto = node.env.getSym(symToken.value); shim_1.assert(proto != undefined, `Undeclared identifier "${symToken.value}" at ` + pos(symToken)); body.push(new definition_1.SymbolWrapper(proto)); } else { throw new Error(`Unknow token ${symToken}!`); } } let preAction = node.preAction == undefined ? undefined : eval(node.preAction.value); let postAction = node.postAction == undefined ? undefined : eval(node.postAction.value); shim_1.assert(node.pid != undefined); let prod = new definition_1.Production(node.pid, nt, body, preAction, postAction); node.env.registerProd(prod, node.varName); //对象到变量名的反向索引(用于代码生成) nt.prods.push(prod); //追加到所属的非终结符 this.prods.push(prod); } visitPrecAssocNode(node) { for (let { symbol, prec, leftAssoc } of node.children) { if (symbol.tag == Tag.STRING) { this.traits.set(symbol.value, new definition_1.SymbolTrait(prec, leftAssoc)); } else if (symbol.tag == Tag.ID) { this.traits.set(this.env.getSym(symbol.value), new definition_1.SymbolTrait(prec, leftAssoc)); } } } } exports.EvalVisitor = EvalVisitor; const DEFINITION_PACKAGE = "@parser-generator/definition"; // const LL_PARSER_PACKAGE = "@parser-generator/core"; // const LR_PARSER_PACKAGE = "@parser-generator/core"; const LR_PARSING_TABLE_VAR = "table"; const FIRST_SET_VAR = "first"; const FOLLOW_SET_VAR = "follow"; const SYMBOL_TRAITS_VAR = "traits"; //ILexer, IToken, ASTElement class TSCodegenVisitor { constructor(context) { this._code = ""; this.context = context; this.emit(`import { ${definition_1.NonTerminal.name}, ${definition_1.TokenPro.name}, ${definition_1.Production.name}, ${definition_1.SymbolWrapper.name}, SSymbol ,${definition_1.SymbolTrait.name}, NIL, Terminal, EOF `); if (context.parser == "LL") { this.emit("}"); } else { this.emit(`,${definition_1.ParsingTable.name}, ${definition_1.Goto.name}, ${definition_1.Shift.name}, ${definition_1.Accept.name}, ${definition_1.Reduce.name} }`); } this.emitln(` from "${DEFINITION_PACKAGE}";`); } emit(code) { this._code += code; } emitln(code) { this.emit(code + "\n"); } get code() { return this._code; } visitProgramNode(node) { // let env = node.grammarNode.env; // let { firstTable, followTable } = this.context; //parser if (this.context.parser == "LL") { // assert(firstTable != undefined && followTable != undefined); // this.emitln(`import {${LLParser.name}} from "${LL_PARSER_PACKAGE}";`); // this.emitln(`export let parser = new ${LLParser.name}(${env.getSymVarName(node.grammarNode.startSym)},${FIRST_SET_VAR},${FOLLOW_SET_VAR});`); this.emitln(`export { ${FIRST_SET_VAR},${FOLLOW_SET_VAR} }`); } else { // this.emitln(`import {${LRParser.name}} from "${LR_PARSER_PACKAGE}";`); // this.emitln(`export let parser = new ${LRParser.name}(${LR_PARSING_TABLE_VAR});`); this.emitln(`export default ${LR_PARSING_TABLE_VAR};`); } } visitScriptNode(node) { this.emit(node.script + "\n"); } visitGrammarNode(node) { for (let key in node.prodNodeGroups) { let group = node.prodNodeGroups[key]; let pnames = new Array(); for (let pNode of group) { pnames.push(pNode.varName); } this.emitln(`${key}.prods=[${pnames.join(",")}];`); } let env = node.env; if (this.context.parser == "LL") { //first table let { firstTable, followTable } = this.context; shim_1.assert(firstTable != undefined && followTable != undefined, "First-table and follow-table is required for lr-parser code generator"); this.emitln("/* first set */"); this.emitln(`let ${FIRST_SET_VAR} = new Map<${definition_1.NonTerminal.name},Map<Terminal,${definition_1.Production.name}>>();`); for (let [nt, fset] of firstTable) { let stmt = `${FIRST_SET_VAR}.set(${env.getSymVarName(nt)},`; stmt += `new Map<Terminal,${definition_1.Production.name}>([`; for (let [sym, prod] of fset) { let k = typeof sym === "string" ? `"${sym}"` : env.getSymVarName(sym); let v = env.getProdVarName(prod); stmt += `[${k},${v}],`; } stmt = stmt.replace(/,$/, ""); stmt += "])"; stmt += ");"; this.emitln(stmt); } //follow table this.emitln("/* follow set */"); this.emitln(`let ${FOLLOW_SET_VAR} = new Map<${definition_1.NonTerminal.name},Set<Terminal>>();`); for (let [nt, fset] of followTable) { let stmt = `${FOLLOW_SET_VAR}.set(${env.getSymVarName(nt)},`; stmt += "new Set<Terminal>(["; for (let a of fset) { if (typeof a === "string") stmt += `"${a}",`; else stmt += env.getSymVarName(a) + ","; } stmt = stmt.replace(/,$/, ""); stmt += "])"; stmt += ");"; this.emitln(stmt); } } else { //lr table let { lrTable: lrParsingTable } = this.context; shim_1.assert(lrParsingTable != undefined, "LR parsing table is required for lr-parser code generator"); this.emitln(`let ${LR_PARSING_TABLE_VAR} = new ${definition_1.ParsingTable.name}();`); for (let [stateId, ops] of lrParsingTable.table) { for (let [sym, op] of ops) { if (typeof sym === "string") { this.emit(`${LR_PARSING_TABLE_VAR}.put(${stateId},"${sym}",`); } else { this.emit(`${LR_PARSING_TABLE_VAR}.put(${stateId},${env.getSymVarName(sym)},`); } if (op.isShift()) { this.emit(`new ${definition_1.Shift.name}(${op.nextStateId})`); } else if (op.isReduce()) { this.emit(`new ${definition_1.Reduce.name}(${env.getProdVarName(op.prod)})`); } else if (op.isGoto()) { this.emit(`new ${definition_1.Goto.name}(${op.nextStateId})`); } else if (op.isAccept()) { this.emit(`new ${definition_1.Accept.name}()`); } this.emitln(");"); } } } } visitTokenProNode(node) { this.emitln(`export let ${node.varName} = new ${definition_1.TokenPro.name}("${node.varName}");`); } visitNonterminalNode(node) { this.emitln(`let ${node.varName} = new ${definition_1.NonTerminal.name}("${node.varName}");`); } visitProductionNode(node) { this.emitln(`/* ${node.env.getProd(node.varName).toString()} */`); let code = `let ${node.varName} = new ${definition_1.Production.name}(${node.pid},${node.ntVarName}`; code += ",["; for (let { symToken: symbol, action } of node.rawBody) { let symbolStr = symbol.tag == Tag.STRING ? `"${symbol.value}"` : symbol.value; let actionStr = (action == undefined ? "" : "," + action.value); code += `\n\tnew ${definition_1.SymbolWrapper.name}(${symbolStr}${actionStr}),`; } code = code.replace(/,$/, ""); code += "]"; if (node.preAction != undefined) code += "," + node.preAction.value; else code += ",undefined"; if (node.postAction != undefined) code += "," + node.postAction.value; else code += ",undefined"; code += ");"; this.emit(code); this.emit("\n"); } visitPrecAssocNode(node) { // this.emit(`let ${SYMBOL_TRAITS_VAR} = new Map<SSymbol, ${SymbolTrait.name}>();`); // for (let item of node.children) { // this.emit("\n"); // let symStr = item.symbol.tag == Tag.STRING ? `"${item.symbol.value}"` : item.symbol.value;//区别字符串字面量与变量名 // this.emit(`${SYMBOL_TRAITS_VAR}.set(${symStr},new ${SymbolTrait.name}(${item.prec},${item.leftAssoc ? "true" : "false"}));`); // } // this.emit("\n"); } } exports.TSCodegenVisitor = TSCodegenVisitor; function genParser(rawGrammar, { parser = "LR1", lang = "TS" }) { let pragram = parse(new GrammarLexer(rawGrammar)); //1. 拿到grammar对象 let evalVisitor = new EvalVisitor({ parser }); pragram.accpet(evalVisitor); let grammar = evalVisitor.grammar; //2. 拿到分析表 let firstTable, followTable, lrTable, lrAutomata; //2.1 first let fir = new core_1.FirstCalculator(grammar); firstTable = fir.getFirstTable(); //2.2 follow let fol = new core_1.FollowCalculator(grammar, fir); followTable = fol.getFollowTable(); if (parser == "LL") { //for nothing } else { //2.3 automata & parsing table shim_1.assert(grammar instanceof definition_1.AugmentedGrammar); if (parser == "SLR") { lrAutomata = core_1.getSLRAutomata(grammar); lrTable = core_1.getSLRParsingTable(grammar, lrAutomata, (i) => fol.getFollowSet(i)); } else if (parser == "LR1") { lrAutomata = core_1.getLR1Automata(grammar, (i) => fir.getFirstSet(i)); lrTable = core_1.getLR1ParsingTable(grammar, lrAutomata); } else if (parser == "LALR") { throw new Error("LALR parsing table is unimplemented!"); } } //3. 生成代码 let codegenVisitor; if (lang == "TS") { codegenVisitor = new TSCodegenVisitor({ parser, firstTable, followTable, lrTable: lrTable }); } else { throw new Error("JS code generator is unimplemented"); } pragram.accpet(codegenVisitor); let code = codegenVisitor.code; //4. 返回结果 return { code, grammar, firstTable, followTable, lrTable, lrAutomata }; } exports.genParser = genParser; //# sourceMappingURL=interp.js.map