updating to the latest Jison

This commit is contained in:
Jeremy Ashkenas
2010-02-23 21:03:05 -05:00
parent 52db4fbf8c
commit c30b3d3c48
7 changed files with 94 additions and 77 deletions

File diff suppressed because one or more lines are too long

View File

@@ -369,8 +369,8 @@ lookaheadMixin.followSets = function followSets () {
var part = production.handle.slice(i+1);
set = self.first(part);
if (set.length === 0 && bool) { // set was nullable
set = nonterminals[production.symbol].follows;
if (self.nullable(part) && bool) {
set.push.apply(set, nonterminals[production.symbol].follows);
}
}
oldcount = nonterminals[t].follows.length;
@@ -838,7 +838,7 @@ lrGeneratorMixin.generateModule = function generateModule (opt) {
var out = "/* Jison generated parser */\n";
out += (moduleName.match(/\./) ? moduleName : "var "+moduleName)+" = (function(){";
out += "\nvar parser = "+this.generateModule_();
if (this.lexer) {
if (this.lexer && this.lexer.generateModule) {
out += this.lexer.generateModule();
out += "\nparser.lexer = lexer;";
}

View File

@@ -57,6 +57,9 @@ function buildActions (dict, tokens) {
}
function RegExpLexer (dict, input, tokens) {
if (typeof dict === 'string') {
dict = require("./jisonlex").parse(dict);
}
dict = dict || {};
this.performAction = buildActions.call(this, dict, tokens);

View File

@@ -138,8 +138,6 @@ parse: function parse(input) {
var symbol, state, action, a, r, yyval = {}, p, len, ip = 0, newState, expected;
symbol = lex();
while (true) {
this.trace("stack:", JSON.stringify(stack), "\n\t\t\tinput:", this.lexer._input);
this.trace("vstack:", JSON.stringify(vstack));
state = stack[stack.length - 1];
action = table[state] && table[state][symbol];
if (typeof action == "undefined" || !action.length || !action[0]) {
@@ -149,11 +147,11 @@ parse: function parse(input) {
expected.push("'" + this.terminals_[p] + "'");
}
}
self.trace("stack:", JSON.stringify(stack), "symbol:", symbol, "input", this.lexer.upcomingInput());
if (this.lexer.upcomingInput) {
self.trace("input", this.lexer.upcomingInput());
if (this.lexer.showPosition) {
parseError("Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", "), {text: this.lexer.match, token: this.terminals_[symbol], line: this.lexer.yylineno, expected: expected});
} else {
parseError("Parse error on line " + (yylineno + 1) + ": Unexpected '" + this.terminals_[symbol] + "'", {text: this.lexer.match, token: this.terminals_[symbol], line: this.lexer.yylineno, expected: expected});
}
parseError("Parse error on line " + (yylineno + 1) + ". Expecting: " + expected.join(", ") + "\n" + (this.lexer.showPosition && this.lexer.showPosition()), {text: this.lexer.match, token: symbol, line: this.lexer.yylineno});
}
this.trace("action:", action);
if (action.length > 1) {
@@ -175,15 +173,12 @@ parse: function parse(input) {
case 2:
reductions++;
len = this.productions_[a[1]][1];
this.trace("reduce by: ", this.productions ? this.productions[a[1]] : a[1]);
yyval.$ = vstack[vstack.length - len];
r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, a[1], vstack);
if (typeof r !== "undefined") {
return r;
}
this.trace("yyval=", JSON.stringify(yyval.$));
if (len) {
this.trace("production length:", len);
stack = stack.slice(0, -1 * len * 2);
vstack = vstack.slice(0, -1 * len);
}
@@ -193,10 +188,8 @@ parse: function parse(input) {
stack.push(newState);
break;
case 3:
this.trace("stack:", stack, "\n\tinput:", this.lexer._input);
this.trace("vstack:", JSON.stringify(vstack));
this.trace("Total reductions:", reductions);
this.trace("Total shifts:", shifts);
this.reductionCount = reductions;
this.shiftCount = shifts;
return true;
default:;
}

View File

@@ -134,8 +134,6 @@ parse: function parse(input) {
var symbol, state, action, a, r, yyval = {}, p, len, ip = 0, newState, expected;
symbol = lex();
while (true) {
this.trace("stack:", JSON.stringify(stack), "\n\t\t\tinput:", this.lexer._input);
this.trace("vstack:", JSON.stringify(vstack));
state = stack[stack.length - 1];
action = table[state] && table[state][symbol];
if (typeof action == "undefined" || !action.length || !action[0]) {
@@ -145,11 +143,11 @@ parse: function parse(input) {
expected.push("'" + this.terminals_[p] + "'");
}
}
self.trace("stack:", JSON.stringify(stack), "symbol:", symbol, "input", this.lexer.upcomingInput());
if (this.lexer.upcomingInput) {
self.trace("input", this.lexer.upcomingInput());
if (this.lexer.showPosition) {
parseError("Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", "), {text: this.lexer.match, token: this.terminals_[symbol], line: this.lexer.yylineno, expected: expected});
} else {
parseError("Parse error on line " + (yylineno + 1) + ": Unexpected '" + this.terminals_[symbol] + "'", {text: this.lexer.match, token: this.terminals_[symbol], line: this.lexer.yylineno, expected: expected});
}
parseError("Parse error on line " + (yylineno + 1) + ". Expecting: " + expected.join(", ") + "\n" + (this.lexer.showPosition && this.lexer.showPosition()), {text: this.lexer.match, token: symbol, line: this.lexer.yylineno});
}
this.trace("action:", action);
if (action.length > 1) {
@@ -171,15 +169,12 @@ parse: function parse(input) {
case 2:
reductions++;
len = this.productions_[a[1]][1];
this.trace("reduce by: ", this.productions ? this.productions[a[1]] : a[1]);
yyval.$ = vstack[vstack.length - len];
r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, a[1], vstack);
if (typeof r !== "undefined") {
return r;
}
this.trace("yyval=", JSON.stringify(yyval.$));
if (len) {
this.trace("production length:", len);
stack = stack.slice(0, -1 * len * 2);
vstack = vstack.slice(0, -1 * len);
}
@@ -189,10 +184,8 @@ parse: function parse(input) {
stack.push(newState);
break;
case 3:
this.trace("stack:", stack, "\n\tinput:", this.lexer._input);
this.trace("vstack:", JSON.stringify(vstack));
this.trace("Total reductions:", reductions);
this.trace("Total shifts:", shifts);
this.reductionCount = reductions;
this.shiftCount = shifts;
return true;
default:;
}

View File

@@ -403,3 +403,15 @@ exports["test DJ lexer"] = function() {
assert.equal(typeof tok, "string");
}
};
exports["test instantiation from string"] = function() {
var dict = "%%\n'x' {return 'X';}\n'y' {return 'Y';}\n<<EOF>> {return 'EOF';}";
var input = "x";
var lexer = new RegExpLexer(dict);
lexer.setInput(input);
assert.equal(lexer.lex(), "X");
assert.equal(lexer.lex(), "EOF");
};

View File

@@ -167,3 +167,17 @@ exports["test LR(1) grammar"] = function () {
var gen = new Jison.Generator(grammar, {type: "lalr"});
assert.equal(gen.conflicts, 2);
};
exports["test BNF grammar bootstrap"] = function () {
var grammar = "%%\n\nspec\n : declaration_list '%%' grammar EOF\n {$$ = $1; $$.bnf = $3; return $$;}\n | declaration_list '%%' grammar '%%' EOF\n {$$ = $1; $$.bnf = $3; return $$;}\n ;\n\ndeclaration_list\n : declaration_list declaration\n {$$ = $1; yy.addDeclaration($$, $2);}\n | \n <$$ = {};>\n ;\n\ndeclaration\n : START id\n <$$ = {start: $2};>\n | operator\n <$$ = {operator: $1};>\n ;\n\noperator\n : associativity token_list\n {$$ = [$1]; $$.push.apply($$, $2);}\n ;\n\nassociativity\n : LEFT\n {$$ = 'left';}\n | RIGHT\n {$$ = 'right';}\n | NONASSOC\n {$$ = 'nonassoc';}\n ;\n\ntoken_list\n : token_list symbol\n {$$ = $1; $$.push($2);}\n | symbol\n {$$ = [$1];}\n ;\n\ngrammar\n : production_list\n {$$ = $1;}\n ;\n\nproduction_list\n : production_list production\n {$$ = $1; $$[$2[0]] = $2[1];}\n | production\n <$$ = {}; $$[$1[0]] = $1[1];>\n ;\n\nproduction\n : id ':' handle_list ';'\n {$$ = [$1, $3];}\n ;\n\nhandle_list\n : handle_list '|' handle_action\n {$$ = $1; $$.push($3);}\n | handle_action\n {$$ = [$1];}\n ;\n\nhandle_action\n : handle action prec\n {$$ = [($1.length ? $1.join(' ') : '')];\n if($2) $$.push($2);\n if($3) $$.push($3);\n if ($$.length === 1) $$ = $$[0];\n }\n ;\n\nhandle\n : handle symbol\n {$$ = $1; $$.push($2)}\n | \n {$$ = [];}\n ;\n\nprec\n : PREC symbol\n <$$ = {prec: $2};>\n | \n {$$ = null;}\n ;\n\nsymbol\n : id\n {$$ = $1;}\n | STRING\n {$$ = yytext;}\n ;\n\nid\n : ID\n {$$ = yytext;}\n ;\n\naction\n : ACTION\n {$$ = yytext;}\n | \n {$$ = '';}\n ;\n\n";
var lex = "\n%%\n\\s+ \t{/* skip whitespace */}\n\"/*\"[^*]*\"*\" \t{return yy.lexComment(this);}\n[a-zA-Z][a-zA-Z0-9_-]* \t{return 'ID';}\n'\"'[^\"]+'\"' \t{yytext = yytext.substr(1, yyleng-2); return 'STRING';}\n\"'\"[^']+\"'\" \t{yytext = yytext.substr(1, yyleng-2); return 'STRING';}\n\":\" \t{return ':';}\n\";\" \t{return ';';}\n\"|\" \t{return '|';}\n\"%%\" \t{return '%%';}\n\"%prec\" \t{return 'PREC';}\n\"%start\" \t{return 'START';}\n\"%left\" \t{return 'LEFT';}\n\"%right\" \t{return 'RIGHT';}\n\"%nonassoc\" \t{return 'NONASSOC';}\n\"%\"[a-zA-Z]+[^\\n]* \t{/* ignore unrecognized decl */}\n\"{{\"[^}]*\"}\" \t{return yy.lexAction(this);}\n\"{\"[^}]*\"}\" \t{yytext = yytext.substr(1, yyleng-2); return 'ACTION';}\n\"<\"[^>]*\">\" \t{yytext = yytext.substr(1, yyleng-2); return 'ACTION';}\n. \t{/* ignore bad characters */}\n<<EOF>> \t{return 'EOF';}\n\n%%\n\n";
var gen = new Jison.Generator(grammar, {type: "lalr"});
gen.lexer = new Lexer(lex);
var parser = gen.createParser();
assert.ok(parser.parse(grammar), "bootstrapped bnf parser should parse correctly.");
};