UNPKG

@parser-generator/definition

Version:

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

436 lines (398 loc) 10.2 kB
import { assert, Stack } from "@light0x00/shim"; import { IToken, TableKey } from "./lexical"; /******************************************************************************************************* 符号的原型 符号原型的作用是用于建立一种逻辑上的匹配关系. 对于终结符而言: 1. 值类型符号,对应于 比较值的token,比如 '==' ,没有原型, 分析过程中直接使用词素值匹配 2. 原型类型符号,对应于 比较类型的token, 比如 NUMBER ,其原型是一个TerminalPro对象, 分析过程中使用该对象匹配 对于非终结符: 3. 文法中左侧符号都会对应一个NonterminalPro对象,而产生式体中出现的非终结符,比如 A->aA ,第二个 例: E->E1+F1 F->digit - 终结符‘+’没有原型,分析时匹配词素值. - 终结符 digit 的实例则不可枚举,1、2都digit,分析时不能以词素值为准,而是以原型为准,1、2的词素值不一样,但其原型一致, 这是一种逻辑相等关系. - 非终结符E1的原型是E,F1的原型是F. *******************************************************************************************************/ /** * 非终结符符号原型 */ export class NonTerminal implements TableKey { private _name: string private _prods: Production[] private _isStart: boolean constructor(name: string, isStart: boolean = false, prods: Production[] = []) { this._name = name; this._isStart = isStart; this._prods = prods; } get name() { return this._name; } get prods() { return this._prods; } set prods(ps: Production[]) { this._prods = ps; } get isStart() { return this._isStart; } toString() { return this._name; } key(): SSymbol { return this; } } /** * token原型 */ export class TokenPro implements IToken { private name: string //just for debug constructor(name: string) { this.name = name; } toString() { return this.name; } key(): Terminal { return this; } } export const NIL = new TokenPro("NIL"); export const EOF = new TokenPro("EOF"); export type SSymbol = string | NonTerminal | TokenPro; export type Terminal = TokenPro | string; //还应该包含一些基础类型 所以还是设置为 Object最好 export function isNonTerminal(sym: Object): sym is NonTerminal { return sym instanceof NonTerminal; } export function isTerminal(sym: Object): sym is Terminal { return sym instanceof TokenPro || typeof sym === "string"; } export type MidAction = ((stack: Stack<ASTElement>) => void) export class SymbolWrapper { private _value: SSymbol private _action: MidAction | undefined constructor(sym: SSymbol, action?: MidAction) { this._value = sym; this._action = action; } get value(): string | NonTerminal | TokenPro { return this._value; } get action(): MidAction | undefined { return this.action; } isNonTerminal(): boolean { return isNonTerminal(this._value); } isTerminal(): boolean { return isTerminal(this._value); } isNIL(): boolean { return this._value == NIL; } toString() { return this._value.toString() + (this._action == undefined ? "" : `<%${this._action}%>`); } } /** * 产生式 */ export class Production { private _id: number private _nt: NonTerminal private _actionBody: SymbolWrapper[] private _body: SSymbol[] private _preAction: PreAction | undefined private _postAction: PostAction | undefined private _leftAssoc: boolean; private _prec: number; constructor(id: number, nt: NonTerminal, body: SymbolWrapper[], preAction?: PreAction, postAction?: PostAction, leftAssoc = false, prec = -1) { this._id = id; this._nt = nt; this._actionBody = body; this._preAction = preAction; this._postAction = postAction; this._body = new Array<SSymbol>(); this._leftAssoc = leftAssoc; this._prec = prec; for (let asym of body) { this._body.push(asym.value); } } get id() { return this._id; } get head() { return this._nt; } get body() { return this._body; } get actionBody() { return this._actionBody; } get preAction() { return this._preAction; } get postAction() { if (this._postAction == undefined) console.warn(`production(${this.id}) doesn't have post action, it is required for Parser`); return this._postAction!; //TODO } get action() { return this.postAction; } get prec() { return this._prec; } set prec(val) { this._prec = val; } get leftAssoc() { return this._leftAssoc; } set leftAssoc(val) { this._leftAssoc = val; } isEpsilon() { return this._body.length == 1 && this._body[0] === NIL; } toString() { return (this._preAction == undefined ? "" : "<%" + this.preAction + "%>") + `(${this._id}) ${this._nt}->${this._actionBody.map(o => o.toString()).join("")}` + (this._postAction == undefined ? "" : "<%" + this.postAction + "%>"); } } export type PreAction = (stack: Stack<ASTElement>) => void export type PostAction = (eles: Array<ASTElement>, stack: Stack<ASTElement>) => ASTree /** * 文法对象的api定义 */ export interface IGrammar { /** * 获得文法的所有非终结符 */ nonTerminals(): NonTerminal[]; /** * 获得所有产生式 */ productions(): Production[]; /** * 获得文法的开始符号 */ startNT(): NonTerminal; } /** * 符号优先级、结合性 */ export class SymbolTrait { private _prec: number; private _leftAssoc: boolean constructor(prec: number, leftAssoc: boolean) { this._prec = prec; this._leftAssoc = leftAssoc; } get prec() { return this._prec; } get leftAssoc() { return this._leftAssoc; } compareTo(other: SymbolTrait): boolean { //TODO return false; } } export type SymbolTraits = Map<SSymbol, SymbolTrait> export class Grammar implements IGrammar { protected nts: NonTerminal[] protected prods: Production[] protected traits: SymbolTraits protected startSym: NonTerminal constructor(nts: NonTerminal[], prods: Production[], startSymbol: NonTerminal, traits: SymbolTraits = new Map<SSymbol, SymbolTrait>()) { this.nts = nts; this.prods = prods; this.startSym = startSymbol; this.traits = traits; //处理产生式的优先级与结合性 for (let p of prods) { if(traits.has(p.head)){ let trait = traits.get(p.head)!; p.prec = trait.prec; p.leftAssoc = trait.leftAssoc; } let prec =p.prec; let leftAssoc = p.leftAssoc; for (let s of p.body) { if (traits.has(s)) { let trait = traits.get(s)!; if (trait.prec > prec) { prec = trait.prec; leftAssoc = trait.leftAssoc; } } } p.prec = prec; p.leftAssoc = leftAssoc; } this.validate(); } protected validate() { } nonTerminals(): NonTerminal[] { return this.nts; } productions(): Production[] { return this.prods; } startNT(): NonTerminal { return this.startSym; } toString() { return this.prods.join("\n"); } } /*************************************** LR相关 ****************************************/ export class AugmentedGrammar extends Grammar { protected validate() { assert(this.startSym.prods.length == 1, `The start symbol of an augmented grammar has one and only one production! but ${this.startSym} has ${this.startSym.prods.length}:\n${this.startSym.prods.join("\n")}`); } } /* 表示LR语法分析表格的操作 */ export abstract class Operation { abstract equals(obj: Object): boolean isReduce(): this is Reduce { return false; } isShift(): this is Shift { return false; } isGoto(): this is Goto { return false; } isAccept(): this is Accept { return false; } } export class Shift extends Operation { private _nextStateId: number; constructor(nextStateId: number) { super(); this._nextStateId = nextStateId; } get nextStateId() { return this._nextStateId; } toString() { return `shift ${this._nextStateId}`; } equals(obj: Object) { return obj instanceof Shift && obj._nextStateId == this._nextStateId; } isShift() { return true; } } export class Goto extends Operation { private _nextStateId: number; constructor(nextStateId: number) { super(); this._nextStateId = nextStateId; } get nextStateId() { return this._nextStateId; } toString() { return `goto ${this._nextStateId}`; } equals(obj: Object) { return obj instanceof Goto && obj._nextStateId == this._nextStateId; } isGoto() { return true; } } export class Reduce extends Operation { /* 用于归约的产生式 */ private _prod: Production; constructor(prod: Production) { super(); this._prod = prod; } get prod() { return this._prod; } toString() { return `reduce ${this._prod.id}`; } equals(obj: Object) { return obj instanceof Reduce && obj._prod == this._prod; } isReduce() { return true; } } export class Accept extends Operation { constructor() { super(); } equals(obj: Object) { return obj instanceof Accept; } toString() { return `accept`; } isAccept() { return true; } } /* TODO 考虑是否应该包装 Map */ // export type LRParsingTable = Map<number, Map<SSymbol, Operation>>; export class ParsingTable { private parsingTable = new Map<number, Map<SSymbol, Operation>>() get table() { return this.parsingTable; } put(state: number, symbol: SSymbol, op: Operation): void { let row = this.parsingTable.get(state); if (row == undefined) { row = new Map<SSymbol, Operation>(); this.parsingTable.set(state, row); } row.set(symbol, op); } has(state: number, symbol: SSymbol, op: Operation): boolean { let row = this.parsingTable.get(state); if (row == undefined) return false; let exstingOp = row.get(symbol); if (exstingOp == null) return false; return exstingOp.equals(op); } get(state: number, symbol: SSymbol): Operation | undefined { let row = this.parsingTable.get(state); if (row == undefined) return undefined; return row.get(symbol); } getExpectedSymbols(state: number): SSymbol[] { let row = this.parsingTable.get(state); if (row == undefined) return []; return Array.from(row.keys()); } getExpectedTokens(state: number) { let expS = this.getExpectedSymbols(state); return expS.filter(s => !(s instanceof NonTerminal)); } } /** * 构成ASTree节点的元素 */ export type ASTElement = IToken | ASTree export interface ASTree { }