Skip to content
Browse files

- add documentation (as comments) to the generated parser; this inclu…

…des a description of the whole structure in a comment at the top of the generated file. (People who don't want this [should] pull the code through a minifier/obfuscator anyway.)

- trivial code duplication removal at the end of the source file.

- use EOF and TERROR constants where applicable for much improved legibility

- some whitespace and semicolon goodness ('pedantic fixes')
  • Loading branch information...
1 parent 17f8d26 commit ef5113fd479bb46a1e89116cab308786dd745edb @GerHobbelt GerHobbelt committed Feb 16, 2013
Showing with 101 additions and 40 deletions.
  1. +101 −40 lib/jison.js
View
141 lib/jison.js
@@ -186,6 +186,7 @@ function processOperators (ops) {
generator.buildProductions = function buildProductions(bnf, productions, nonterminals, symbols, operators) {
var actions = [
+ '/* this == yyval */',
this.actionInclude || '',
'var $0 = $$.length - 1;',
'switch (yystate) {'
@@ -838,7 +839,7 @@ function findDefaults (states) {
}
if (i === 1 && state[act][0] === 2) {
- // only one action in state and it's a reduction
+ // only one action in state and it's a reduction
defaults[k] = state[act];
}
});
@@ -897,20 +898,21 @@ lrGeneratorMixin.generate = function parser_generate (opt) {
switch (opt.moduleType) {
case "js":
code = this.generateModule(opt);
- break;
+ break;
case "amd":
code = this.generateAMDModule(opt);
- break;
+ break;
default:
code = this.generateCommonJSModule(opt);
+ break;
}
return code;
};
lrGeneratorMixin.generateAMDModule = function generateAMDModule(opt){
opt = typal.mix.call({}, this.options, opt);
- var out = 'define([], function(){'
+ var out = '\n\ndefine([], function(){'
+ '\nvar parser = '+ this.generateModule_(opt)
+ (this.lexer && this.lexer.generateModule ?
'\n' + this.lexer.generateModule() +
@@ -924,30 +926,102 @@ lrGeneratorMixin.generateCommonJSModule = function generateCommonJSModule (opt)
opt = typal.mix.call({}, this.options, opt);
var moduleName = opt.moduleName || "parser";
var out = this.generateModule(opt)
- + "\nif (typeof require !== 'undefined' && typeof exports !== 'undefined') {"
+ + "\n\n\nif (typeof require !== 'undefined' && typeof exports !== 'undefined') {"
+ "\nexports.parser = "+moduleName+";"
+ "\nexports.Parser = "+moduleName+".Parser;"
+ "\nexports.parse = function () { return "+moduleName+".parse.apply("+moduleName+", arguments); };"
+ "\nexports.main = "+ String(opt.moduleMain || commonjsMain) + ";"
+ "\nif (typeof module !== 'undefined' && require.main === module) {\n"
+ " exports.main(process.argv.slice(1));\n}"
- + "\n}"
+ + "\n}";
return out;
};
lrGeneratorMixin.generateModule = function generateModule (opt) {
opt = typal.mix.call({}, this.options, opt);
var moduleName = opt.moduleName || "parser";
- var out = "/* parser generated by jison " + version + " */\n";
+ var out = "/* parser generated by jison " + version + " */\n"
+ + "/*\n"
+ + " Returns a Parser object of the following structure:\n"
+ + "\n"
+ + " Parser: {\n"
+ + " yy: {}\n"
+ + " }\n"
+ + "\n"
+ + " Parser.prototype: {\n"
+ + " yy: {},\n"
+ + " trace: function(),\n"
+ + " symbols_: {associative list: name ==> number},\n"
+ + " terminals_: {associative list: number ==> name},\n"
+ + " productions_: [...],\n"
+ + " performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$),\n"
+ + " table: [...],\n"
+ + " defaultActions: {...},\n"
+ + " parseError: function(str, hash),\n"
+ + " parse: function(input),\n"
+ + "\n"
+ + " lexer: {\n"
+ + " EOF: 1,\n"
+ + " parseError: function(str, hash),\n"
+ + " setInput: function(input),\n"
+ + " input: function(),\n"
+ + " unput: function(str),\n"
+ + " more: function(),\n"
+ + " less: function(n),\n"
+ + " pastInput: function(),\n"
+ + " upcomingInput: function(),\n"
+ + " showPosition: function(),\n"
+ + " test_match: function(regex_match_array, rule_index),\n"
+ + " next: function(),\n"
+ + " lex: function(),\n"
+ + " begin: function(condition),\n"
+ + " popState: function(),\n"
+ + " _currentRules: function(),\n"
+ + " topState: function(),\n"
+ + " pushState: function(condition),\n"
+ + "\n"
+ + " options: {\n"
+ + " ranges: boolean (optional: true ==> token location info will include a .range[] member)\n"
+ + " flex: boolean (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match)\n"
+ + " backtrack_lexer: boolean (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code)\n"
+ + " },\n"
+ + "\n"
+ + " performAction: function(yy, yy_, $avoiding_name_collisions, YY_START),\n"
+ + " rules: [...],\n"
+ + " conditions: {associative list: name ==> set},\n"
+ + " }\n"
+ + " }\n"
+ + "\n"
+ + "\n"
+ + " token location info (@$, _$, etc.): {\n"
+ + " first_line: n,\n"
+ + " last_line: n,\n"
+ + " first_column: n,\n"
+ + " last_column: n,\n"
+ + " range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based)\n"
+ + " }\n"
+ + "\n"
+ + "\n"
+ + " the parseError function receives a 'hash' object with these members for lexer and parser errors: {\n"
+ + " text: (matched text)\n"
+ + " token: (the produced terminal token, if any)\n"
+ + " line: (yylineno)\n"
+ + " }\n"
+ + " while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: {\n"
+ + " loc: (yylloc)\n"
+ + " expected: (string describing the set of expected tokens)\n"
+ + " recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error)\n"
+ + " }\n"
+ + "*/\n";
out += (moduleName.match(/\./) ? moduleName : "var "+moduleName)+" = (function(){";
out += "\nvar parser = "+this.generateModule_();
out += "\n"+this.moduleInclude;
if (this.lexer && this.lexer.generateModule) {
out += this.lexer.generateModule();
out += "\nparser.lexer = lexer;";
}
- out += "\nfunction Parser () { this.yy = {}; }"
+ out += "\nfunction Parser () {\n this.yy = {};\n}\n"
+ "Parser.prototype = parser;"
+ "parser.Parser = Parser;"
+ "\nreturn new Parser;\n})();";
@@ -1108,8 +1182,9 @@ parser.parse = function parse (input) {
this.lexer.yy = this.yy;
this.yy.lexer = this.lexer;
this.yy.parser = this;
- if (typeof this.lexer.yylloc == 'undefined')
+ if (typeof this.lexer.yylloc == 'undefined') {
this.lexer.yylloc = {};
+ }
var yyloc = this.lexer.yylloc;
lstack.push(yyloc);
@@ -1119,25 +1194,25 @@ parser.parse = function parse (input) {
this.parseError = this.yy.parseError;
function popStack (n) {
- stack.length = stack.length - 2*n;
+ stack.length = stack.length - 2 * n;
vstack.length = vstack.length - n;
lstack.length = lstack.length - n;
}
function lex() {
var token;
- token = self.lexer.lex() || 1; // $end = 1
+ token = self.lexer.lex() || EOF; // $end = 1
// if token isn't its numeric value, convert
if (typeof token !== 'number') {
token = self.symbols_[token] || token;
}
return token;
}
- var symbol, preErrorSymbol, state, action, a, r, yyval={},p,len,newState, expected;
+ var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;
while (true) {
// retreive state number from top of stack
- state = stack[stack.length-1];
+ state = stack[stack.length - 1];
// use default actions if available
if (this.defaultActions[state]) {
@@ -1150,22 +1225,22 @@ parser.parse = function parse (input) {
action = table[state] && table[state][symbol];
}
+_handle_error:
// handle parse error
- _handle_error:
if (typeof action === 'undefined' || !action.length || !action[0]) {
var errStr = '';
if (!recovering) {
// Report error
expected = [];
- for (p in table[state]) if (this.terminals_[p] && p > 2) {
+ for (p in table[state]) if (this.terminals_[p] && p > TERROR) {
expected.push("'"+this.terminals_[p]+"'");
}
if (this.lexer.showPosition) {
errStr = 'Parse error on line '+(yylineno+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+expected.join(', ') + ", got '" + (this.terminals_[symbol] || symbol)+ "'";
} else {
errStr = 'Parse error on line '+(yylineno+1)+": Unexpected " +
- (symbol == 1 /*EOF*/ ? "end of input" :
+ (symbol == EOF ? "end of input" :
("'"+(this.terminals_[symbol] || symbol)+"'"));
}
this.parseError(errStr,
@@ -1199,7 +1274,7 @@ parser.parse = function parse (input) {
state = stack[stack.length-1];
}
- preErrorSymbol = symbol == 2 ? null : symbol; // save the lookahead token
+ preErrorSymbol = (symbol == TERROR ? null : symbol); // save the lookahead token
symbol = TERROR; // insert generic error symbol as new lookahead
state = stack[stack.length-1];
action = table[state] && table[state][TERROR];
@@ -1212,7 +1287,6 @@ parser.parse = function parse (input) {
}
switch (action[0]) {
-
case 1: // shift
//this.shiftCount++;
@@ -1226,15 +1300,18 @@ parser.parse = function parse (input) {
yytext = this.lexer.yytext;
yylineno = this.lexer.yylineno;
yyloc = this.lexer.yylloc;
- if (recovering > 0)
+ if (recovering > 0) {
recovering--;
- } else { // error just occurred, resume old lookahead f/ before error
+ }
+ } else {
+ // error just occurred, resume old lookahead f/ before error
symbol = preErrorSymbol;
preErrorSymbol = null;
}
break;
- case 2: // reduce
+ case 2:
+ // reduce
//this.reductionCount++;
len = this.productions_[action[1]][1];
@@ -1272,7 +1349,8 @@ parser.parse = function parse (input) {
stack.push(newState);
break;
- case 3: // accept
+ case 3:
+ // accept
return true;
}
@@ -1580,24 +1658,7 @@ Jison.Generator = function Jison_Generator (g, options) {
};
return function Parser (g, options) {
- var opt = typal.mix.call({}, g.options, options);
- var gen;
- switch (opt.type) {
- case 'lr0':
- gen = new LR0Generator(g, opt);
- break;
- case 'slr':
- gen = new SLRGenerator(g, opt);
- break;
- case 'lr':
- gen = new LR1Generator(g, opt);
- break;
- case 'll':
- gen = new LLGenerator(g, opt);
- break;
- default:
- gen = new LALRGenerator(g, opt);
- }
+ var gen = Jison.Generator(g, options);
return gen.createParser();
};

0 comments on commit ef5113f

Please sign in to comment.
Something went wrong with that request. Please try again.