@light0x00/parser-generator
Version:
A Parser Generator
145 lines (110 loc) • 17.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.FollowSetCalculator = void 0;
var _shim = require("@light0x00/shim");
var _parserDefinition = require("@light0x00/parser-definition");
var _debug = _interopRequireDefault(require("debug"));
var _Toolkit = require("./Toolkit");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
let debug = (0, _debug.default)("APP:follow");
class FollowSetCalculator {
// issue: 9.循环依赖
constructor(grammar, firstSetCalculator) {
_defineProperty(this, "cyclicDector", new _Toolkit.CyclicDepsDector());
_defineProperty(this, "cache", new Map());
_defineProperty(this, "firstSetCalculator", void 0);
_defineProperty(this, "grammar", void 0);
this.grammar = grammar;
this.firstSetCalculator = firstSetCalculator;
}
throwError(holder, other) {
throw new Error(`Cyclic dependencies are detected between the non-terminal ${holder} and ${other} when calculating the follow set of ${holder}!`);
}
/*
约定:
j表示当前正在处理的产生式(prod)
k表示当前正在处理的符号(j中的一个符号)
k+n表示当前符号k后的n个符号
伪代码:
k是否为j末尾符号
- 是, 加入Follow(j)
- 不是,加入 (First(k+1)-{ε})
- 如果 ε ∈ First(k+1) 则继续加入 First(k+2)).
并重复这一过程,直到第n个满足ε ∉ First(k+n),
如果符号(k+n)直到j的最后一个符号还仍旧存在 ε ∈ First(k+n), 则加入Follow(j)
注:伪代码仅供参考,一切以实物为准!
*/
getFollowSet(target) {
if (this.cache.has(target)) {
debug(`cache hit:${target}`);
return this.cache.get(target);
}
let non_terminals = this.grammar.NTS();
let follow_set = new Set();
let whichHaveAddedFristSet = new Set(); //记录已经添加过哪些符号的First集
let whichHaveAddedFollowSet = new Set(); //记录已经添加过哪些符号的Follow集
if (non_terminals[0] == target) {
// if start symbol
follow_set.add(_parserDefinition.EOF);
debug(`+EOF is added because ${target} is the beginning symbol`);
} //每一个非终结符i
for (let i = 0; i < non_terminals.length; i++) {
let non_terminal = non_terminals[i]; //终结符中的每一个产生式j
for (let j = 0; j < non_terminal.prods.length; j++) {
let prod = non_terminal.prods[j];
debug(`Scanning ${target} in production:${prod}`);
let searching = false; //标记是否处于搜索状态 issue: 5. 连续重复
//每一个符号k
for (let k = 0; k < prod.length; k++) {
if (prod[k] != target && !searching) {
//非搜索状态,且非target,则跳过 issue: 5. 连续重复
continue;
} //k为j的末尾符号
if (k == prod.length - 1) {
if (non_terminal != target && !whichHaveAddedFollowSet.has(non_terminal)) {
//issue: 6,7 自递归 && 重复添加
if (this.cyclicDector.registerAndCheckCycl(target, non_terminal)) // issue: 9.循环依赖 跳过
continue;
debug(`+Since ${target.name} is at the end of production ${prod.name},add Follow(${non_terminal.name})`);
(0, _shim.addAll_Set)(follow_set, this.getFollowSet(non_terminal));
whichHaveAddedFollowSet.add(non_terminal); //标记Follow(p)已添加
}
break;
}
searching = true; //处理k+1
let follower = prod[k + 1];
if (whichHaveAddedFristSet.has(follower)) //issue: 6. 重复添加
continue;
let followerFirstSet = this.firstSetCalculator.getFirstSet(follower);
whichHaveAddedFristSet.add(follower); //标记 First(k+1)为已添加
//如果: ε ∈ First(k+1)
if (followerFirstSet.has(_parserDefinition.NIL)) {
(0, _shim.addAll_Set)(follow_set, followerFirstSet);
follow_set.delete(_parserDefinition.NIL);
debug(`+The symbol ${follower} follows ${target},add First(${follower})-{𝝴}, due ${follower} contains 𝝴 ,scan the following symbol of ${follower} `);
} //如果 ε ∉ First(k+1)
else {
(0, _shim.addAll_Set)(follow_set, followerFirstSet);
debug(`+The symbol ${follower} follows ${target},add First(${follower})`);
searching = false; //k+1不可推出𝝴 则结束搜索状态 issue: 5. 连续重复
}
}
}
}
this.cache.set(target, follow_set);
return follow_set;
}
getFollowTable() {
let followTable = new Map();
for (let non_terminal of this.grammar.NTS()) {
let followSet = this.getFollowSet(non_terminal);
followTable.set(non_terminal.name, followSet);
}
return followTable;
}
}
exports.FollowSetCalculator = FollowSetCalculator;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9Gb2xsb3cudHMiXSwibmFtZXMiOlsiZGVidWciLCJGb2xsb3dTZXRDYWxjdWxhdG9yIiwiY29uc3RydWN0b3IiLCJncmFtbWFyIiwiZmlyc3RTZXRDYWxjdWxhdG9yIiwiQ3ljbGljRGVwc0RlY3RvciIsIk1hcCIsInRocm93RXJyb3IiLCJob2xkZXIiLCJvdGhlciIsIkVycm9yIiwiZ2V0Rm9sbG93U2V0IiwidGFyZ2V0IiwiY2FjaGUiLCJoYXMiLCJnZXQiLCJub25fdGVybWluYWxzIiwiTlRTIiwiZm9sbG93X3NldCIsIlNldCIsIndoaWNoSGF2ZUFkZGVkRnJpc3RTZXQiLCJ3aGljaEhhdmVBZGRlZEZvbGxvd1NldCIsImFkZCIsIkVPRiIsImkiLCJsZW5ndGgiLCJub25fdGVybWluYWwiLCJqIiwicHJvZHMiLCJwcm9kIiwic2VhcmNoaW5nIiwiayIsImN5Y2xpY0RlY3RvciIsInJlZ2lzdGVyQW5kQ2hlY2tDeWNsIiwibmFtZSIsImZvbGxvd2VyIiwiZm9sbG93ZXJGaXJzdFNldCIsImdldEZpcnN0U2V0IiwiTklMIiwiZGVsZXRlIiwic2V0IiwiZ2V0Rm9sbG93VGFibGUiLCJmb2xsb3dUYWJsZSIsImZvbGxvd1NldCJdLCJtYXBwaW5ncyI6Ijs7Ozs7OztBQUFBOztBQUNBOztBQUVBOztBQUNBOzs7Ozs7QUFHQSxJQUFJQSxLQUFLLEdBQUcsb0JBQVUsWUFBVixDQUFaOztBQUVPLE1BQU1DLG1CQUFOLENBQTBCO0FBRTBCO0FBSzFEQyxFQUFBQSxXQUFXLENBQUNDLE9BQUQsRUFBb0JDLGtCQUFwQixFQUE0RDtBQUFBLDBDQUxoRCxJQUFJQyx5QkFBSixFQUtnRDs7QUFBQSxtQ0FKdkQsSUFBSUMsR0FBSixFQUl1RDs7QUFBQTs7QUFBQTs7QUFDdEUsU0FBS0gsT0FBTCxHQUFlQSxPQUFmO0FBQ0EsU0FBS0Msa0JBQUwsR0FBMEJBLGtCQUExQjtBQUNBOztBQUNPRyxFQUFBQSxVQUFSLENBQW1CQyxNQUFuQixFQUF3Q0MsS0FBeEMs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R0FBWixDQUFnQmQsWUFBWSxDQUFDUSxJQUE3QixFQUFtQ1MsU0FBbkM7QUFDQTs7QUFDRCxXQUFPRCxXQUFQO0FBQ0E7O0FBMUcrQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGFkZEFsbF9TZXQgYXMgYWRkQWxsIH0gZnJvbSBcIkBsaWdodDB4MDAvc2hpbVwiO1xuaW1wb3J0IHsgRU9GLCBOSUwgfSBmcm9tIFwiQGxpZ2h0MHgwMC9wYXJzZXItZGVmaW5pdGlvblwiO1xuaW1wb3J0IHsgTm9uVGVybWluYWwsIFRlcm1pbmFsLCBJR3JhbW1hciwgU3ltYm9sIH0gZnJvbSBcIi4vRGVmaW5pdGlvblwiO1xuaW1wb3J0IHJvb3REZWJ1ZyBmcm9tIFwiZGVidWdcIjtcbmltcG9ydCB7IEN5Y2xpY0RlcHNEZWN0b3IgfSBmcm9tIFwiLi9Ub29sa2l0XCI7XG5pbXBvcnQgeyBGaXJzdFNldENhbGN1bGF0b3IgfSBmcm9tIFwiLi9GaXJzdFwiO1xuXG5sZXQgZGVidWcgPSByb290RGVidWcoXCJBUFA6Zm9sbG93XCIpO1xuXG5leHBvcnQgY2xhc3MgRm9sbG93U2V0Q2FsY3VsYXRvciB7XG5cblx0cHJpdmF0ZSBjeWNsaWNEZWN0b3IgPSBuZXcgQ3ljbGljRGVwc0RlY3RvcjxOb25UZXJtaW5hbD4oKS8vIGlzc3VlOiA5LuW+queOr+S+nei1llxuXHRwcml2YXRlIGNhY2hlID0gbmV3IE1hcDxOb25UZXJtaW5hbCwgU2V0PFRlcm1pbmFsPj4oKVxuXHRwcml2YXRlIGZpcnN0U2V0Q2FsY3VsYXRvcjogRmlyc3RTZXRDYWxjdWxhdG9yXG5cdHByaXZhdGUgZ3JhbW1hcjogSUdyYW1tYXJcblxuXHRjb25zdHJ1Y3RvcihncmFtbWFyOiBJR3JhbW1hciwgZmlyc3RTZXRDYWxjdWxhdG9yOiBGaXJzdFNldENhbGN1bGF0b3IpIHtcblx0XHR0aGlzLmdyYW1tYXIgPSBncmFtbWFyO1xuXHRcdHRoaXMuZmlyc3RTZXRDYWxjdWxhdG9yID0gZmlyc3RTZXRDYWxjdWxhdG9yO1xuXHR9XG5cdHByaXZhdGUgdGhyb3dFcnJvcihob2xkZXI6IE5vblRlcm1pbmFsLCBvdGhlcjogTm9uVGVybWluYWwpIHtcblx0XHR0aHJvdyBuZXcgRXJyb3IoYEN5Y2xpYyBkZXBlbmRlbmNpZXMgYXJlIGRldGVjdGVkIGJldHdlZW4gdGhlIG5vbi10ZXJtaW5hbCAke2hvbGRlcn0gYW5kICR7b3RoZXJ9ICB3aGVuIGNhbGN1bGF0aW5nIHRoZSBmb2xsb3cgc2V0IG9mICR7aG9sZGVyfSFgKTtcblx0fVxuXHQvKlxuICAgIOe6puWumjpcbiAgICBq6KGo56S65b2T5YmN5q2j5Zyo5aSE55CG55qE5Lqn55Sf5byPKHByb2QpXG4gICAga+ihqOekuuW9k+WJjeato+WcqOWkhOeQhueahOespuWPtyhq5Lit55qE5LiA5Liq56ym5Y+3KVxuICAgIGsrbuihqOekuuW9k+WJjeespuWPt2vlkI7nmoRu5Liq56ym5Y+3XG5cbiAgICDkvKrku6PnoIE6XG4gICAga+aYr+WQpuS4umrmnKvlsL7nrKblj7dcbiAgICAgICAgLSDmmK8sIOWKoOWFpUZvbGxvdyhqKVxuICAgICAgICAtIOS4jeaYryzliqDlhaUgKEZpcnN0KGsrMSkte861fSlcbiAgICAgICAgICAgIC0g5aaC5p6cIM61IOKIiCBGaXJzdChrKzEpIOWImee7p+e7reWKoOWFpSBGaXJzdChrKzIpKS5cbiAgICAgICAgICAgICAgICDlubbph43lpI3ov5nkuIDov4fnqIss55u05Yiw56ysbuS4qua7oei2s861IOKIiSBGaXJzdChrK24pLFxuICAgICAgICAgICAgICAgIOWmguaenOespuWPtyhrK24p55u05YiwaueahOacgOWQjuS4gOS4quespuWPt+i/mOS7jeaXp+WtmOWcqCDOtSDiiIggRmlyc3QoaytuKSwg5YiZ5Yqg5YWlRm9sbG93KGopXG5cbiAgICDms6g65Lyq5Luj56CB5LuF5L6b5Y+C6ICDLOS4gOWIh+S7peWunueJqeS4uuWHhiFcbiAgICAqL1xuXHRnZXRGb2xsb3dTZXQodGFyZ2V0OiBOb25UZXJtaW5hbCk6IFNldDxUZXJtaW5hbD4ge1xuXHRcdGlmICh0aGlzLmNhY2hlLmhhcyh0YXJnZXQpKSB7XG5cdFx0XHRkZWJ1ZyhgY2FjaGUgaGl0OiR7dGFyZ2V0fWApO1xuXHRcdFx0cmV0dXJuIHRoaXMuY2FjaGUuZ2V0KHRhcmdldCkhO1xuXHRcdH1cblxuXHRcdGxldCBub25fdGVybWluYWxzID0gdGhpcy5ncmFtbWFyLk5UUygpO1xuXG5cdFx0bGV0IGZvbGxvd19zZXQgPSBuZXcgU2V0PFRlcm1pbmFsPigpO1xuXHRcdGxldCB3aGljaEhhdmVBZGRlZEZyaXN0U2V0ID0gbmV3IFNldDxTeW1ib2w+KCk7IC8v6K6w5b2V5bey57uP5re75Yqg6L+H5ZOq5Lqb56ym5Y+355qERmlyc3Tpm4Zcblx0XHRsZXQgd2hpY2hIYXZlQWRkZWRGb2xsb3dTZXQgPSBuZXcgU2V0PFN5bWJvbD4oKTsgLy/orrDlvZXlt7Lnu4/mt7vliqDov4flk6rkupvnrKblj7fnmoRGb2xsb3fpm4ZcblxuXHRcdGlmIChub25fdGVybWluYWxzWzBdID09IHRhcmdldCkgeyAgLy8gaWYgc3RhcnQgc3ltYm9sXG5cdFx0XHRmb2xsb3dfc2V0LmFkZChFT0YpO1xuXHRcdFx0ZGVidWcoYCtFT0YgaXMgYWRkZWQgYmVjYXVzZSAke3RhcmdldH0gaXMgdGhlIGJlZ2lubmluZyBzeW1ib2xgKTtcblx0XHR9XG5cdFx0Ly/mr4/kuIDkuKrpnZ7nu4jnu5PnrKZpXG5cdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCBub25fdGVybWluYWxzLmxlbmd0aDsgaSsrKSB7XG5cdFx0XHRsZXQgbm9uX3Rlcm1pbmFsID0gbm9uX3Rlcm1pbmFsc1tpXTtcblxuXHRcdFx0Ly/nu4jnu5PnrKbkuK3nmoTmr4/kuIDkuKrkuqfnlJ/lvI9qXG5cdFx0XHRmb3IgKGxldCBqID0gMDsgaiA8IG5vbl90ZXJtaW5hbC5wcm9kcy5sZW5ndGg7IGorKykge1xuXHRcdFx0XHRsZXQgcHJvZCA9IG5vbl90ZXJtaW5hbC5wcm9kc1tqXTtcblx0XHRcdFx0ZGVidWcoYFNjYW5uaW5nICR7dGFyZ2V0fSBpbiBwcm9kdWN0aW9uOiR7cHJvZH1gKTtcblxuXHRcdFx0XHRsZXQgc2VhcmNoaW5nID0gZmFsc2U7IC8v5qCH6K6w5piv5ZCm5aSE5LqO5pCc57Si54q25oCBIGlzc3VlOiAgNS4g6L+e57ut6YeN5aSNXG5cdFx0XHRcdC8v5q+P5LiA5Liq56ym5Y+3a1xuXHRcdFx0XHRmb3IgKGxldCBrID0gMDsgayA8IHByb2QubGVuZ3RoOyBrKyspIHtcblx0XHRcdFx0XHRpZiAocHJvZFtrXSAhPSB0YXJnZXQgJiYgIXNlYXJjaGluZykgeyAvL+mdnuaQnOe0oueKtuaAgSzkuJTpnZ50YXJnZXQs5YiZ6Lez6L+HICAgaXNzdWU6ICA1LiDov57nu63ph43lpI1cblx0XHRcdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHQvL2vkuLpq55qE5pyr5bC+56ym5Y+3XG5cdFx0XHRcdFx0aWYgKGsgPT0gcHJvZC5sZW5ndGggLSAxKSB7XG5cdFx0XHRcdFx0XHRpZiAobm9uX3Rlcm1pbmFsICE9IHRhcmdldCAmJiAhd2hpY2hIYXZlQWRkZWRGb2xsb3dTZXQuaGFzKG5vbl90ZXJtaW5hbCkpIHsgICAvL2lzc3VlOiA2LDcg6Ieq6YCS5b2SICYmIOmHjeWkjea3u+WKoFxuXHRcdFx0XHRcdFx0XHRpZiAodGhpcy5jeWNsaWNEZWN0b3IucmVnaXN0ZXJBbmRDaGVja0N5Y2wodGFyZ2V0LCBub25fdGVybWluYWwpKSAvLyBpc3N1ZTogOS7lvqrnjq/kvp3otZYg6Lez6L+HXG5cdFx0XHRcdFx0XHRcdFx0Y29udGludWU7XG5cdFx0XHRcdFx0XHRcdGRlYnVnKGArU2luY2UgJHt0YXJnZXQubmFtZX0gaXMgYXQgdGhlIGVuZCBvZiBwcm9kdWN0aW9uICR7cHJvZC5uYW1lfSxhZGQgRm9sbG93KCR7bm9uX3Rlcm1pbmFsLm5hbWV9KWApO1xuXHRcdFx0XHRcdFx0XHRhZGRBbGwoZm9sbG93X3NldCwgdGhpcy5nZXRGb2xsb3dTZXQobm9uX3Rlcm1pbmFsKSk7XG5cdFx0XHRcdFx0XHRcdHdoaWNoSGF2ZUFkZGVkRm9sbG93U2V0LmFkZChub25fdGVybWluYWwpOyAvL+agh+iusEZvbGxvdyhwKeW3sua3u+WKoFxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHNlYXJjaGluZyA9IHRydWU7XG5cdFx0XHRcdFx0Ly/lpITnkIZrKzFcblx0XHRcdFx0XHRsZXQgZm9sbG93ZXIgPSBwcm9kW2sgKyAxXTtcblx0XHRcdFx0XHRpZiAod2hpY2hIYXZlQWRkZWRGcmlzdFNldC5oYXMoZm9sbG93ZXIpKSAgLy9pc3N1ZTogNi4g6YeN5aSN5re75YqgXG5cdFx0XHRcdFx0XHRjb250aW51ZTtcblx0XHRcdFx0XHRsZXQgZm9sbG93ZXJGaXJzdFNldCA9IHRoaXMuZmlyc3RTZXRDYWxjdWxhdG9yLmdldEZpcnN0U2V0KGZvbGxvd2VyKTtcblxuXHRcdFx0XHRcdHdoaWNoSGF2ZUFkZGVkRnJpc3RTZXQuYWRkKGZvbGxvd2VyKTsgLy/moIforrAgRmlyc3QoaysxKeS4uuW3sua3u+WKoFxuXHRcdFx0XHRcdC8v5aaC5p6cOiDOtSDiiIggRmlyc3QoaysxKVxuXHRcdFx0XHRcdGlmIChmb2xsb3dlckZpcnN0U2V0LmhhcyhOSUwpKSB7XG5cdFx0XHRcdFx0XHRhZGRBbGwoZm9sbG93X3NldCwgZm9sbG93ZXJGaXJzdFNldCk7XG5cdFx0XHRcdFx0XHRmb2xsb3dfc2V0LmRlbGV0ZShOSUwpO1xuXHRcdFx0XHRcdFx0ZGVidWcoYCtUaGUgc3ltYm9sICR7Zm9sbG93ZXJ9IGZvbGxvd3MgJHt0YXJnZXR9LGFkZCBGaXJzdCgke2ZvbGxvd2VyfSkte/CdnbR9LCBkdWUgJHtmb2xsb3dlcn0gY29udGFpbnMg8J2dtCAsc2NhbiB0aGUgZm9sbG93aW5nIHN5bWJvbCBvZiAke2ZvbGxvd2VyfSBgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0Ly/lpoLmnpwgzrUg4oiJIEZpcnN0KGsrMSlcblx0XHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHRcdGFkZEFsbChmb2xsb3dfc2V0LCBmb2xsb3dlckZpcnN0U2V0KTtcblx0XHRcdFx0XHRcdGRlYnVnKGArVGhlIHN5bWJvbCAke2ZvbGxvd2VyfSBmb2xsb3dzICR7dGFyZ2V0fSxhZGQgRmlyc3QoJHtmb2xsb3dlcn0pYCk7XG5cdFx0XHRcdFx0XHRzZWFyY2hpbmcgPSBmYWxzZTsgIC8vaysx5LiN5Y+v5o6o5Ye68J2dtCDliJnnu5PmnZ/mkJzntKLnirbmgIEgICAgaXNzdWU6ICA1LiDov57nu63ph43lpI1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdFx0dGhpcy5jYWNoZS5zZXQodGFyZ2V0LCBmb2xsb3dfc2V0KTtcblx0XHRyZXR1cm4gZm9sbG93X3NldDtcblx0fVxuXG5cdGdldEZvbGxvd1RhYmxlKCk6IEZvbGxvd1NldFRhYmxlIHtcblx0XHRsZXQgZm9sbG93VGFibGUgPSBuZXcgTWFwPHN0cmluZywgU2V0PFRlcm1pbmFsPj4oKTtcblx0XHRmb3IgKGxldCBub25fdGVybWluYWwgb2YgdGhpcy5ncmFtbWFyLk5UUygpKSB7XG5cdFx0XHRsZXQgZm9sbG93U2V0ID0gdGhpcy5nZXRGb2xsb3dTZXQobm9uX3Rlcm1pbmFsKTtcblx0XHRcdGZvbGxvd1RhYmxlLnNldChub25fdGVybWluYWwubmFtZSwgZm9sbG93U2V0KTtcblx0XHR9XG5cdFx0cmV0dXJuIGZvbGxvd1RhYmxlO1xuXHR9XG59XG5leHBvcnQgdHlwZSBGb2xsb3dTZXQgPSBTZXQ8VGVybWluYWw+O1xuZXhwb3J0IHR5cGUgRm9sbG93U2V0VGFibGUgPSBNYXA8c3RyaW5nLCBTZXQ8VGVybWluYWw+PjtcblxuIl19