UNPKG

cfg-first-follow

Version:

Calculate FIRST and FOLLOW set of a Context Free Grammar symbol

90 lines 4.65 kB
"use strict"; var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _Parser_grammar, _Parser_nonTerminals, _Parser_terminals; Object.defineProperty(exports, "__esModule", { value: true }); exports.Parser = void 0; class Parser { constructor(grammar) { _Parser_grammar.set(this, void 0); _Parser_nonTerminals.set(this, void 0); _Parser_terminals.set(this, void 0); __classPrivateFieldSet(this, _Parser_grammar, grammar, "f"); __classPrivateFieldSet(this, _Parser_nonTerminals, new Set(Object.keys(__classPrivateFieldGet(this, _Parser_grammar, "f"))), "f"); __classPrivateFieldSet(this, _Parser_terminals, new Set(Object.values(__classPrivateFieldGet(this, _Parser_grammar, "f")) .flat(2) .filter(symbol => symbol && !__classPrivateFieldGet(this, _Parser_nonTerminals, "f").has(symbol))), "f"); } get grammar() { return __classPrivateFieldGet(this, _Parser_grammar, "f"); } get nonTerminals() { return __classPrivateFieldGet(this, _Parser_nonTerminals, "f"); } get terminals() { return __classPrivateFieldGet(this, _Parser_terminals, "f"); } /** * Finds the `FIRST` set of a given grammar symbol. * @param symbol The grammar symbol whose `FIRST` set is to be calculated */ first(symbol) { const firstSet = new Set(); const productions = __classPrivateFieldGet(this, _Parser_grammar, "f")[symbol]; // symbol is a terminal if it has no productions if (!productions) return firstSet.add(symbol); for (const production of productions) { if (!production) { // symbol has an epsilon production firstSet.add(null); continue; } let pointer = 0; let flag = true; while (flag) { const startSymbol = production[pointer]; // this should never be true for the first iteration of the while loop if (typeof startSymbol === 'undefined') { // current production is reducible to an epsilon production firstSet.add(null); flag = false; } else if (__classPrivateFieldGet(this, _Parser_terminals, "f").has(startSymbol)) { // production begins with a terminal firstSet.add(startSymbol); flag = false; } else { // production begins with a non-terminal const firstOfStartSymbol = this.first(startSymbol); // add all terminals except epsilon (if it exists) from the first-set of current startSymbol into first-set of given symbol firstOfStartSymbol.forEach(e => e && firstSet.add(e)); if (firstOfStartSymbol.has(null)) { // move pointer to next symbol in production if current start symbol has epsilon in its first-set (it can vanish and cease to be the start symbol) pointer++; } else { flag = false; } } } } return firstSet; } follow(symbol) { // TODO } } exports.Parser = Parser; _Parser_grammar = new WeakMap(), _Parser_nonTerminals = new WeakMap(), _Parser_terminals = new WeakMap(); //# sourceMappingURL=parser.js.map