Add compiler optimization: Remove proxy rules

This shouldn't have measurable effect on the benchmarks as there are no
proxy rules in the grammars the benchamrk uses. However the effect on
generated parsers' speed should be positive generally.
This commit is contained in:
David Majda 2010-05-22 13:11:15 +02:00
parent 33a1a7c1e9
commit 90ed4712e9
2 changed files with 1023 additions and 963 deletions

View file

@ -372,6 +372,82 @@ PEG.Compiler = {
} }
], ],
/*
* Optimalization passes made on the grammar AST before compilation. Each pass
* is a function that is passed the AST and start rule and returns a new AST
* and start rule. The AST can be modified in-place by the pass. The passes
* are run in sequence in order of their definition.
*/
_passes: [
/*
* Removes proxy rules -- that is, rules that only delegate to other rule.
*/
function(ast, startRule) {
function isProxyRule(node) {
return node.type === "rule" && node.expression.type === "rule_ref";
}
function replaceRuleRefs(ast, from, to) {
function nop() {}
function replaceInExpression(node, from, to) {
replace(node.expression, from, to);
}
function replaceInSubnodes(propertyName) {
return function(node, from, to) {
PEG.ArrayUtils.each(node[propertyName], function(node) {
replace(node, from, to);
});
};
}
var replaceFunctions = {
rule: replaceInExpression,
choice: replaceInSubnodes("alternatives"),
sequence: replaceInSubnodes("elements"),
and_predicate: replaceInExpression,
not_predicate: replaceInExpression,
optional: replaceInExpression,
zero_or_more: replaceInExpression,
one_or_more: replaceInExpression,
action: replaceInExpression,
rule_ref:
function(node, from, to) {
if (node.name === from) {
node.name = to;
}
},
literal: nop,
any: nop,
"class": nop
};
function replace(node, from, to) {
replaceFunctions[node.type](node, from, to);
}
for (var rule in ast) {
replace(ast[rule], from, to);
}
}
for (var rule in ast) {
if (isProxyRule(ast[rule])) {
replaceRuleRefs(ast, ast[rule].name, ast[rule].expression.name);
if (rule === startRule) {
startRule = ast[rule].expression.name;
}
delete ast[rule];
}
}
return [ast, startRule];
}
],
_compileFunctions: { _compileFunctions: {
rule: function(node) { rule: function(node) {
var resultVar = PEG.Compiler.generateUniqueIdentifier("result"); var resultVar = PEG.Compiler.generateUniqueIdentifier("result");
@ -787,6 +863,12 @@ PEG.Compiler = {
this._checks[i](ast, startRule); this._checks[i](ast, startRule);
} }
for (var i = 0; i < this._passes.length; i++) {
var newAstNadStartRule = this._passes[i](ast, startRule);
ast = newAstNadStartRule[0];
startRule = newAstNadStartRule[1];
}
var parseFunctionDefinitions = []; var parseFunctionDefinitions = [];
for (var rule in ast) { for (var rule in ast) {
parseFunctionDefinitions.push(this.compileNode(ast[rule])); parseFunctionDefinitions.push(this.compileNode(ast[rule]));

File diff suppressed because it is too large Load diff