Update Jison for table optimizations.
This commit is contained in:
parent
659a5436a5
commit
8adbc75811
|
@ -1,5 +1,7 @@
|
|||
Jison
|
||||
=====
|
||||
* [issues](http://github.com/zaach/jison/issues)
|
||||
* [discuss](mailto:jison@librelist.com)
|
||||
|
||||
An API for creating parsers in JavaScript
|
||||
-----------------------------------------
|
||||
|
@ -189,8 +191,8 @@ and calc.jison, language grammar
|
|||
{$$ = $1/$3;}
|
||||
| e '^' e
|
||||
{$$ = Math.pow($1, $3);}
|
||||
| '-' e
|
||||
{$$ = -$2;} %prec UMINUS
|
||||
| '-' e %prec UMINUS
|
||||
{$$ = -$2;}
|
||||
| '(' e ')'
|
||||
{$$ = $2;}
|
||||
| NUMBER
|
||||
|
@ -288,14 +290,12 @@ Like Bison, Jison can recognize languages described by LALR(1) grammars, though
|
|||
|
||||
**LR(1) mode is currently not practical for use with anything other than toy grammars, but that is entirely a consequence of the algorithm used, and may change in the future.*
|
||||
|
||||
Real world example
|
||||
Real world examples
|
||||
------------------
|
||||
|
||||
I wrote a parser for [Orderly][3] using Jison. Some benefits I found were:
|
||||
* [CoffeeScript](http://github.com/jashkenas/coffee-script) uses Jison in its self-compiler.
|
||||
* [Orderly.js][3] uses Jison for compilation.
|
||||
|
||||
- If modeled after the normative language grammar, it is guaranteed to recognize the correct language.
|
||||
- Adding new syntax is straight forward.
|
||||
- It was much faster to develop than if I were to attempt implementing a (top-down) parser from scratch. But for others not used to grammar specifications, this might not be the case.
|
||||
|
||||
Contributors
|
||||
------------
|
||||
|
|
|
@ -24,8 +24,8 @@ e
|
|||
{$$ = $1/$3;}
|
||||
| e '^' e
|
||||
{$$ = Math.pow($1, $3);}
|
||||
| '-' e
|
||||
{$$ = -$2;} %prec UMINUS
|
||||
| '-' e %prec UMINUS
|
||||
{$$ = -$2;}
|
||||
| '(' e ')'
|
||||
{$$ = $2;}
|
||||
| NUMBER
|
||||
|
|
|
@ -392,10 +392,12 @@ lookaheadMixin.first = function first (symbol) {
|
|||
} else if (symbol instanceof Array) {
|
||||
var firsts = [];
|
||||
for (var i=0,t;t=symbol[i];++i) {
|
||||
this.first(t).forEach(function first_forEach (e) {
|
||||
if (firsts.indexOf(e)===-1)
|
||||
firsts.push(e);
|
||||
});
|
||||
if (!this.nonterminals[t]) {
|
||||
if (firsts.indexOf(t) === -1)
|
||||
firsts.push(t);
|
||||
} else {
|
||||
Set.union(firsts, this.nonterminals[t].first);
|
||||
}
|
||||
if (!this.nullable(t))
|
||||
break;
|
||||
}
|
||||
|
@ -581,9 +583,9 @@ lrGeneratorMixin.ItemSet = Set.prototype.construct({
|
|||
contains: function (item) {
|
||||
return this.hash_[item.id];
|
||||
},
|
||||
toValue: function toValue () {
|
||||
var v = this.items_.sort().join('|');
|
||||
return (this.toValue = function toValue_inner() {return v;})();
|
||||
valueOf: function toValue () {
|
||||
var v = this._items.map(function (a) {return a.id}).sort().join('|');
|
||||
return (this.valueOf = function toValue_inner() {return v;})();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -630,11 +632,10 @@ lrGeneratorMixin.closureOperation = function closureOperation (itemSet /*, closu
|
|||
|
||||
lrGeneratorMixin.gotoOperation = function gotoOperation (itemSet, symbol) {
|
||||
var gotoSet = new this.ItemSet(),
|
||||
EOF = this.EOF,
|
||||
self = this;
|
||||
|
||||
itemSet.forEach(function goto_forEach(item, n) {
|
||||
if (item.markedSymbol === symbol && symbol !== EOF) {
|
||||
if (item.markedSymbol === symbol) {
|
||||
gotoSet.push(new self.Item(item.production, item.dotPosition+1, item.follows, n));
|
||||
}
|
||||
});
|
||||
|
@ -652,10 +653,13 @@ lrGeneratorMixin.canonicalCollection = function canonicalCollection () {
|
|||
self = this,
|
||||
itemSet;
|
||||
|
||||
states.has = {};
|
||||
states.has[firstState] = 0;
|
||||
|
||||
while (marked !== states.size()) {
|
||||
itemSet = states.item(marked); marked++;
|
||||
itemSet.forEach(function CC_itemSet_forEach (item) {
|
||||
if(item.markedSymbol)
|
||||
if (item.markedSymbol && item.markedSymbol !== self.EOF)
|
||||
self.canonicalCollectionInsert(item.markedSymbol, itemSet, states, marked-1);
|
||||
});
|
||||
}
|
||||
|
@ -670,8 +674,10 @@ lrGeneratorMixin.canonicalCollectionInsert = function canonicalCollectionInsert
|
|||
g.predecessors = {};
|
||||
// add g to que if not empty or duplicate
|
||||
if (!g.isEmpty()) {
|
||||
var i = states.indexOf(g);
|
||||
if (i === -1) {
|
||||
var gv = g.valueOf(),
|
||||
i = states.has[gv];
|
||||
if (i === -1 || typeof i === 'undefined') {
|
||||
states.has[gv] = states.size();
|
||||
itemSet.edges[symbol] = states.size(); // store goto transition for table
|
||||
states.push(g);
|
||||
g.predecessors[symbol] = [stateNum];
|
||||
|
@ -682,6 +688,7 @@ lrGeneratorMixin.canonicalCollectionInsert = function canonicalCollectionInsert
|
|||
}
|
||||
};
|
||||
|
||||
var NONASSOC = 0;
|
||||
lrGeneratorMixin.parseTable = function parseTable (itemSets) {
|
||||
var states = [],
|
||||
nonterminals = this.nonterminals,
|
||||
|
@ -708,7 +715,7 @@ lrGeneratorMixin.parseTable = function parseTable (itemSets) {
|
|||
state[self.symbols_[stackSymbol]] = gotoState;
|
||||
} else {
|
||||
//self.trace(k, stackSymbol, 's'+gotoState);
|
||||
state[self.symbols_[stackSymbol]] = [[s,gotoState]];
|
||||
state[self.symbols_[stackSymbol]] = [s,gotoState];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -718,7 +725,7 @@ lrGeneratorMixin.parseTable = function parseTable (itemSets) {
|
|||
itemSet.forEach(function (item, j) {
|
||||
if (item.markedSymbol == self.EOF) {
|
||||
// accept
|
||||
state[self.symbols_[self.EOF]] = [[a]];
|
||||
state[self.symbols_[self.EOF]] = [a];
|
||||
//self.trace(k, self.EOF, state[self.EOF]);
|
||||
}
|
||||
});
|
||||
|
@ -731,11 +738,12 @@ lrGeneratorMixin.parseTable = function parseTable (itemSets) {
|
|||
var terminals = allterms || self.lookAheads(itemSet, item);
|
||||
|
||||
terminals.forEach(function (stackSymbol) {
|
||||
action = state[self.symbols_[stackSymbol]] || [];
|
||||
action = state[self.symbols_[stackSymbol]];
|
||||
var op = operators[stackSymbol];
|
||||
|
||||
// Reading a terminal and current position is at the end of a production, try to reduce
|
||||
if (action.length) {
|
||||
var sol = resolveConflict(item.production, op, [r,item.production.id], action[0]);
|
||||
if (action || action && action.length) {
|
||||
var sol = resolveConflict(item.production, op, [r,item.production.id], action[0] instanceof Array ? action[0] : action);
|
||||
self.resolutions.push([k,stackSymbol,sol]);
|
||||
if (sol.bydefault) {
|
||||
self.conflicts++;
|
||||
|
@ -743,16 +751,20 @@ lrGeneratorMixin.parseTable = function parseTable (itemSets) {
|
|||
self.warn('Conflict in grammar (state:',k, ', token:',stackSymbol, ")\n ", printAction(sol.r, self), "\n ", printAction(sol.s, self));
|
||||
}
|
||||
if (self.options.noDefaultResolve) {
|
||||
if (!(action[0] instanceof Array))
|
||||
action = [action];
|
||||
action.push(sol.r);
|
||||
}
|
||||
} else {
|
||||
action = [sol.action];
|
||||
action = sol.action;
|
||||
}
|
||||
} else {
|
||||
action.push([r,item.production.id]);
|
||||
action = [r,item.production.id];
|
||||
}
|
||||
if (action && action.length) {
|
||||
state[self.symbols_[stackSymbol]] = action;
|
||||
} else if (action === NONASSOC) {
|
||||
state[self.symbols_[stackSymbol]] = undefined;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -773,7 +785,6 @@ function resolveConflict (production, op, reduce, shift) {
|
|||
sln.msg = "Resolve R/R conflict (use first production declared in grammar.)";
|
||||
sln.action = shift[1] < reduce[1] ? shift : reduce;
|
||||
sln.bydefault = true;
|
||||
//print(production, reduce[0]);
|
||||
return sln;
|
||||
}
|
||||
|
||||
|
@ -793,7 +804,7 @@ function resolveConflict (production, op, reduce, shift) {
|
|||
sln.action = reduce;
|
||||
} else if (op.assoc === "nonassoc" ) {
|
||||
sln.msg = "Resolve S/R conflict (no action for non-associative operator.)";
|
||||
sln.action = undefined;
|
||||
sln.action = NONASSOC;
|
||||
}
|
||||
} else {
|
||||
sln.msg = "Resolve conflict (reduce for higher precedent production.)";
|
||||
|
@ -979,7 +990,7 @@ parser.parse = function parse (input) {
|
|||
// read action for current state and first input
|
||||
action = table[state] && table[state][symbol];
|
||||
|
||||
if (typeof action == 'undefined' || !action.length || !action[0]) {
|
||||
if (typeof action === 'undefined' || !action.length || !action[0]) {
|
||||
expected = [];
|
||||
for (p in table[state]) if (this.terminals_[p] && p != 1) {
|
||||
expected.push("'"+this.terminals_[p]+"'");
|
||||
|
@ -993,14 +1004,12 @@ parser.parse = function parse (input) {
|
|||
}
|
||||
}
|
||||
|
||||
this.trace('action:',action);
|
||||
|
||||
// this shouldn't happen, unless resolve defaults are off
|
||||
if (action.length > 1) {
|
||||
if (action[0] instanceof Array && action.length > 1) {
|
||||
throw new Error('Parse Error: multiple actions possible at state: '+state+', token: '+symbol);
|
||||
}
|
||||
|
||||
a = action[0];
|
||||
a = action;
|
||||
|
||||
switch (a[0]) {
|
||||
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
// converts json grammar format to Jison grammar format
|
||||
|
||||
function json2jison (grammar) {
|
||||
function json2jison (grammar, options) {
|
||||
options = options || {};
|
||||
var s = "";
|
||||
|
||||
s += genDecls(grammar);
|
||||
s += genBNF(grammar.bnf);
|
||||
s += genDecls(grammar, options);
|
||||
s += genBNF(grammar.bnf, options);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
function genDecls (grammar) {
|
||||
function genDecls (grammar, options) {
|
||||
var s = "",
|
||||
key;
|
||||
|
||||
|
@ -34,18 +35,18 @@ function genDecls (grammar) {
|
|||
return s;
|
||||
}
|
||||
|
||||
function genBNF (bnf) {
|
||||
function genBNF (bnf, options) {
|
||||
var s = "%%\n",
|
||||
sym;
|
||||
|
||||
for (sym in bnf) if (bnf.hasOwnProperty(sym)) {
|
||||
s += ["\n",sym,'\n : ', genHandles(bnf[sym]),"\n ;\n"].join("");
|
||||
s += ["\n",sym,'\n : ', genHandles(bnf[sym], options),"\n ;\n"].join("");
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
function genHandles (handle) {
|
||||
function genHandles (handle, options) {
|
||||
if (typeof handle === 'string') {
|
||||
return handle;
|
||||
} else { //array
|
||||
|
@ -56,9 +57,11 @@ function genHandles (handle) {
|
|||
} else if (handle[i] instanceof Array) {
|
||||
s += (handle[i][0] && quoteSymbols(handle[i][0]));
|
||||
if (typeof handle[i][1] === 'string') {
|
||||
if (!options.stripActions) {
|
||||
s += handle[i][1].match(/\}/) ?
|
||||
"\n {{"+handle[i][1]+(handle[i][1].match(/\}$/) ? ' ' : '')+"}}" :
|
||||
"\n {"+handle[i][1]+"}";
|
||||
}
|
||||
if (handle[i][2] && handle[i][2].prec) {
|
||||
s += " %prec "+handle[i][2].prec;
|
||||
}
|
||||
|
|
|
@ -200,7 +200,7 @@ RegExpLexer.prototype = {
|
|||
out += p.join(",\n");
|
||||
out += "})";
|
||||
out += ";\nlexer.performAction = "+String(this.performAction);
|
||||
out += ";\nlexer.rules = "+uneval(this.rules);
|
||||
out += ";\nlexer.rules = [" + this.rules + "]";
|
||||
out += ";return lexer;})()";
|
||||
return out;
|
||||
},
|
||||
|
|
|
@ -3,9 +3,9 @@ var bnf = (function(){
|
|||
var parser = {trace: function trace() {
|
||||
},
|
||||
yy: {},
|
||||
symbols_: {"spec":2,"declaration_list":3,"%%":4,"grammar":5,"EOF":6,"declaration":7,"START":8,"id":9,"operator":10,"associativity":11,"token_list":12,"LEFT":13,"RIGHT":14,"NONASSOC":15,"symbol":16,"production_list":17,"production":18,":":19,"handle_list":20,";":21,"|":22,"handle_action":23,"handle":24,"action":25,"prec":26,"PREC":27,"STRING":28,"ID":29,"ACTION":30,"$accept":0,"$end":1},
|
||||
symbols_: {"spec":2,"declaration_list":3,"%%":4,"grammar":5,"EOF":6,"declaration":7,"START":8,"id":9,"operator":10,"associativity":11,"token_list":12,"LEFT":13,"RIGHT":14,"NONASSOC":15,"symbol":16,"production_list":17,"production":18,":":19,"handle_list":20,";":21,"|":22,"handle_action":23,"handle":24,"prec":25,"action":26,"PREC":27,"STRING":28,"ID":29,"ACTION":30,"$accept":0,"$end":1},
|
||||
terminals_: {"4":"%%","6":"EOF","8":"START","13":"LEFT","14":"RIGHT","15":"NONASSOC","19":":","21":";","22":"|","27":"PREC","28":"STRING","29":"ID","30":"ACTION"},
|
||||
productions_: [0,[2,4],[2,5],[3,2],[3,0],[7,2],[7,1],[10,2],[11,1],[11,1],[11,1],[12,2],[12,1],[5,1],[17,2],[17,1],[18,4],[20,3],[20,1],[23,3],[24,2],[24,0],[26,2],[26,0],[16,1],[16,1],[9,1],[25,1],[25,0]],
|
||||
productions_: [0,[2,4],[2,5],[3,2],[3,0],[7,2],[7,1],[10,2],[11,1],[11,1],[11,1],[12,2],[12,1],[5,1],[17,2],[17,1],[18,4],[20,3],[20,1],[23,3],[24,2],[24,0],[25,2],[25,0],[16,1],[16,1],[9,1],[26,1],[26,0]],
|
||||
performAction: function anonymous(yytext, yyleng, yylineno, yy) {
|
||||
var $$ = arguments[5], $0 = arguments[5].length;
|
||||
switch (arguments[4]) {
|
||||
|
@ -75,12 +75,12 @@ performAction: function anonymous(yytext, yyleng, yylineno, yy) {
|
|||
break;
|
||||
case 19:
|
||||
this.$ = [$$[$0 - 3 + 1 - 1].length ? $$[$0 - 3 + 1 - 1].join(" ") : ""];
|
||||
if ($$[$0 - 3 + 2 - 1]) {
|
||||
this.$.push($$[$0 - 3 + 2 - 1]);
|
||||
}
|
||||
if ($$[$0 - 3 + 3 - 1]) {
|
||||
this.$.push($$[$0 - 3 + 3 - 1]);
|
||||
}
|
||||
if ($$[$0 - 3 + 2 - 1]) {
|
||||
this.$.push($$[$0 - 3 + 2 - 1]);
|
||||
}
|
||||
if (this.$.length === 1) {
|
||||
this.$ = this.$[0];
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ performAction: function anonymous(yytext, yyleng, yylineno, yy) {
|
|||
default:;
|
||||
}
|
||||
},
|
||||
table: [{"2":1,"3":2,"4":[[2,4]],"15":[[2,4]],"14":[[2,4]],"13":[[2,4]],"8":[[2,4]]},{"1":[[3]]},{"4":[[1,3]],"7":4,"8":[[1,5]],"10":6,"11":7,"13":[[1,8]],"14":[[1,9]],"15":[[1,10]]},{"5":11,"17":12,"18":13,"9":14,"29":[[1,15]]},{"4":[[2,3]],"15":[[2,3]],"14":[[2,3]],"13":[[2,3]],"8":[[2,3]]},{"9":16,"29":[[1,15]]},{"8":[[2,6]],"13":[[2,6]],"14":[[2,6]],"15":[[2,6]],"4":[[2,6]]},{"12":17,"16":18,"9":19,"28":[[1,20]],"29":[[1,15]]},{"29":[[2,8]],"28":[[2,8]]},{"29":[[2,9]],"28":[[2,9]]},{"29":[[2,10]],"28":[[2,10]]},{"6":[[1,21]],"4":[[1,22]]},{"18":23,"9":14,"29":[[1,15]],"6":[[2,13]],"4":[[2,13]]},{"4":[[2,15]],"6":[[2,15]],"29":[[2,15]]},{"19":[[1,24]]},{"19":[[2,26]],"4":[[2,26]],"15":[[2,26]],"14":[[2,26]],"13":[[2,26]],"8":[[2,26]],"28":[[2,26]],"29":[[2,26]],"21":[[2,26]],"22":[[2,26]],"27":[[2,26]],"30":[[2,26]]},{"8":[[2,5]],"13":[[2,5]],"14":[[2,5]],"15":[[2,5]],"4":[[2,5]]},{"16":25,"9":19,"28":[[1,20]],"29":[[1,15]],"4":[[2,7]],"15":[[2,7]],"14":[[2,7]],"13":[[2,7]],"8":[[2,7]]},{"8":[[2,12]],"13":[[2,12]],"14":[[2,12]],"15":[[2,12]],"4":[[2,12]],"28":[[2,12]],"29":[[2,12]]},{"29":[[2,24]],"28":[[2,24]],"4":[[2,24]],"15":[[2,24]],"14":[[2,24]],"13":[[2,24]],"8":[[2,24]],"30":[[2,24]],"27":[[2,24]],"22":[[2,24]],"21":[[2,24]]},{"29":[[2,25]],"28":[[2,25]],"4":[[2,25]],"15":[[2,25]],"14":[[2,25]],"13":[[2,25]],"8":[[2,25]],"30":[[2,25]],"27":[[2,25]],"22":[[2,25]],"21":[[2,25]]},{"1":[[2,1]]},{"6":[[1,26]]},{"4":[[2,14]],"6":[[2,14]],"29":[[2,14]]},{"20":27,"23":28,"24":29,"21":[[2,21]],"22":[[2,21]],"27":[[2,21]],"30":[[2,21]],"28":[[2,21]],"29":[[2,21]]},{"8":[[2,11]],"13":[[2,11]],"14":[[2,11]],"15":[[2,11]],"4":[[2,11]],"28":[[2,11]],"29":[[2,11]]},{"1":[[2,2]]},{"21":[[1,30]],"22":[[1,31]]},{"21":[[2,18]],"22":[[2,18]]},{"25":32,"16":33,"30":[[1,34]],"9":19,"28":[[1,20]],"29":[[1,15]],"21":[[2,28]],"22":[[2,28]],"27":[[2,28]]},{"29":[[2,16]],"6":[[2,16]],"4":[[2,16]]},{"23":35,"24":29,"21":[[2,21]],"22":[[2,21]],"27":[[2,21]],"30":[[2,21]],"28":[[2,21]],"29":[[2,21]]},{"26":36,"27":[[1,37]],"21":[[2,23]],"22":[[2,23]]},{"21":[[2,20]],"22":[[2,20]],"27":[[2,20]],"30":[[2,20]],"28":[[2,20]],"29":[[2,20]]},{"21":[[2,27]],"22":[[2,27]],"27":[[2,27]]},{"21":[[2,17]],"22":[[2,17]]},{"22":[[2,19]],"21":[[2,19]]},{"16":38,"9":19,"28":[[1,20]],"29":[[1,15]]},{"21":[[2,22]],"22":[[2,22]]}],
|
||||
table: [{"2":1,"3":2,"4":[2,4],"8":[2,4],"13":[2,4],"14":[2,4],"15":[2,4]},{"1":[3]},{"4":[1,3],"7":4,"8":[1,5],"10":6,"11":7,"13":[1,8],"14":[1,9],"15":[1,10]},{"5":11,"17":12,"18":13,"9":14,"29":[1,15]},{"4":[2,3],"8":[2,3],"13":[2,3],"14":[2,3],"15":[2,3]},{"9":16,"29":[1,15]},{"15":[2,6],"14":[2,6],"13":[2,6],"8":[2,6],"4":[2,6]},{"12":17,"16":18,"9":19,"28":[1,20],"29":[1,15]},{"28":[2,8],"29":[2,8]},{"28":[2,9],"29":[2,9]},{"28":[2,10],"29":[2,10]},{"6":[1,21],"4":[1,22]},{"18":23,"9":14,"29":[1,15],"6":[2,13],"4":[2,13]},{"4":[2,15],"6":[2,15],"29":[2,15]},{"19":[1,24]},{"19":[2,26],"4":[2,26],"8":[2,26],"13":[2,26],"14":[2,26],"15":[2,26],"29":[2,26],"28":[2,26],"21":[2,26],"22":[2,26],"30":[2,26],"27":[2,26]},{"15":[2,5],"14":[2,5],"13":[2,5],"8":[2,5],"4":[2,5]},{"16":25,"9":19,"28":[1,20],"29":[1,15],"4":[2,7],"8":[2,7],"13":[2,7],"14":[2,7],"15":[2,7]},{"15":[2,12],"14":[2,12],"13":[2,12],"8":[2,12],"4":[2,12],"29":[2,12],"28":[2,12]},{"28":[2,24],"29":[2,24],"4":[2,24],"8":[2,24],"13":[2,24],"14":[2,24],"15":[2,24],"27":[2,24],"30":[2,24],"22":[2,24],"21":[2,24]},{"28":[2,25],"29":[2,25],"4":[2,25],"8":[2,25],"13":[2,25],"14":[2,25],"15":[2,25],"27":[2,25],"30":[2,25],"22":[2,25],"21":[2,25]},{"1":[2,1]},{"6":[1,26]},{"4":[2,14],"6":[2,14],"29":[2,14]},{"20":27,"23":28,"24":29,"21":[2,21],"22":[2,21],"30":[2,21],"27":[2,21],"29":[2,21],"28":[2,21]},{"15":[2,11],"14":[2,11],"13":[2,11],"8":[2,11],"4":[2,11],"29":[2,11],"28":[2,11]},{"1":[2,2]},{"21":[1,30],"22":[1,31]},{"21":[2,18],"22":[2,18]},{"25":32,"16":33,"27":[1,34],"9":19,"28":[1,20],"29":[1,15],"21":[2,23],"22":[2,23],"30":[2,23]},{"29":[2,16],"6":[2,16],"4":[2,16]},{"23":35,"24":29,"21":[2,21],"22":[2,21],"30":[2,21],"27":[2,21],"29":[2,21],"28":[2,21]},{"26":36,"30":[1,37],"21":[2,28],"22":[2,28]},{"21":[2,20],"22":[2,20],"30":[2,20],"27":[2,20],"29":[2,20],"28":[2,20]},{"16":38,"9":19,"28":[1,20],"29":[1,15]},{"21":[2,17],"22":[2,17]},{"22":[2,19],"21":[2,19]},{"21":[2,27],"22":[2,27]},{"21":[2,22],"22":[2,22],"30":[2,22]}],
|
||||
parseError: function parseError(str, hash) {
|
||||
throw new Error(str);
|
||||
},
|
||||
|
@ -140,7 +140,7 @@ parse: function parse(input) {
|
|||
while (true) {
|
||||
state = stack[stack.length - 1];
|
||||
action = table[state] && table[state][symbol];
|
||||
if (typeof action == "undefined" || !action.length || !action[0]) {
|
||||
if (typeof action === "undefined" || !action.length || !action[0]) {
|
||||
expected = [];
|
||||
for (p in table[state]) {
|
||||
if (this.terminals_[p] && p != 1) {
|
||||
|
@ -153,11 +153,10 @@ parse: function parse(input) {
|
|||
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});
|
||||
}
|
||||
}
|
||||
this.trace("action:", action);
|
||||
if (action.length > 1) {
|
||||
if (action[0] instanceof Array && action.length > 1) {
|
||||
throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol);
|
||||
}
|
||||
a = action[0];
|
||||
a = action;
|
||||
switch (a[0]) {
|
||||
case 1:
|
||||
shifts++;
|
||||
|
@ -301,68 +300,72 @@ lexer.performAction = function anonymous(yy, yy_) {
|
|||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
return yy.lexComment(this);
|
||||
break;
|
||||
case 2:
|
||||
return 29;
|
||||
return yy.lexComment(this);
|
||||
break;
|
||||
case 3:
|
||||
yy_.yytext = yy_.yytext.substr(1, yy_.yyleng - 2);
|
||||
return 28;
|
||||
return 29;
|
||||
break;
|
||||
case 4:
|
||||
yy_.yytext = yy_.yytext.substr(1, yy_.yyleng - 2);
|
||||
return 28;
|
||||
break;
|
||||
case 5:
|
||||
return 19;
|
||||
yy_.yytext = yy_.yytext.substr(1, yy_.yyleng - 2);
|
||||
return 28;
|
||||
break;
|
||||
case 6:
|
||||
return 21;
|
||||
return 19;
|
||||
break;
|
||||
case 7:
|
||||
return 22;
|
||||
return 21;
|
||||
break;
|
||||
case 8:
|
||||
return 4;
|
||||
return 22;
|
||||
break;
|
||||
case 9:
|
||||
return 27;
|
||||
return 4;
|
||||
break;
|
||||
case 10:
|
||||
return 8;
|
||||
return 27;
|
||||
break;
|
||||
case 11:
|
||||
return 13;
|
||||
return 8;
|
||||
break;
|
||||
case 12:
|
||||
return 14;
|
||||
return 13;
|
||||
break;
|
||||
case 13:
|
||||
return 15;
|
||||
return 14;
|
||||
break;
|
||||
case 14:
|
||||
return 15;
|
||||
break;
|
||||
case 15:
|
||||
return yy.lexAction(this);
|
||||
break;
|
||||
case 16:
|
||||
yy_.yytext = yy_.yytext.substr(1, yy_.yyleng - 2);
|
||||
return 30;
|
||||
break;
|
||||
case 17:
|
||||
return yy.lexAction(this);
|
||||
break;
|
||||
case 18:
|
||||
yy_.yytext = yy_.yytext.substr(1, yy_.yyleng - 2);
|
||||
return 30;
|
||||
break;
|
||||
case 18:
|
||||
break;
|
||||
case 19:
|
||||
yy_.yytext = yy_.yytext.substr(2, yy_.yytext.length - 4);
|
||||
return 30;
|
||||
break;
|
||||
case 20:
|
||||
break;
|
||||
case 21:
|
||||
return 6;
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
};
|
||||
lexer.rules = [/^\s+/, /^\/\*[^*]*\*/, /^[a-zA-Z][a-zA-Z0-9_-]*/, /^"[^"]+"/, /^'[^']+'/, /^:/, /^;/, /^\|/, /^%%/, /^%prec\b/, /^%start\b/, /^%left\b/, /^%right\b/, /^%nonassoc\b/, /^%[a-zA-Z]+[^\n]*/, /^\{\{[^}]*\}/, /^\{[^}]*\}/, /^<[^>]*>/, /^./, /^$/];return lexer;})()
|
||||
lexer.rules = [/^\s+/, /^\/\/.*/, /^\/\*[^*]*\*/, /^[a-zA-Z][a-zA-Z0-9_-]*/, /^"[^"]+"/, /^'[^']+'/, /^:/, /^;/, /^\|/, /^%%/, /^%prec\b/, /^%start\b/, /^%left\b/, /^%right\b/, /^%nonassoc\b/, /^%[a-zA-Z]+[^\n]*/, /^<[a-zA-Z]*>/, /^\{\{[^}]*\}/, /^\{[^}]*\}/, /^%\{(.|\n)*?%\}/, /^./, /^$/];return lexer;})()
|
||||
parser.lexer = lexer;
|
||||
return parser;
|
||||
})();
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -11,14 +11,14 @@ declaration_list
|
|||
: declaration_list declaration
|
||||
{$$ = $1; yy.addDeclaration($$, $2);}
|
||||
|
|
||||
<$$ = {};>
|
||||
{{$$ = {};}}
|
||||
;
|
||||
|
||||
declaration
|
||||
: START id
|
||||
<$$ = {start: $2};>
|
||||
{{$$ = {start: $2};}}
|
||||
| operator
|
||||
<$$ = {operator: $1};>
|
||||
{{$$ = {operator: $1};}}
|
||||
;
|
||||
|
||||
operator
|
||||
|
@ -51,7 +51,7 @@ production_list
|
|||
: production_list production
|
||||
{$$ = $1; $$[$2[0]] = $2[1];}
|
||||
| production
|
||||
<$$ = {}; $$[$1[0]] = $1[1];>
|
||||
{{$$ = {}; $$[$1[0]] = $1[1];}}
|
||||
;
|
||||
|
||||
production
|
||||
|
@ -67,10 +67,10 @@ handle_list
|
|||
;
|
||||
|
||||
handle_action
|
||||
: handle action prec
|
||||
: handle prec action
|
||||
{$$ = [($1.length ? $1.join(' ') : '')];
|
||||
if($2) $$.push($2);
|
||||
if($3) $$.push($3);
|
||||
if($2) $$.push($2);
|
||||
if ($$.length === 1) $$ = $$[0];
|
||||
}
|
||||
;
|
||||
|
@ -84,7 +84,7 @@ handle
|
|||
|
||||
prec
|
||||
: PREC symbol
|
||||
<$$ = {prec: $2};>
|
||||
{{$$ = {prec: $2};}}
|
||||
|
|
||||
{$$ = null;}
|
||||
;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
%%
|
||||
\s+ {/* skip whitespace */}
|
||||
"//".* {/* skip comment */}
|
||||
"/*"[^*]*"*" {return yy.lexComment(this);}
|
||||
[a-zA-Z][a-zA-Z0-9_-]* {return 'ID';}
|
||||
'"'[^"]+'"' {yytext = yytext.substr(1, yyleng-2); return 'STRING';}
|
||||
|
@ -15,9 +16,10 @@
|
|||
"%right" {return 'RIGHT';}
|
||||
"%nonassoc" {return 'NONASSOC';}
|
||||
"%"[a-zA-Z]+[^\n]* {/* ignore unrecognized decl */}
|
||||
"<"[a-zA-Z]*">" { /* ignore type */}
|
||||
"{{"[^}]*"}" {return yy.lexAction(this);}
|
||||
"{"[^}]*"}" {yytext = yytext.substr(1, yyleng-2); return 'ACTION';}
|
||||
"<"[^>]*">" {yytext = yytext.substr(1, yyleng-2); return 'ACTION';}
|
||||
"%{"(.|\n)*?"%}" {yytext = yytext.substr(2, yytext.length-4);return 'ACTION';}
|
||||
. {/* ignore bad characters */}
|
||||
<<EOF>> {return 'EOF';}
|
||||
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
{
|
||||
"rules": [
|
||||
["\\s+", "/* skip whitespace */"],
|
||||
["\\/\\*[^*]*\\*", "return yy.lexComment(this);"],
|
||||
["[a-zA-Z][a-zA-Z0-9_-]*", "return 'ID';"],
|
||||
["\"[^\"]+\"", "yytext = yytext.substr(1, yyleng-2); return 'STRING';"],
|
||||
["'[^']+'", "yytext = yytext.substr(1, yyleng-2); return 'STRING';"],
|
||||
[":", "return ':';"],
|
||||
[";", "return ';';"],
|
||||
["\\|", "return '|';"],
|
||||
["%%", "return '%%';"],
|
||||
["%prec\\b", "return 'PREC';"],
|
||||
["%start\\b", "return 'START';"],
|
||||
["%left\\b", "return 'LEFT';"],
|
||||
["%right\\b", "return 'RIGHT';"],
|
||||
["%nonassoc\\b", "return 'NONASSOC';"],
|
||||
["%[a-zA-Z]+[^\\n]*", "/* ignore unrecognized decl */"],
|
||||
["\\{\\{[^}]*\\}", "return yy.lexAction(this);"],
|
||||
["\\{[^}]*\\}", "yytext = yytext.substr(1, yyleng-2); return 'ACTION';"],
|
||||
["<[^>]*>", "yytext = yytext.substr(1, yyleng-2); return 'ACTION';"],
|
||||
[".", "/* ignore bad characters */"],
|
||||
["$", "return 'EOF';"]
|
||||
]
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
{
|
||||
"rules": [
|
||||
["\\n+", "yy.freshLine = true;"],
|
||||
["\\s+", "yy.freshLine = false;"],
|
||||
["y\\{[^}]*\\}", "yytext = yytext.substr(2, yytext.length-3);return 'ACTION';"],
|
||||
["[a-zA-Z_][a-zA-Z0-9_-]*", "return 'NAME';"],
|
||||
["\"(?:[^\"]|\\\\\")*\"", "return 'STRING_LIT';"],
|
||||
["'(?:[^']|\\\\')*'", "return 'STRING_LIT';"],
|
||||
["\\|", "return '|';"],
|
||||
["\\[(?:\\\\\\]|[^\\]])*\\]", "return 'ANY_GROUP_REGEX';"],
|
||||
["\\(", "return '(';"],
|
||||
["\\)", "return ')';"],
|
||||
["\\+", "return '+';"],
|
||||
["\\*", "return '*';"],
|
||||
["\\?", "return '?';"],
|
||||
["\\^", "return '^';"],
|
||||
["\\/", "return '/';"],
|
||||
["\\\\[a-zA-Z0]", "return 'ESCAPE_CHAR';"],
|
||||
["\\$", "return '$';"],
|
||||
["<<EOF>>", "return '$';"],
|
||||
["\\.", "return '.';"],
|
||||
["%%", "return '%%';"],
|
||||
["\\{\\d+(?:,\\s?\\d+|,)?\\}", "return 'RANGE_REGEX';"],
|
||||
["(?=\\{)", "if(yy.freshLine){this.input('{');return '{';} else this.unput('y');"],
|
||||
["\\}", "return '}';"],
|
||||
["%\\{(?:.|\\n)*?\\}%", "yytext = yytext.substr(2, yytext.length-4);return 'ACTION';"],
|
||||
[".", "/* ignore bad characters */"],
|
||||
["$", "return 'EOF';"]
|
||||
]
|
||||
}
|
|
@ -17,7 +17,7 @@ exports["test classy grammar"] = function () {
|
|||
};
|
||||
|
||||
exports["test advanced grammar"] = function () {
|
||||
var grammar = "%% test: foo bar {action} | baz ; hello: world %prec UMINUS ;extra: foo {action} %prec '-' ;";
|
||||
var grammar = "%% test: foo bar {action} | baz ; hello: world %prec UMINUS ;extra: foo %prec '-' {action} ;";
|
||||
var expected = {bnf: {test: [["foo bar", "action" ], "baz"], hello: [[ "world", {prec:"UMINUS"} ]], extra: [[ "foo", "action", {prec: "-"} ]]}};
|
||||
|
||||
assert.deepEqual(bnf.parse(grammar), expected, "grammar should be parsed correctly");
|
||||
|
@ -37,8 +37,8 @@ exports["test nullable rule with action"] = function () {
|
|||
assert.deepEqual(bnf.parse(grammar), expected, "grammar should be parsed correctly");
|
||||
};
|
||||
|
||||
exports["test nullable rule with < > delimited action"] = function () {
|
||||
var grammar = "%% test: foo bar | <action{}>; hello: world ;";
|
||||
exports["test nullable rule with %{ %} delimited action"] = function () {
|
||||
var grammar = "%% test: foo bar | %{action{}%}; hello: world ;";
|
||||
var expected = {bnf: {test: ["foo bar", [ "", "action{}" ]], hello: ["world"]}};
|
||||
|
||||
assert.deepEqual(bnf.parse(grammar), expected, "grammar should be parsed correctly");
|
||||
|
@ -57,9 +57,31 @@ exports["test comment"] = function () {
|
|||
|
||||
assert.deepEqual(bnf.parse(grammar), expected, "grammar should be parsed correctly");
|
||||
};
|
||||
|
||||
exports["test single line comment"] = function () {
|
||||
var grammar = "//comment \n %% hello: world ;";
|
||||
var expected = {bnf: {hello: ["world"]}};
|
||||
|
||||
assert.deepEqual(bnf.parse(grammar), expected, "grammar should be parse comment");
|
||||
};
|
||||
|
||||
exports["test comment with nested *"] = function () {
|
||||
var grammar = "/* comment * not done */ %% hello: /* oh hai */ world ;";
|
||||
var expected = {bnf: {hello: ["world"]}};
|
||||
|
||||
assert.deepEqual(bnf.parse(grammar), expected, "grammar should be parsed correctly");
|
||||
};
|
||||
|
||||
exports["test token"] = function () {
|
||||
var grammar = "%token blah\n%% test: foo bar | baz ; hello: world ;";
|
||||
var expected = {bnf: {test: ["foo bar", "baz"], hello: ["world"]}};
|
||||
|
||||
assert.deepEqual(bnf.parse(grammar), expected, "grammar should be parsed correctly");
|
||||
};
|
||||
|
||||
exports["test token with type"] = function () {
|
||||
var grammar = "%type <type> blah\n%% test: foo bar | baz ; hello: world ;";
|
||||
var expected = {bnf: {test: ["foo bar", "baz"], hello: ["world"]}};
|
||||
|
||||
assert.deepEqual(bnf.parse(grammar), expected, "grammar should be parsed correctly");
|
||||
};
|
||||
|
|
|
@ -10,14 +10,14 @@ exports["test basic grammar"] = function () {
|
|||
};
|
||||
|
||||
exports["test advanced grammar"] = function () {
|
||||
var grammar = "%start foo %% test: foo bar | baz ; hello: world {action} %prec UM;";
|
||||
var grammar = "%start foo %% test: foo bar | baz ; hello: world %prec UM {action};";
|
||||
var expected = {start: "foo", bnf: {test: ["foo bar", "baz"], hello: [[ "world", "action", {prec: "UM"} ]]}};
|
||||
|
||||
assert.deepEqual(json2jison.convert(bnf.parse(grammar)), json2jison.convert(expected), "grammar should be parsed correctly");
|
||||
};
|
||||
|
||||
exports["test actions"] = function () {
|
||||
var grammar = "%start foo %% test: foo bar | baz ; hello: world {{action{} }} %prec UM;";
|
||||
var grammar = "%start foo %% test: foo bar | baz ; hello: world %prec UM {{action{} }} ;";
|
||||
var expected = {start: "foo", bnf: {test: ["foo bar", "baz"], hello: [[ "world", "action{}", {prec: "UM"} ]]}};
|
||||
|
||||
assert.deepEqual(json2jison.convert(bnf.parse(grammar)), json2jison.convert(expected), "grammar should be parsed correctly");
|
||||
|
|
|
@ -234,3 +234,23 @@ exports["test jison grammar as string"] = function () {
|
|||
parser.lexer = new Lexer(lexData);
|
||||
assert.ok(parser.parse('xyx'), "parse xyx");
|
||||
};
|
||||
|
||||
exports["test no default resolve"] = function () {
|
||||
var grammar = {
|
||||
tokens: [ 'x' ],
|
||||
startSymbol: "A",
|
||||
bnf: {
|
||||
"A" :[ 'x A',
|
||||
'' ]
|
||||
}
|
||||
};
|
||||
|
||||
var gen = new Jison.Generator(grammar, {type: "lr0", noDefaultResolve: true});
|
||||
var parser = gen.createParser();
|
||||
parser.lexer = new Lexer(lexData);
|
||||
|
||||
assert.ok(gen.table.length == 4, "table has 4 states");
|
||||
assert.ok(gen.conflicts == 2, "encountered 2 conflicts");
|
||||
assert["throws"](function () {parser.parse("xx")}, "throws parse error for multiple actions");
|
||||
};
|
||||
|
||||
|
|
|
@ -169,9 +169,9 @@ exports["test LR(1) grammar"] = function () {
|
|||
};
|
||||
|
||||
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 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 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\"%{\"(.|\\n)*?\"%}\" {yytext = yytext.substr(2, yytext.length-4);return 'ACTION';} \n. \t{/* ignore bad characters */}\n<<EOF>> \t{return 'EOF';}\n\n%%\n\n";
|
||||
|
||||
|
||||
var gen = new Jison.Generator(grammar, {type: "lalr"});
|
||||
|
|
Loading…
Reference in New Issue