Skip to content

Commit

Permalink
release 1.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Mike_Device committed Oct 12, 2016
1 parent cc28384 commit 065f97f
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 164 deletions.
5 changes: 4 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
{
"extends": "dvpnt"
"extends": "dvpnt",
"globals": {
"define": true
}
}
332 changes: 170 additions & 162 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,201 +1,209 @@
'use strict';

var _ = require('underscore');

var Grammar = function(rules) {
this.rules = rules || [];
this.endMarker = '\0';

this.nonterminals = this._getNonterminals();
this.nonterminalsHash = _(this.nonterminals).indexBy();
this.terminals = this._getTerminals();

this.firstSetHash = this.makeFirstSet();
this.followSetHash = this.makeFollowSet();
this.predictSets = this.makePredictSet();
};

Grammar.prototype._getNonterminals = function() {
return _(this.rules).chain()
.pluck('left')
.uniq()
.value();
};

Grammar.prototype._getTerminals = function() {
var self = this,
terminals = [];

_(this.rules).each(function(rule) {
_(rule.right).each(function(item) {
if (self.isTerminal()) {
terminals.push(item);
}
(function(root, factory) {
if (typeof exports === 'object') {
module.exports = factory(require('underscore'));
} else if (typeof define === 'function' && define.amd) {
define(['underscore'], factory);
} else {
root.Grammar = factory(root._).Grammar;
}
}(this, function(_) {
var Grammar = function(rules) {
this.rules = rules || [];
this.endMarker = '\0';

this.nonterminals = this._getNonterminals();
this.nonterminalsHash = _(this.nonterminals).indexBy();
this.terminals = this._getTerminals();

this.firstSetHash = this.makeFirstSet();
this.followSetHash = this.makeFollowSet();
this.predictSets = this.makePredictSet();
};

Grammar.prototype._getNonterminals = function() {
return _(this.rules).chain()
.pluck('left')
.uniq()
.value();
};

Grammar.prototype._getTerminals = function() {
var self = this,
terminals = [];

_(this.rules).each(function(rule) {
_(rule.right).each(function(item) {
if (self.isTerminal()) {
terminals.push(item);
}
});
});
});

return terminals;
};
return terminals;
};

Grammar.prototype._initSetHash = function() {
var setHash = {};
Grammar.prototype._initSetHash = function() {
var setHash = {};

_(this.nonterminals).each(function(nonterminal) {
setHash[nonterminal] = [];
});
_(this.nonterminals).each(function(nonterminal) {
setHash[nonterminal] = [];
});

return setHash;
};
return setHash;
};

Grammar.prototype.isNonterminal = function(item) {
return this.nonterminalsHash[item];
};
Grammar.prototype.isNonterminal = function(item) {
return this.nonterminalsHash[item];
};

Grammar.prototype.isTerminal = function(item) {
return item && !this.isNonterminal(item);
};
Grammar.prototype.isTerminal = function(item) {
return item && !this.isNonterminal(item);
};

Grammar.prototype.getFirstSetHash = function() {
return this.firstSetHash;
};
Grammar.prototype.getFirstSetHash = function() {
return this.firstSetHash;
};

Grammar.prototype.getFollowSetHash = function() {
return this.followSetHash;
};
Grammar.prototype.getFollowSetHash = function() {
return this.followSetHash;
};

Grammar.prototype.getPredictSets = function() {
return this.predictSets;
};
Grammar.prototype.getPredictSets = function() {
return this.predictSets;
};

Grammar.prototype.makeFirstSet = function() {
var self = this,
firstSetHash = this._initSetHash(),
isSetChanged;
Grammar.prototype.makeFirstSet = function() {
var self = this,
firstSetHash = this._initSetHash(),
isSetChanged;

do {
isSetChanged = false;
do {
isSetChanged = false;

_(this.rules).each(function(rule) {
var nonterminal = rule.left,
set = firstSetHash[nonterminal];
_(this.rules).each(function(rule) {
var nonterminal = rule.left,
set = firstSetHash[nonterminal];

_(rule.right).every(function(item, index) {
if (self.isNonterminal(item)) {
set = _.union(set, _(firstSetHash[item]).compact());
_(rule.right).every(function(item, index) {
if (self.isNonterminal(item)) {
set = _.union(set, _(firstSetHash[item]).compact());

var nextItem = rule.right[index + 1];
var nextItem = rule.right[index + 1];

if (_(firstSetHash[item]).contains(null)) {
if (nextItem) return true;
if (_(firstSetHash[item]).contains(null)) {
if (nextItem) return true;
set = _.union(set, [null]);
}

} else if (self.isTerminal(item)) {
set = _.union(set, [item]);
} else {
set = _.union(set, [null]);
}
});

} else if (self.isTerminal(item)) {
set = _.union(set, [item]);
} else {
set = _.union(set, [null]);
if (firstSetHash[nonterminal].length !== set.length) {
firstSetHash[nonterminal] = set;
isSetChanged = true;
}
});
} while (isSetChanged);

if (firstSetHash[nonterminal].length !== set.length) {
firstSetHash[nonterminal] = set;
isSetChanged = true;
}
});
} while (isSetChanged);
return firstSetHash;
};

return firstSetHash;
};
Grammar.prototype.makeFollowSet = function() {
var self = this,
startNonterminal = this.rules[0].left,
followSetHash = this._initSetHash(),
isSetChanged;

Grammar.prototype.makeFollowSet = function() {
var self = this,
startNonterminal = this.rules[0].left,
followSetHash = this._initSetHash(),
isSetChanged;
followSetHash[startNonterminal].push(this.endMarker);

followSetHash[startNonterminal].push(this.endMarker);
do {
isSetChanged = false;

do {
isSetChanged = false;
_(this.rules).each(function(rule) {
_(rule.right).each(function(item, index) {
if (!self.isNonterminal(item)) return;

_(this.rules).each(function(rule) {
_(rule.right).each(function(item, index) {
if (!self.isNonterminal(item)) return;
var nonterminal = rule.left,
set = followSetHash[item],
restItems = _(rule.right).rest(index + 1);

var nonterminal = rule.left,
set = followSetHash[item],
restItems = _(rule.right).rest(index + 1);

if (restItems.length) {
_(restItems).every(function(item, index) {
if (self.isNonterminal(item)) {
set = _.union(set, _(self.firstSetHash[item]).compact());
var nextItem = restItems[index + 1];

if (_(self.firstSetHash[item]).contains(null)) {
if (nextItem) return true;
set = _.union(set, followSetHash[nonterminal]);
}
if (restItems.length) {
_(restItems).every(function(item, index) {
if (self.isNonterminal(item)) {
set = _.union(set, _(self.firstSetHash[item]).compact());
var nextItem = restItems[index + 1];

} else {
set = _.union(set, [item]);
}
});
} else {
set = _.union(set, followSetHash[nonterminal]);
}
if (followSetHash[item].length !== set.length) {
followSetHash[item] = set;
isSetChanged = true;
}
if (_(self.firstSetHash[item]).contains(null)) {
if (nextItem) return true;
set = _.union(set, followSetHash[nonterminal]);
}

} else {
set = _.union(set, [item]);
}
});
} else {
set = _.union(set, followSetHash[nonterminal]);
}
if (followSetHash[item].length !== set.length) {
followSetHash[item] = set;
isSetChanged = true;
}
});
});
});
} while (isSetChanged);
return followSetHash;
};

Grammar.prototype.makePredictSet = function() {
var self = this,
predictSets = [];

_(this.rules).each(function(rule, ruleIndex) {
predictSets.push([]);

var items = rule.right,
nonterminal = rule.left,
firstItem = items[0];

if (self.isTerminal(firstItem)) {
predictSets[ruleIndex].push(firstItem);
} else if (self.isNonterminal(firstItem)) {
_(rule.right).every(function(item, index) {
if (self.isNonterminal(item)) {
predictSets[ruleIndex] = _.union(
predictSets[ruleIndex],
_(self.firstSetHash[item]).compact()
);

if (_(self.firstSetHash[item]).contains(null)) {
if (rule.right[index + 1]) return true;
} while (isSetChanged);
return followSetHash;
};

Grammar.prototype.makePredictSet = function() {
var self = this,
predictSets = [];

_(this.rules).each(function(rule, ruleIndex) {
predictSets.push([]);

var items = rule.right,
nonterminal = rule.left,
firstItem = items[0];

if (self.isTerminal(firstItem)) {
predictSets[ruleIndex].push(firstItem);
} else if (self.isNonterminal(firstItem)) {
_(rule.right).every(function(item, index) {
if (self.isNonterminal(item)) {
predictSets[ruleIndex] = _.union(
predictSets[ruleIndex],
_(self.firstSetHash[item]).compact()
);

if (_(self.firstSetHash[item]).contains(null)) {
if (rule.right[index + 1]) return true;

predictSets[ruleIndex] = _.union(
predictSets[ruleIndex],
self.followSetHash[nonterminal]
);
}
} else {
predictSets[ruleIndex] = _.union(
predictSets[ruleIndex],
self.followSetHash[nonterminal]
[item]
);
}
} else {
predictSets[ruleIndex] = _.union(
predictSets[ruleIndex],
[item]
);
}
});
} else {
predictSets[ruleIndex] = _(self.followSetHash[nonterminal]).clone();
}
});
});
} else {
predictSets[ruleIndex] = _(self.followSetHash[nonterminal]).clone();
}
});

return predictSets;
};
return predictSets;
};

exports.Grammar = Grammar;
return {Grammar: Grammar};
}));
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "first-follow",
"version": "1.0.0",
"version": "1.1.0",
"description": "Calculator for finding first, follow and predict sets by the grammar",
"main": "index.js",
"scripts": {
Expand Down

0 comments on commit 065f97f

Please sign in to comment.