cfg-first-follow
Version:
Calculate FIRST and FOLLOW set of a Context Free Grammar symbol
90 lines • 4.65 kB
JavaScript
;
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