haml-more 0.4.0.a
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +79 -0
- data/lib/haml/more/coffee_script.rb +137 -0
- data/lib/haml/more/content_for.rb +25 -0
- data/lib/haml/more.rb +45 -0
- data/lib/haml-more.rb +1 -0
- data/lib/sass/more.rb +16 -0
- data/lib/sass-more.rb +1 -0
- data/spec/sass/more_spec.rb +21 -0
- data/vendor/coffee-script/Cakefile +57 -0
- data/vendor/coffee-script/LICENSE +22 -0
- data/vendor/coffee-script/README +41 -0
- data/vendor/coffee-script/Rakefile +20 -0
- data/vendor/coffee-script/bin/cake +7 -0
- data/vendor/coffee-script/bin/coffee +7 -0
- data/vendor/coffee-script/documentation/coffee/aliases.coffee +9 -0
- data/vendor/coffee-script/documentation/coffee/arguments.coffee +4 -0
- data/vendor/coffee-script/documentation/coffee/array_comprehensions.coffee +7 -0
- data/vendor/coffee-script/documentation/coffee/assignment.coffee +2 -0
- data/vendor/coffee-script/documentation/coffee/cake_tasks.coffee +5 -0
- data/vendor/coffee-script/documentation/coffee/comparisons.coffee +5 -0
- data/vendor/coffee-script/documentation/coffee/conditionals.coffee +9 -0
- data/vendor/coffee-script/documentation/coffee/embedded.coffee +5 -0
- data/vendor/coffee-script/documentation/coffee/existence.coffee +8 -0
- data/vendor/coffee-script/documentation/coffee/expressions.coffee +9 -0
- data/vendor/coffee-script/documentation/coffee/expressions_assignment.coffee +1 -0
- data/vendor/coffee-script/documentation/coffee/expressions_comprehension.coffee +3 -0
- data/vendor/coffee-script/documentation/coffee/expressions_try.coffee +6 -0
- data/vendor/coffee-script/documentation/coffee/fat_arrow.coffee +6 -0
- data/vendor/coffee-script/documentation/coffee/functions.coffee +2 -0
- data/vendor/coffee-script/documentation/coffee/heredocs.coffee +5 -0
- data/vendor/coffee-script/documentation/coffee/multiple_return_values.coffee +5 -0
- data/vendor/coffee-script/documentation/coffee/object_comprehensions.coffee +4 -0
- data/vendor/coffee-script/documentation/coffee/object_extraction.coffee +13 -0
- data/vendor/coffee-script/documentation/coffee/objects_and_arrays.coffee +13 -0
- data/vendor/coffee-script/documentation/coffee/overview.coffee +29 -0
- data/vendor/coffee-script/documentation/coffee/parallel_assignment.coffee +4 -0
- data/vendor/coffee-script/documentation/coffee/range_comprehensions.coffee +6 -0
- data/vendor/coffee-script/documentation/coffee/scope.coffee +5 -0
- data/vendor/coffee-script/documentation/coffee/slices.coffee +6 -0
- data/vendor/coffee-script/documentation/coffee/soaks.coffee +1 -0
- data/vendor/coffee-script/documentation/coffee/splats.coffee +25 -0
- data/vendor/coffee-script/documentation/coffee/splices.coffee +5 -0
- data/vendor/coffee-script/documentation/coffee/strings.coffee +8 -0
- data/vendor/coffee-script/documentation/coffee/super.coffee +34 -0
- data/vendor/coffee-script/documentation/coffee/switch.coffee +10 -0
- data/vendor/coffee-script/documentation/coffee/try.coffee +7 -0
- data/vendor/coffee-script/documentation/coffee/while.coffee +10 -0
- data/vendor/coffee-script/documentation/css/docs.css +213 -0
- data/vendor/coffee-script/documentation/css/idle.css +63 -0
- data/vendor/coffee-script/documentation/css/logo.png +0 -0
- data/vendor/coffee-script/documentation/index.html.erb +967 -0
- data/vendor/coffee-script/documentation/js/aliases.js +14 -0
- data/vendor/coffee-script/documentation/js/arguments.js +8 -0
- data/vendor/coffee-script/documentation/js/array_comprehensions.js +26 -0
- data/vendor/coffee-script/documentation/js/assignment.js +5 -0
- data/vendor/coffee-script/documentation/js/cake_tasks.js +14 -0
- data/vendor/coffee-script/documentation/js/comparisons.js +5 -0
- data/vendor/coffee-script/documentation/js/conditionals.js +12 -0
- data/vendor/coffee-script/documentation/js/embedded.js +6 -0
- data/vendor/coffee-script/documentation/js/existence.js +7 -0
- data/vendor/coffee-script/documentation/js/expressions.js +13 -0
- data/vendor/coffee-script/documentation/js/expressions_assignment.js +4 -0
- data/vendor/coffee-script/documentation/js/expressions_comprehension.js +12 -0
- data/vendor/coffee-script/documentation/js/expressions_try.js +9 -0
- data/vendor/coffee-script/documentation/js/fat_arrow.js +15 -0
- data/vendor/coffee-script/documentation/js/functions.js +9 -0
- data/vendor/coffee-script/documentation/js/heredocs.js +4 -0
- data/vendor/coffee-script/documentation/js/intro.js +7 -0
- data/vendor/coffee-script/documentation/js/multiple_return_values.js +11 -0
- data/vendor/coffee-script/documentation/js/object_comprehensions.js +17 -0
- data/vendor/coffee-script/documentation/js/object_extraction.js +17 -0
- data/vendor/coffee-script/documentation/js/objects_and_arrays.js +10 -0
- data/vendor/coffee-script/documentation/js/overview.js +43 -0
- data/vendor/coffee-script/documentation/js/parallel_assignment.js +8 -0
- data/vendor/coffee-script/documentation/js/punctuation.js +8 -0
- data/vendor/coffee-script/documentation/js/range_comprehensions.js +21 -0
- data/vendor/coffee-script/documentation/js/scope.js +10 -0
- data/vendor/coffee-script/documentation/js/slices.js +6 -0
- data/vendor/coffee-script/documentation/js/soaks.js +4 -0
- data/vendor/coffee-script/documentation/js/splats.js +16 -0
- data/vendor/coffee-script/documentation/js/splices.js +5 -0
- data/vendor/coffee-script/documentation/js/strings.js +9 -0
- data/vendor/coffee-script/documentation/js/super.js +37 -0
- data/vendor/coffee-script/documentation/js/switch.js +18 -0
- data/vendor/coffee-script/documentation/js/try.js +10 -0
- data/vendor/coffee-script/documentation/js/while.js +22 -0
- data/vendor/coffee-script/documentation/underscore.html +627 -0
- data/vendor/coffee-script/examples/beautiful_code/binary_search.coffee +16 -0
- data/vendor/coffee-script/examples/beautiful_code/quicksort_runtime.coffee +13 -0
- data/vendor/coffee-script/examples/beautiful_code/regular_expression_matcher.coffee +34 -0
- data/vendor/coffee-script/examples/blocks.coffee +57 -0
- data/vendor/coffee-script/examples/code.coffee +173 -0
- data/vendor/coffee-script/examples/computer_science/README +4 -0
- data/vendor/coffee-script/examples/computer_science/binary_search.coffee +25 -0
- data/vendor/coffee-script/examples/computer_science/bubble_sort.coffee +11 -0
- data/vendor/coffee-script/examples/computer_science/linked_list.coffee +106 -0
- data/vendor/coffee-script/examples/computer_science/luhn_algorithm.coffee +36 -0
- data/vendor/coffee-script/examples/computer_science/merge_sort.coffee +19 -0
- data/vendor/coffee-script/examples/computer_science/selection_sort.coffee +23 -0
- data/vendor/coffee-script/examples/poignant.coffee +186 -0
- data/vendor/coffee-script/examples/potion.coffee +205 -0
- data/vendor/coffee-script/examples/underscore.coffee +603 -0
- data/vendor/coffee-script/examples/web_server.coffee +12 -0
- data/vendor/coffee-script/extras/CoffeeScript.tmbundle/Preferences/CoffeeScript.tmPreferences +24 -0
- data/vendor/coffee-script/extras/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage +361 -0
- data/vendor/coffee-script/extras/CoffeeScript.tmbundle/info.plist +10 -0
- data/vendor/coffee-script/extras/EXTRAS +20 -0
- data/vendor/coffee-script/extras/coffee.vim +117 -0
- data/vendor/coffee-script/index.html +1847 -0
- data/vendor/coffee-script/lib/bin/cake +7 -0
- data/vendor/coffee-script/lib/bin/coffee +7 -0
- data/vendor/coffee-script/lib/cake.js +80 -0
- data/vendor/coffee-script/lib/coffee-script.js +61 -0
- data/vendor/coffee-script/lib/command_line.js +201 -0
- data/vendor/coffee-script/lib/grammar.js +564 -0
- data/vendor/coffee-script/lib/lexer.js +405 -0
- data/vendor/coffee-script/lib/narwhal.js +44 -0
- data/vendor/coffee-script/lib/nodes.js +1328 -0
- data/vendor/coffee-script/lib/optparse.js +117 -0
- data/vendor/coffee-script/lib/parser.js +536 -0
- data/vendor/coffee-script/lib/repl.js +32 -0
- data/vendor/coffee-script/lib/rewriter.js +383 -0
- data/vendor/coffee-script/lib/scope.js +114 -0
- data/vendor/coffee-script/package.json +7 -0
- data/vendor/coffee-script/src/cake.coffee +45 -0
- data/vendor/coffee-script/src/coffee-script.coffee +45 -0
- data/vendor/coffee-script/src/command_line.coffee +130 -0
- data/vendor/coffee-script/src/grammar.coffee +456 -0
- data/vendor/coffee-script/src/lexer.coffee +327 -0
- data/vendor/coffee-script/src/narwhal.coffee +42 -0
- data/vendor/coffee-script/src/nodes.coffee +1045 -0
- data/vendor/coffee-script/src/optparse.coffee +79 -0
- data/vendor/coffee-script/src/repl.coffee +23 -0
- data/vendor/coffee-script/src/rewriter.coffee +253 -0
- data/vendor/coffee-script/src/scope.coffee +75 -0
- data/vendor/coffee-script/test/test_arguments.coffee +34 -0
- data/vendor/coffee-script/test/test_array_comprehension.coffee +42 -0
- data/vendor/coffee-script/test/test_assignment.coffee +26 -0
- data/vendor/coffee-script/test/test_blocks.coffee +4 -0
- data/vendor/coffee-script/test/test_calling_super.coffee +42 -0
- data/vendor/coffee-script/test/test_chained_calls.coffee +25 -0
- data/vendor/coffee-script/test/test_destructuring_assignment.coffee +62 -0
- data/vendor/coffee-script/test/test_everything.coffee +29 -0
- data/vendor/coffee-script/test/test_exceptions.coffee +2 -0
- data/vendor/coffee-script/test/test_existence.coffee +81 -0
- data/vendor/coffee-script/test/test_expressions.coffee +30 -0
- data/vendor/coffee-script/test/test_fancy_if_statement.coffee +26 -0
- data/vendor/coffee-script/test/test_functions.coffee +80 -0
- data/vendor/coffee-script/test/test_funky_comments.coffee +25 -0
- data/vendor/coffee-script/test/test_heredocs.coffee +46 -0
- data/vendor/coffee-script/test/test_lexical_scope.coffee +10 -0
- data/vendor/coffee-script/test/test_literals.coffee +56 -0
- data/vendor/coffee-script/test/test_nested_comprehensions.coffee +11 -0
- data/vendor/coffee-script/test/test_newline_escaping.coffee +6 -0
- data/vendor/coffee-script/test/test_operations.coffee +18 -0
- data/vendor/coffee-script/test/test_range_comprehension.coffee +20 -0
- data/vendor/coffee-script/test/test_ranges_and_slices.coffee +16 -0
- data/vendor/coffee-script/test/test_splats.coffee +47 -0
- data/vendor/coffee-script/test/test_splices.coffee +5 -0
- data/vendor/coffee-script/test/test_switch.coffee +64 -0
- data/vendor/coffee-script/test/test_while.coffee +30 -0
- data/vendor/coffee-script/vendor/jison/Jakefile +31 -0
- data/vendor/coffee-script/vendor/jison/README.md +347 -0
- data/vendor/coffee-script/vendor/jison/bin/jison +3 -0
- data/vendor/coffee-script/vendor/jison/bin/json2jison +3 -0
- data/vendor/coffee-script/vendor/jison/examples/ansic.jison +415 -0
- data/vendor/coffee-script/vendor/jison/examples/basic.json +8 -0
- data/vendor/coffee-script/vendor/jison/examples/basic2.json +9 -0
- data/vendor/coffee-script/vendor/jison/examples/basic2_lex.json +16 -0
- data/vendor/coffee-script/vendor/jison/examples/basic_lex.json +15 -0
- data/vendor/coffee-script/vendor/jison/examples/calculator.jison +38 -0
- data/vendor/coffee-script/vendor/jison/examples/calculator.jisonlex +14 -0
- data/vendor/coffee-script/vendor/jison/examples/calculator.json +42 -0
- data/vendor/coffee-script/vendor/jison/examples/classy.json +105 -0
- data/vendor/coffee-script/vendor/jison/examples/classy_ast.json +126 -0
- data/vendor/coffee-script/vendor/jison/examples/dism.json +25 -0
- data/vendor/coffee-script/vendor/jison/examples/dism_lr0.json +26 -0
- data/vendor/coffee-script/vendor/jison/examples/json.js +80 -0
- data/vendor/coffee-script/vendor/jison/examples/json_ast.js +83 -0
- data/vendor/coffee-script/vendor/jison/examples/precedence.json +26 -0
- data/vendor/coffee-script/vendor/jison/examples/reduce_conflict.json +13 -0
- data/vendor/coffee-script/vendor/jison/lib/jison/bnf.js +43 -0
- data/vendor/coffee-script/vendor/jison/lib/jison/jisonlex.js +18 -0
- data/vendor/coffee-script/vendor/jison/lib/jison/json2jison.js +146 -0
- data/vendor/coffee-script/vendor/jison/lib/jison/lexer.js +224 -0
- data/vendor/coffee-script/vendor/jison/lib/jison/util/bnf-parser.js +383 -0
- data/vendor/coffee-script/vendor/jison/lib/jison/util/lex-parser.js +407 -0
- data/vendor/coffee-script/vendor/jison/lib/jison/util/set.js +94 -0
- data/vendor/coffee-script/vendor/jison/lib/jison/util/typal.js +90 -0
- data/vendor/coffee-script/vendor/jison/lib/jison.js +1414 -0
- data/vendor/coffee-script/vendor/jison/package.json +14 -0
- data/vendor/coffee-script/vendor/jison/src/bnf.jison +110 -0
- data/vendor/coffee-script/vendor/jison/src/bnf.jisonlex +25 -0
- data/vendor/coffee-script/vendor/jison/src/bnf.lex.json +24 -0
- data/vendor/coffee-script/vendor/jison/src/jisonlex.jison +129 -0
- data/vendor/coffee-script/vendor/jison/src/jisonlex.jisonlex +31 -0
- data/vendor/coffee-script/vendor/jison/src/jisonlex.lex.json +30 -0
- data/vendor/coffee-script/vendor/jison/tests/all-tests.js +8 -0
- data/vendor/coffee-script/vendor/jison/tests/grammar/bnf.js +91 -0
- data/vendor/coffee-script/vendor/jison/tests/grammar/bnf_parse.js +65 -0
- data/vendor/coffee-script/vendor/jison/tests/grammar/grammar-tests.js +10 -0
- data/vendor/coffee-script/vendor/jison/tests/grammar/json2jison.js +24 -0
- data/vendor/coffee-script/vendor/jison/tests/grammar/lex/ansic.jisonlex +115 -0
- data/vendor/coffee-script/vendor/jison/tests/grammar/lex/bnf.jisonlex +25 -0
- data/vendor/coffee-script/vendor/jison/tests/grammar/lex/bnf.lex.json +24 -0
- data/vendor/coffee-script/vendor/jison/tests/grammar/lex/lex_grammar.jisonlex +31 -0
- data/vendor/coffee-script/vendor/jison/tests/grammar/lex/lex_grammar.lex.json +30 -0
- data/vendor/coffee-script/vendor/jison/tests/grammar/lex.jison +119 -0
- data/vendor/coffee-script/vendor/jison/tests/grammar/lex.js +58 -0
- data/vendor/coffee-script/vendor/jison/tests/grammar/lex_parse.js +117 -0
- data/vendor/coffee-script/vendor/jison/tests/lexer/lexer-tests.js +6 -0
- data/vendor/coffee-script/vendor/jison/tests/lexer/regexplexer.js +417 -0
- data/vendor/coffee-script/vendor/jison/tests/parser/actions.js +311 -0
- data/vendor/coffee-script/vendor/jison/tests/parser/api.js +236 -0
- data/vendor/coffee-script/vendor/jison/tests/parser/generator.js +196 -0
- data/vendor/coffee-script/vendor/jison/tests/parser/lalr.js +183 -0
- data/vendor/coffee-script/vendor/jison/tests/parser/lr0.js +72 -0
- data/vendor/coffee-script/vendor/jison/tests/parser/lr1.js +119 -0
- data/vendor/coffee-script/vendor/jison/tests/parser/parser-tests.js +14 -0
- data/vendor/coffee-script/vendor/jison/tests/parser/precedence.js +237 -0
- data/vendor/coffee-script/vendor/jison/tests/parser/slr.js +52 -0
- data/vendor/coffee-script/vendor/jison/tests/parser/tables.js +126 -0
- data/vendor/coffee-script/vendor/jison/tests/performance.js +110 -0
- data/vendor/coffee-script/vendor/jison/tests/setup.js +3 -0
- metadata +324 -0
@@ -0,0 +1,1414 @@
|
|
1
|
+
// Jison, an LR(0), SLR(1), LARL(1), LR(1) Parser Generator
|
2
|
+
// Zachary Carter <zach@carter.name>
|
3
|
+
// MIT X Licensed
|
4
|
+
|
5
|
+
if (typeof exports === 'undefined') {
|
6
|
+
exports = {};
|
7
|
+
} else {
|
8
|
+
// assume we're in commonjs land
|
9
|
+
//var system = require("system");
|
10
|
+
var typal = require('./jison/util/typal').typal;
|
11
|
+
var Set = require('./jison/util/set').Set;
|
12
|
+
var RegExpLexer = require('./jison/lexer').RegExpLexer;
|
13
|
+
}
|
14
|
+
|
15
|
+
var Jison = exports.Jison = exports;
|
16
|
+
|
17
|
+
// detect print
|
18
|
+
if (typeof puts !== 'undefined') {
|
19
|
+
Jison.print = function print () { puts([].join.call(arguments, ' ')); };
|
20
|
+
} else if (typeof print !== 'undefined') {
|
21
|
+
Jison.print = print;
|
22
|
+
} else {
|
23
|
+
Jison.print = function print () {};
|
24
|
+
}
|
25
|
+
|
26
|
+
Jison.Parser = (function () {
|
27
|
+
|
28
|
+
// iterator utility
|
29
|
+
function each (obj, func) {
|
30
|
+
if (obj.forEach) {
|
31
|
+
obj.forEach(func);
|
32
|
+
} else {
|
33
|
+
var p;
|
34
|
+
for (p in obj) {
|
35
|
+
if (obj.hasOwnProperty(p)) {
|
36
|
+
func.call(obj, obj[p], p, obj);
|
37
|
+
}
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
var Nonterminal = typal.construct({
|
43
|
+
constructor: function Nonterminal (symbol) {
|
44
|
+
this.symbol = symbol;
|
45
|
+
this.productions = new Set();
|
46
|
+
this.first = [];
|
47
|
+
this.follows = [];
|
48
|
+
this.nullable = false;
|
49
|
+
},
|
50
|
+
toString: function Nonterminal_toString () {
|
51
|
+
var str = this.symbol+"\n";
|
52
|
+
str += (this.nullable ? 'nullable' : 'not nullable');
|
53
|
+
str += "\nFirsts: "+this.first.join(', ');
|
54
|
+
str += "\nFollows: "+this.first.join(', ');
|
55
|
+
str += "\nProductions:\n "+this.productions.join('\n ');
|
56
|
+
|
57
|
+
return str;
|
58
|
+
}
|
59
|
+
});
|
60
|
+
|
61
|
+
var Production = typal.construct({
|
62
|
+
constructor: function Production (symbol, handle, id) {
|
63
|
+
this.symbol = symbol;
|
64
|
+
this.handle = handle;
|
65
|
+
this.nullable = false;
|
66
|
+
this.id = id;
|
67
|
+
this.first = [];
|
68
|
+
this.precedence = 0;
|
69
|
+
},
|
70
|
+
toString: function Production_toString () {
|
71
|
+
return this.symbol+" -> "+this.handle.join(' ');
|
72
|
+
}
|
73
|
+
});
|
74
|
+
|
75
|
+
var generator = typal.beget();
|
76
|
+
|
77
|
+
generator.constructor = function Jison_Generator (grammar, opt) {
|
78
|
+
if (typeof grammar === 'string') {
|
79
|
+
grammar = require("jison/bnf").parse(grammar);
|
80
|
+
}
|
81
|
+
|
82
|
+
var options = typal.mix.call({}, grammar.options, opt);
|
83
|
+
this.terms = {};
|
84
|
+
this.operators = {};
|
85
|
+
this.productions = [];
|
86
|
+
this.conflicts = 0;
|
87
|
+
this.resolutions = [];
|
88
|
+
this.options = options;
|
89
|
+
this.yy = {}; // accessed as yy free variable in the parser/lexer actions
|
90
|
+
|
91
|
+
// source included in semantic action execution scope
|
92
|
+
if (grammar.actionInclude) {
|
93
|
+
if (typeof grammar.actionInclude === 'function') {
|
94
|
+
grammar.actionInclude = String(grammar.actionInclude).replace(/^\s*function \(\) \{/, '').replace(/\}\s*$/, '');
|
95
|
+
}
|
96
|
+
this.actionInclude = grammar.actionInclude;
|
97
|
+
}
|
98
|
+
|
99
|
+
this.DEBUG = options.debug || false;
|
100
|
+
if (this.DEBUG) this.mix(generatorDebug); // mixin debug methods
|
101
|
+
|
102
|
+
this.processGrammar(grammar);
|
103
|
+
|
104
|
+
if (grammar.lex) {
|
105
|
+
this.lexer = new RegExpLexer(grammar.lex, null, this.terminals_);
|
106
|
+
}
|
107
|
+
};
|
108
|
+
|
109
|
+
generator.processGrammar = function processGrammarDef (grammar) {
|
110
|
+
var bnf = grammar.bnf,
|
111
|
+
tokens = grammar.tokens,
|
112
|
+
nonterminals = this.nonterminals = {},
|
113
|
+
productions = this.productions,
|
114
|
+
self = this;
|
115
|
+
|
116
|
+
if (tokens) {
|
117
|
+
if (typeof tokens === 'string') {
|
118
|
+
tokens = tokens.trim().split(' ');
|
119
|
+
} else {
|
120
|
+
tokens = tokens.slice(0);
|
121
|
+
}
|
122
|
+
}
|
123
|
+
|
124
|
+
var symbols = this.symbols = [];
|
125
|
+
|
126
|
+
// calculate precedence of operators
|
127
|
+
var operators = this.operators = processOperators(grammar.operators);
|
128
|
+
|
129
|
+
// build productions from cfg
|
130
|
+
this.buildProductions(grammar.bnf, productions, nonterminals, symbols, operators);
|
131
|
+
|
132
|
+
if (tokens && this.terminals.length !== tokens.length) {
|
133
|
+
self.trace("Warning: declared tokens differ from tokens found in rules.");
|
134
|
+
self.trace(this.terminals);
|
135
|
+
self.trace(tokens);
|
136
|
+
}
|
137
|
+
|
138
|
+
// augment the grammar
|
139
|
+
this.augmentGrammar(grammar);
|
140
|
+
};
|
141
|
+
|
142
|
+
generator.augmentGrammar = function augmentGrammar (grammar) {
|
143
|
+
// use specified start symbol, or default to first user defined production
|
144
|
+
this.startSymbol = grammar.start || grammar.startSymbol || this.productions[0].symbol;
|
145
|
+
if (!this.nonterminals[this.startSymbol]) {
|
146
|
+
throw new Error("Grammar error: startSymbol must be a non-terminal found in your grammar.");
|
147
|
+
}
|
148
|
+
this.EOF = "$end";
|
149
|
+
|
150
|
+
// augment the grammar
|
151
|
+
var acceptProduction = new Production('$accept', [this.startSymbol, '$end'], 0);
|
152
|
+
this.productions.unshift(acceptProduction);
|
153
|
+
|
154
|
+
// prepend parser tokens
|
155
|
+
this.symbols.unshift("$accept","$end");
|
156
|
+
this.symbols_["$accept"] = 0;
|
157
|
+
this.symbols_["$end"] = 1;
|
158
|
+
this.terminals.unshift("$end");
|
159
|
+
|
160
|
+
this.nonterminals["$accept"] = new Nonterminal("$accept");
|
161
|
+
this.nonterminals["$accept"].productions.push(acceptProduction);
|
162
|
+
|
163
|
+
// add follow $ to start symbol
|
164
|
+
this.nonterminals[this.startSymbol].follows.push(this.EOF);
|
165
|
+
};
|
166
|
+
|
167
|
+
// set precedence and associativity of operators
|
168
|
+
function processOperators (ops) {
|
169
|
+
if (!ops) return {};
|
170
|
+
var operators = {};
|
171
|
+
for (var i=0,k,prec;prec=ops[i]; i++) {
|
172
|
+
for (k=1;k < prec.length;k++) {
|
173
|
+
operators[prec[k]] = {precedence: i+1, assoc: prec[0]};
|
174
|
+
}
|
175
|
+
}
|
176
|
+
return operators;
|
177
|
+
}
|
178
|
+
|
179
|
+
|
180
|
+
generator.buildProductions = function buildProductions(bnf, productions, nonterminals, symbols, operators) {
|
181
|
+
var actions = [this.actionInclude || "", "var $$ = arguments[5],$0=arguments[5].length;",'switch(arguments[4]) {'],
|
182
|
+
prods, symbol;
|
183
|
+
var productions_ = [0];
|
184
|
+
var symbolId = 1;
|
185
|
+
var symbols_ = {};
|
186
|
+
|
187
|
+
function addSymbol (s) {
|
188
|
+
if (s && !symbols_[s]) {
|
189
|
+
symbols_[s] = ++symbolId;
|
190
|
+
symbols.push(s);
|
191
|
+
}
|
192
|
+
}
|
193
|
+
|
194
|
+
for (symbol in bnf) {
|
195
|
+
if (!bnf.hasOwnProperty(symbol)) continue;
|
196
|
+
|
197
|
+
addSymbol(symbol);
|
198
|
+
nonterminals[symbol] = new Nonterminal(symbol);
|
199
|
+
|
200
|
+
if (typeof bnf[symbol] === 'string') {
|
201
|
+
prods = bnf[symbol].split(/\s*\|\s*/g);
|
202
|
+
} else {
|
203
|
+
prods = bnf[symbol].slice(0);
|
204
|
+
}
|
205
|
+
|
206
|
+
prods.forEach(function buildProds_forEach (handle) {
|
207
|
+
var r, rhs, i;
|
208
|
+
if (handle.constructor === Array) {
|
209
|
+
if (typeof handle[0] === 'string')
|
210
|
+
rhs = handle[0].trim().split(' ');
|
211
|
+
else
|
212
|
+
rhs = handle[0].slice(0);
|
213
|
+
|
214
|
+
for (i=0; i<rhs.length; i++) if (!symbols_[rhs[i]]) {
|
215
|
+
addSymbol(rhs[i]);
|
216
|
+
}
|
217
|
+
|
218
|
+
if (typeof handle[1] === 'string' || handle.length == 3) {
|
219
|
+
// semantic action specified
|
220
|
+
var action = 'case '+(productions.length+1)+':'+handle[1]+'\nbreak;';
|
221
|
+
|
222
|
+
// replace named semantic values ($nonterminal)
|
223
|
+
if (action.match(/\$[a-zA-Z][a-zA-Z0-9_]*/)) {
|
224
|
+
var count = {},
|
225
|
+
names = {};
|
226
|
+
for (i=0;i<rhs.length;i++) {
|
227
|
+
if (names[rhs[i]]) {
|
228
|
+
names[rhs[i]+(++count[rhs[i]])] = i+1;
|
229
|
+
} else {
|
230
|
+
names[rhs[i]] = i+1;
|
231
|
+
names[rhs[i]+"1"] = i+1;
|
232
|
+
count[rhs[i]] = 1;
|
233
|
+
}
|
234
|
+
}
|
235
|
+
action = action.replace(/\$([a-zA-Z][a-zA-Z0-9_]*)/g, function (str, pl) {
|
236
|
+
return names[pl] ? '$'+names[pl] : pl;
|
237
|
+
});
|
238
|
+
}
|
239
|
+
action = action.replace(/\$(?:0|\$)/g, "this.$")
|
240
|
+
.replace(/\$(\d+)/g, "$$$[\$0-"+rhs.length+"+$1-1]");
|
241
|
+
actions.push(action);
|
242
|
+
|
243
|
+
r = new Production(symbol, rhs, productions.length+1);
|
244
|
+
// precedence specified also
|
245
|
+
if (handle[2]) {
|
246
|
+
r.precedence = operators[handle[2].prec].precedence;
|
247
|
+
}
|
248
|
+
} else {
|
249
|
+
// only precedence specified
|
250
|
+
r = new Production(symbol, rhs, productions.length+1);
|
251
|
+
r.precedence = operators[handle[1].prec].precedence;
|
252
|
+
}
|
253
|
+
} else {
|
254
|
+
rhs = handle.trim().split(' ');
|
255
|
+
for (i=0; i<rhs.length; i++) if (!symbols_[rhs[i]]) {
|
256
|
+
addSymbol(rhs[i]);
|
257
|
+
}
|
258
|
+
r = new Production(symbol, rhs, productions.length+1);
|
259
|
+
}
|
260
|
+
if (r.precedence === 0) {
|
261
|
+
// set precedence
|
262
|
+
for (i=r.handle.length-1; i>=0; i--) {
|
263
|
+
if (!(r.handle[i] in nonterminals) && r.handle[i] in operators) {
|
264
|
+
r.precedence = operators[r.handle[i]].precedence;
|
265
|
+
}
|
266
|
+
}
|
267
|
+
}
|
268
|
+
|
269
|
+
productions.push(r);
|
270
|
+
productions_.push([symbols_[r.symbol], r.handle[0] === '' ? 0 : r.handle.length]);
|
271
|
+
nonterminals[symbol].productions.push(r);
|
272
|
+
});
|
273
|
+
}
|
274
|
+
|
275
|
+
var sym, terms = [], terms_ = {};
|
276
|
+
each(symbols_, function (id, sym) {
|
277
|
+
if (!nonterminals[sym]) {
|
278
|
+
terms.push(sym);
|
279
|
+
terms_[id] = sym;
|
280
|
+
}
|
281
|
+
});
|
282
|
+
|
283
|
+
this.terminals = terms;
|
284
|
+
this.terminals_ = terms_;
|
285
|
+
this.symbols_ = symbols_;
|
286
|
+
|
287
|
+
this.productions_ = productions_;
|
288
|
+
actions.push('}');
|
289
|
+
this.performAction = Function("yytext","yyleng","yylineno","yy", actions.join("\n"));
|
290
|
+
};
|
291
|
+
|
292
|
+
generator.createParser = function createParser () {
|
293
|
+
throw 'Calling abstract method.';
|
294
|
+
};
|
295
|
+
|
296
|
+
// noop. implemented in debug mixin
|
297
|
+
generator.trace = function trace () { };
|
298
|
+
|
299
|
+
generator.warn = function warn () {
|
300
|
+
Jison.print.apply(null,arguments);
|
301
|
+
};
|
302
|
+
|
303
|
+
generator.error = function error (msg) {
|
304
|
+
throw msg;
|
305
|
+
};
|
306
|
+
|
307
|
+
// Generator debug mixin
|
308
|
+
|
309
|
+
var generatorDebug = {
|
310
|
+
trace: function trace () {
|
311
|
+
Jison.print.apply(null, arguments);
|
312
|
+
},
|
313
|
+
beforeprocessGrammar: function () {
|
314
|
+
this.trace("Processing grammar.");
|
315
|
+
},
|
316
|
+
afteraugmentGrammar: function () {
|
317
|
+
var trace = this.trace;
|
318
|
+
each(this.symbols, function (sym, i) {
|
319
|
+
trace(sym+"("+i+")");
|
320
|
+
});
|
321
|
+
}
|
322
|
+
};
|
323
|
+
|
324
|
+
|
325
|
+
|
326
|
+
/*
|
327
|
+
* Mixin for common behaviors of lookahead parsers
|
328
|
+
* */
|
329
|
+
var lookaheadMixin = {};
|
330
|
+
|
331
|
+
lookaheadMixin.computeLookaheads = function computeLookaheads () {
|
332
|
+
if (this.DEBUG) this.mix(lookaheadDebug); // mixin debug methods
|
333
|
+
|
334
|
+
this.computeLookaheads = function () {};
|
335
|
+
this.nullableSets();
|
336
|
+
this.firstSets();
|
337
|
+
this.followSets();
|
338
|
+
};
|
339
|
+
|
340
|
+
// calculate follow sets typald on first and nullable
|
341
|
+
lookaheadMixin.followSets = function followSets () {
|
342
|
+
var productions = this.productions,
|
343
|
+
nonterminals = this.nonterminals,
|
344
|
+
self = this,
|
345
|
+
cont = true;
|
346
|
+
|
347
|
+
// loop until no further changes have been made
|
348
|
+
while(cont) {
|
349
|
+
cont = false;
|
350
|
+
|
351
|
+
productions.forEach(function Follow_prod_forEach (production, k) {
|
352
|
+
//self.trace(production.symbol,nonterminals[production.symbol].follows);
|
353
|
+
// q is used in Simple LALR algorithm determine follows in context
|
354
|
+
var q;
|
355
|
+
var ctx = !!self.go_;
|
356
|
+
|
357
|
+
var set = [],oldcount;
|
358
|
+
for (var i=0,t;t=production.handle[i];++i) {
|
359
|
+
if (!nonterminals[t]) continue;
|
360
|
+
|
361
|
+
// for Simple LALR algorithm, self.go_ checks if
|
362
|
+
if (ctx)
|
363
|
+
q = self.go_(production.symbol, production.handle.slice(0, i));
|
364
|
+
var bool = !ctx || q === parseInt(self.nterms_[t]);
|
365
|
+
|
366
|
+
if (i === production.handle.length+1 && bool) {
|
367
|
+
set = nonterminals[production.symbol].follows
|
368
|
+
} else {
|
369
|
+
var part = production.handle.slice(i+1);
|
370
|
+
|
371
|
+
set = self.first(part);
|
372
|
+
if (self.nullable(part) && bool) {
|
373
|
+
set.push.apply(set, nonterminals[production.symbol].follows);
|
374
|
+
}
|
375
|
+
}
|
376
|
+
oldcount = nonterminals[t].follows.length;
|
377
|
+
Set.union(nonterminals[t].follows, set);
|
378
|
+
if (oldcount !== nonterminals[t].follows.length) {
|
379
|
+
cont = true;
|
380
|
+
}
|
381
|
+
}
|
382
|
+
});
|
383
|
+
}
|
384
|
+
};
|
385
|
+
|
386
|
+
// return the FIRST set of a symbol or series of symbols
|
387
|
+
lookaheadMixin.first = function first (symbol) {
|
388
|
+
// epsilon
|
389
|
+
if (symbol === '') {
|
390
|
+
return [];
|
391
|
+
// RHS
|
392
|
+
} else if (symbol instanceof Array) {
|
393
|
+
var firsts = [];
|
394
|
+
for (var i=0,t;t=symbol[i];++i) {
|
395
|
+
this.first(t).forEach(function first_forEach (e) {
|
396
|
+
if (firsts.indexOf(e)===-1)
|
397
|
+
firsts.push(e);
|
398
|
+
});
|
399
|
+
if (!this.nullable(t))
|
400
|
+
break;
|
401
|
+
}
|
402
|
+
return firsts;
|
403
|
+
// terminal
|
404
|
+
} else if (!this.nonterminals[symbol]) {
|
405
|
+
return [symbol];
|
406
|
+
// nonterminal
|
407
|
+
} else {
|
408
|
+
return this.nonterminals[symbol].first;
|
409
|
+
}
|
410
|
+
};
|
411
|
+
|
412
|
+
// fixed-point calculation of FIRST sets
|
413
|
+
lookaheadMixin.firstSets = function firstSets () {
|
414
|
+
var productions = this.productions,
|
415
|
+
nonterminals = this.nonterminals,
|
416
|
+
self = this,
|
417
|
+
cont = true,
|
418
|
+
symbol,firsts;
|
419
|
+
|
420
|
+
// loop until no further changes have been made
|
421
|
+
while(cont) {
|
422
|
+
cont = false;
|
423
|
+
|
424
|
+
productions.forEach(function FirstSets_forEach (production, k) {
|
425
|
+
var firsts = self.first(production.handle);
|
426
|
+
if (firsts.length !== production.first.length) {
|
427
|
+
production.first = firsts;
|
428
|
+
cont=true;
|
429
|
+
}
|
430
|
+
});
|
431
|
+
|
432
|
+
for (symbol in nonterminals) {
|
433
|
+
firsts = [];
|
434
|
+
nonterminals[symbol].productions.forEach(function (production) {
|
435
|
+
Set.union(firsts, production.first);
|
436
|
+
});
|
437
|
+
if (firsts.length !== nonterminals[symbol].first.length) {
|
438
|
+
nonterminals[symbol].first = firsts;
|
439
|
+
cont=true;
|
440
|
+
}
|
441
|
+
}
|
442
|
+
}
|
443
|
+
};
|
444
|
+
|
445
|
+
// fixed-point calculation of NULLABLE
|
446
|
+
lookaheadMixin.nullableSets = function nullableSets () {
|
447
|
+
var firsts = this.firsts = {},
|
448
|
+
nonterminals = this.nonterminals,
|
449
|
+
self = this,
|
450
|
+
cont = true;
|
451
|
+
|
452
|
+
// loop until no further changes have been made
|
453
|
+
while(cont) {
|
454
|
+
cont = false;
|
455
|
+
|
456
|
+
// check if each production is nullable
|
457
|
+
this.productions.forEach(function (production, k) {
|
458
|
+
if (!production.nullable) {
|
459
|
+
for (var i=0,n=0,t;t=production.handle[i];++i) {
|
460
|
+
if (self.nullable(t)) n++;
|
461
|
+
}
|
462
|
+
if (n===i) { // production is nullable if all tokens are nullable
|
463
|
+
production.nullable = cont = true;
|
464
|
+
}
|
465
|
+
}
|
466
|
+
});
|
467
|
+
|
468
|
+
//check if each symbol is nullable
|
469
|
+
for (var symbol in nonterminals) {
|
470
|
+
if (!this.nullable(symbol)) {
|
471
|
+
for (var i=0,production;production=nonterminals[symbol].productions.item(i);i++) {
|
472
|
+
if (production.nullable)
|
473
|
+
nonterminals[symbol].nullable = cont = true;
|
474
|
+
}
|
475
|
+
}
|
476
|
+
}
|
477
|
+
}
|
478
|
+
};
|
479
|
+
|
480
|
+
// check if a token or series of tokens is nullable
|
481
|
+
lookaheadMixin.nullable = function nullable (symbol) {
|
482
|
+
// epsilon
|
483
|
+
if (symbol === '') {
|
484
|
+
return true
|
485
|
+
// RHS
|
486
|
+
} else if (symbol instanceof Array) {
|
487
|
+
for (var i=0,t;t=symbol[i];++i) {
|
488
|
+
if (!this.nullable(t))
|
489
|
+
return false;
|
490
|
+
}
|
491
|
+
return true;
|
492
|
+
// terminal
|
493
|
+
} else if (!this.nonterminals[symbol]) {
|
494
|
+
return false;
|
495
|
+
// nonterminal
|
496
|
+
} else {
|
497
|
+
return this.nonterminals[symbol].nullable;
|
498
|
+
}
|
499
|
+
};
|
500
|
+
|
501
|
+
|
502
|
+
// lookahead debug mixin
|
503
|
+
var lookaheadDebug = {
|
504
|
+
beforenullableSets: function () {
|
505
|
+
this.trace("Computing Nullable sets.");
|
506
|
+
},
|
507
|
+
beforefirstSets: function () {
|
508
|
+
this.trace("Computing First sets.");
|
509
|
+
},
|
510
|
+
beforefollowSets: function () {
|
511
|
+
this.trace("Computing Follow sets.");
|
512
|
+
},
|
513
|
+
afterfollowSets: function () {
|
514
|
+
var trace = this.trace;
|
515
|
+
each(this.nonterminals, function (nt, t) {
|
516
|
+
trace(nt, '\n');
|
517
|
+
});
|
518
|
+
}
|
519
|
+
};
|
520
|
+
|
521
|
+
/*
|
522
|
+
* Mixin for common LR parser behavior
|
523
|
+
* */
|
524
|
+
var lrGeneratorMixin = {};
|
525
|
+
|
526
|
+
lrGeneratorMixin.buildTable = function buildTable () {
|
527
|
+
if (this.DEBUG) this.mix(lrGeneratorDebug); // mixin debug methods
|
528
|
+
|
529
|
+
this.states = this.canonicalCollection();
|
530
|
+
this.table = this.parseTable(this.states);
|
531
|
+
};
|
532
|
+
|
533
|
+
lrGeneratorMixin.Item = typal.construct({
|
534
|
+
constructor: function Item(production, dot, f, predecessor) {
|
535
|
+
this.production = production;
|
536
|
+
this.dotPosition = dot || 0;
|
537
|
+
this.follows = f || [];
|
538
|
+
this.predecessor = predecessor;
|
539
|
+
this.id = parseInt(production.id+'a'+this.dotPosition, 36);
|
540
|
+
this.markedSymbol = this.production.handle[this.dotPosition];
|
541
|
+
},
|
542
|
+
remainingHandle: function () {
|
543
|
+
return this.production.handle.slice(this.dotPosition+1);
|
544
|
+
},
|
545
|
+
eq: function (e) {
|
546
|
+
return e.id === this.id;
|
547
|
+
},
|
548
|
+
toString: function () {
|
549
|
+
var temp = this.production.handle.slice(0);
|
550
|
+
temp[this.dotPosition] = '.'+(temp[this.dotPosition]||'');
|
551
|
+
return '['+this.production.symbol+" -> "+temp.join(' ')
|
552
|
+
+(this.follows.length === 0 ? "" : ", "+this.follows.join('/'))
|
553
|
+
+']';
|
554
|
+
}
|
555
|
+
});
|
556
|
+
|
557
|
+
lrGeneratorMixin.ItemSet = Set.prototype.construct({
|
558
|
+
afterconstructor: function () {
|
559
|
+
this.reductions = [];
|
560
|
+
this.goes = {};
|
561
|
+
this.edges = {};
|
562
|
+
this.shifts = false;
|
563
|
+
this.inadequate = false;
|
564
|
+
this.hash_ = {};
|
565
|
+
for (var i=this._items.length-1;i >=0;i--) {
|
566
|
+
this.hash_[this._items[i].id] = true; //i;
|
567
|
+
}
|
568
|
+
},
|
569
|
+
concat: function concat (set) {
|
570
|
+
var a = set._items || set;
|
571
|
+
for (var i=a.length-1;i >=0;i--) {
|
572
|
+
this.hash_[a[i].id] = true; //i;
|
573
|
+
}
|
574
|
+
this._items.push.apply(this._items, a);
|
575
|
+
return this;
|
576
|
+
},
|
577
|
+
push: function (item) {
|
578
|
+
this.hash_[item.id] = true;
|
579
|
+
return this._items.push(item);
|
580
|
+
},
|
581
|
+
contains: function (item) {
|
582
|
+
return this.hash_[item.id];
|
583
|
+
},
|
584
|
+
toValue: function toValue () {
|
585
|
+
var v = this.items_.sort().join('|');
|
586
|
+
return (this.toValue = function toValue_inner() {return v;})();
|
587
|
+
}
|
588
|
+
});
|
589
|
+
|
590
|
+
lrGeneratorMixin.closureOperation = function closureOperation (itemSet /*, closureSet*/) {
|
591
|
+
var closureSet = new this.ItemSet();
|
592
|
+
var self = this;
|
593
|
+
|
594
|
+
var set = itemSet,
|
595
|
+
itemQueue, syms = {};
|
596
|
+
|
597
|
+
do {
|
598
|
+
itemQueue = new Set();
|
599
|
+
closureSet.concat(set);
|
600
|
+
set.forEach(function CO_set_forEach (item) {
|
601
|
+
var symbol = item.markedSymbol;
|
602
|
+
|
603
|
+
// if token is a non-terminal, recursively add closures
|
604
|
+
if (symbol && self.nonterminals[symbol]) {
|
605
|
+
if(!syms[symbol]) {
|
606
|
+
self.nonterminals[symbol].productions.forEach(function CO_nt_forEach (production) {
|
607
|
+
var newItem = new self.Item(production, 0);
|
608
|
+
if(!closureSet.contains(newItem))
|
609
|
+
itemQueue.push(newItem);
|
610
|
+
});
|
611
|
+
syms[symbol] = true;
|
612
|
+
}
|
613
|
+
} else if (!symbol) {
|
614
|
+
// reduction
|
615
|
+
closureSet.reductions.push(item);
|
616
|
+
closureSet.inadequate = closureSet.reductions.length > 1 || closureSet.shifts;
|
617
|
+
} else {
|
618
|
+
// shift
|
619
|
+
closureSet.shifts = true;
|
620
|
+
closureSet.inadequate = closureSet.reductions.length > 0;
|
621
|
+
}
|
622
|
+
});
|
623
|
+
|
624
|
+
set = itemQueue;
|
625
|
+
|
626
|
+
} while (!itemQueue.isEmpty());
|
627
|
+
|
628
|
+
return closureSet;
|
629
|
+
};
|
630
|
+
|
631
|
+
lrGeneratorMixin.gotoOperation = function gotoOperation (itemSet, symbol) {
|
632
|
+
var gotoSet = new this.ItemSet(),
|
633
|
+
EOF = this.EOF,
|
634
|
+
self = this;
|
635
|
+
|
636
|
+
itemSet.forEach(function goto_forEach(item, n) {
|
637
|
+
if (item.markedSymbol === symbol && symbol !== EOF) {
|
638
|
+
gotoSet.push(new self.Item(item.production, item.dotPosition+1, item.follows, n));
|
639
|
+
}
|
640
|
+
});
|
641
|
+
|
642
|
+
return gotoSet.isEmpty() ? gotoSet : this.closureOperation(gotoSet);
|
643
|
+
};
|
644
|
+
|
645
|
+
/* Create unique set of item sets
|
646
|
+
* */
|
647
|
+
lrGeneratorMixin.canonicalCollection = function canonicalCollection () {
|
648
|
+
var item1 = new this.Item(this.productions[0], 0, new Set(this.EOF));
|
649
|
+
var firstState = this.closureOperation(new this.ItemSet(item1)),
|
650
|
+
states = new Set(firstState),
|
651
|
+
marked = 0,
|
652
|
+
self = this,
|
653
|
+
itemSet;
|
654
|
+
|
655
|
+
while (marked !== states.size()) {
|
656
|
+
itemSet = states.item(marked); marked++;
|
657
|
+
itemSet.forEach(function CC_itemSet_forEach(item) {
|
658
|
+
if(item.markedSymbol)
|
659
|
+
self.canonicalCollectionInsert(item.markedSymbol, itemSet, states, marked-1);
|
660
|
+
});
|
661
|
+
}
|
662
|
+
|
663
|
+
return states;
|
664
|
+
};
|
665
|
+
|
666
|
+
// Pushes a unique state into the que. Some parsing algorithms may perform additional operations
|
667
|
+
lrGeneratorMixin.canonicalCollectionInsert = function canonicalCollectionInsert (symbol, itemSet, states, stateNum) {
|
668
|
+
var g = this.gotoOperation(itemSet, symbol);
|
669
|
+
if (!g.predecessors)
|
670
|
+
g.predecessors = {};
|
671
|
+
// add g to que if not empty or duplicate
|
672
|
+
if (!g.isEmpty()) {
|
673
|
+
var i = states.indexOf(g);
|
674
|
+
if (i === -1) {
|
675
|
+
itemSet.edges[symbol] = states.size(); // store goto transition for table
|
676
|
+
states.push(g);
|
677
|
+
g.predecessors[symbol] = [stateNum];
|
678
|
+
} else {
|
679
|
+
itemSet.edges[symbol] = i; // store goto transition for table
|
680
|
+
states.item(i).predecessors[symbol].push(stateNum);
|
681
|
+
}
|
682
|
+
}
|
683
|
+
};
|
684
|
+
|
685
|
+
lrGeneratorMixin.parseTable = function parseTable (itemSets) {
|
686
|
+
var states = [],
|
687
|
+
nonterminals = this.nonterminals,
|
688
|
+
operators = this.operators,
|
689
|
+
self = this,
|
690
|
+
s = 1, // shift
|
691
|
+
r = 2, // reduce
|
692
|
+
a = 3; // accept
|
693
|
+
|
694
|
+
// for each item set
|
695
|
+
itemSets.forEach(function (itemSet, k) {
|
696
|
+
var state = states[k] = {};
|
697
|
+
var action, stackSymbol;
|
698
|
+
|
699
|
+
// set shift and goto actions
|
700
|
+
for (stackSymbol in itemSet.edges) {
|
701
|
+
itemSet.forEach(function (item, j) {
|
702
|
+
// find shift and goto actions
|
703
|
+
if (item.markedSymbol == stackSymbol) {
|
704
|
+
var gotoState = itemSet.edges[stackSymbol];
|
705
|
+
if (nonterminals[stackSymbol]) {
|
706
|
+
// store state to go to after a reduce
|
707
|
+
//self.trace(k, stackSymbol, 'g'+gotoState);
|
708
|
+
state[self.symbols_[stackSymbol]] = gotoState;
|
709
|
+
} else {
|
710
|
+
//self.trace(k, stackSymbol, 's'+gotoState);
|
711
|
+
state[self.symbols_[stackSymbol]] = [[s,gotoState]];
|
712
|
+
}
|
713
|
+
}
|
714
|
+
});
|
715
|
+
}
|
716
|
+
|
717
|
+
// set accept action
|
718
|
+
itemSet.forEach(function (item, j) {
|
719
|
+
if (item.markedSymbol == self.EOF) {
|
720
|
+
// accept
|
721
|
+
state[self.symbols_[self.EOF]] = [[a]];
|
722
|
+
//self.trace(k, self.EOF, state[self.EOF]);
|
723
|
+
}
|
724
|
+
});
|
725
|
+
|
726
|
+
var allterms = self.lookAheads ? false : self.terminals;
|
727
|
+
|
728
|
+
// set reductions and resolve potential conflicts
|
729
|
+
itemSet.reductions.forEach(function (item, j) {
|
730
|
+
// if parser uses lookahead, only enumerate those terminals
|
731
|
+
var terminals = allterms || self.lookAheads(itemSet, item);
|
732
|
+
|
733
|
+
terminals.forEach(function (stackSymbol) {
|
734
|
+
action = state[self.symbols_[stackSymbol]] || [];
|
735
|
+
var op = operators[stackSymbol];
|
736
|
+
// Reading a terminal and current position is at the end of a production, try to reduce
|
737
|
+
if (action.length) {
|
738
|
+
var sol = resolveConflict(item.production, op, [r,item.production.id], action[0]);
|
739
|
+
self.resolutions.push([k,stackSymbol,sol]);
|
740
|
+
if (sol.bydefault) {
|
741
|
+
self.conflicts++;
|
742
|
+
if (!self.DEBUG) {
|
743
|
+
self.warn('Conflict in grammar (state:',k, ', token:',stackSymbol, ")\n ", printAction(sol.r, self), "\n ", printAction(sol.s, self));
|
744
|
+
}
|
745
|
+
if (self.options.noDefaultResolve) {
|
746
|
+
action.push(sol.r);
|
747
|
+
}
|
748
|
+
} else {
|
749
|
+
action = [sol.action];
|
750
|
+
}
|
751
|
+
} else {
|
752
|
+
action.push([r,item.production.id]);
|
753
|
+
}
|
754
|
+
if (action && action.length) {
|
755
|
+
state[self.symbols_[stackSymbol]] = action;
|
756
|
+
}
|
757
|
+
});
|
758
|
+
});
|
759
|
+
|
760
|
+
});
|
761
|
+
|
762
|
+
return states;
|
763
|
+
};
|
764
|
+
|
765
|
+
// resolves shift-reduce and reduce-reduce conflicts
|
766
|
+
function resolveConflict (production, op, reduce, shift) {
|
767
|
+
var sln = {production: production, operator: op, r: reduce, s: shift},
|
768
|
+
s = 1, // shift
|
769
|
+
r = 2, // reduce
|
770
|
+
a = 3; // accept
|
771
|
+
|
772
|
+
if (shift[0] === r) {
|
773
|
+
sln.msg = "Resolve R/R conflict (use first production declared in grammar.)";
|
774
|
+
sln.action = shift[1] < reduce[1] ? shift : reduce;
|
775
|
+
sln.bydefault = true;
|
776
|
+
//print(production, reduce[0]);
|
777
|
+
return sln;
|
778
|
+
}
|
779
|
+
|
780
|
+
if (production.precedence === 0 || !op) {
|
781
|
+
sln.msg = "Resolve S/R conflict (shift by default.)";
|
782
|
+
sln.bydefault = true;
|
783
|
+
sln.action = shift;
|
784
|
+
} else if (production.precedence < op.precedence ) {
|
785
|
+
sln.msg = "Resolve S/R conflict (shift for higher precedent operator.)";
|
786
|
+
sln.action = shift;
|
787
|
+
} else if (production.precedence === op.precedence) {
|
788
|
+
if (op.assoc === "right" ) {
|
789
|
+
sln.msg = "Resolve S/R conflict (shift for right associative operator.)";
|
790
|
+
sln.action = shift;
|
791
|
+
} else if (op.assoc === "left" ) {
|
792
|
+
sln.msg = "Resolve S/R conflict (reduce for left associative operator.)";
|
793
|
+
sln.action = reduce;
|
794
|
+
} else if (op.assoc === "nonassoc" ) {
|
795
|
+
sln.msg = "Resolve S/R conflict (no action for non-associative operator.)";
|
796
|
+
sln.action = undefined;
|
797
|
+
}
|
798
|
+
} else {
|
799
|
+
sln.msg = "Resolve conflict (reduce for higher precedent production.)";
|
800
|
+
sln.action = reduce;
|
801
|
+
}
|
802
|
+
|
803
|
+
return sln;
|
804
|
+
}
|
805
|
+
|
806
|
+
lrGeneratorMixin.generate = function parser_generate (opt) {
|
807
|
+
opt = typal.mix.call({}, this.options, opt);
|
808
|
+
var code = "";
|
809
|
+
switch (opt.moduleType) {
|
810
|
+
case "js":
|
811
|
+
code = this.generateModule(opt);
|
812
|
+
break;
|
813
|
+
case "commonjs":
|
814
|
+
default:
|
815
|
+
code = this.generateCommonJSModule(opt);
|
816
|
+
}
|
817
|
+
|
818
|
+
return code;
|
819
|
+
};
|
820
|
+
|
821
|
+
lrGeneratorMixin.generateCommonJSModule = function generateCommonJSModule (opt) {
|
822
|
+
opt = typal.mix.call({}, this.options, opt);
|
823
|
+
var moduleName = opt.moduleName || "parser";
|
824
|
+
var out = this.generateModule(opt);
|
825
|
+
out += "\nif (typeof require !== 'undefined') {";
|
826
|
+
out += "\nexports.parser = "+moduleName+";";
|
827
|
+
out += "\nexports.parse = function () { return "+moduleName+".parse.apply("+moduleName+", arguments); }";
|
828
|
+
out += "\nexports.main = "+ String(opt.moduleMain || commonjsMain);
|
829
|
+
out += "\nif (require.main === module) {\n\texports.main(require(\"system\").args);\n}";
|
830
|
+
out += "\n}";
|
831
|
+
|
832
|
+
return out;
|
833
|
+
};
|
834
|
+
|
835
|
+
lrGeneratorMixin.generateModule = function generateModule (opt) {
|
836
|
+
opt = typal.mix.call({}, this.options, opt);
|
837
|
+
var moduleName = opt.moduleName || "parser";
|
838
|
+
var out = "/* Jison generated parser */\n";
|
839
|
+
out += (moduleName.match(/\./) ? moduleName : "var "+moduleName)+" = (function(){";
|
840
|
+
out += "\nvar parser = "+this.generateModule_();
|
841
|
+
if (this.lexer && this.lexer.generateModule) {
|
842
|
+
out += this.lexer.generateModule();
|
843
|
+
out += "\nparser.lexer = lexer;";
|
844
|
+
}
|
845
|
+
out += "\nreturn parser;\n})();";
|
846
|
+
|
847
|
+
return out;
|
848
|
+
};
|
849
|
+
|
850
|
+
lrGeneratorMixin.generateModule_ = function generateModule_ () {
|
851
|
+
var out = "{";
|
852
|
+
out += [
|
853
|
+
"trace: " + String(this.trace),
|
854
|
+
"yy: {}",
|
855
|
+
"symbols_: " + JSON.stringify(this.symbols_),
|
856
|
+
"terminals_: " + JSON.stringify(this.terminals_),
|
857
|
+
"productions_: " + JSON.stringify(this.productions_),
|
858
|
+
"performAction: " + String(this.performAction),
|
859
|
+
"table: " + JSON.stringify(this.table),
|
860
|
+
"parseError: " + String(this.parseError || parser.parseError),
|
861
|
+
"parse: " + String(parser.parse)
|
862
|
+
].join(",\n");
|
863
|
+
out += "};";
|
864
|
+
|
865
|
+
return out;
|
866
|
+
};
|
867
|
+
|
868
|
+
// default main method for generated commonjs modules
|
869
|
+
function commonjsMain (args) {
|
870
|
+
var cwd = require("file").path(require("file").cwd());
|
871
|
+
if (!args[1])
|
872
|
+
throw new Error('Usage: '+args[0]+' FILE');
|
873
|
+
var source = cwd.join(args[1]).read({charset: "utf-8"});
|
874
|
+
this.parse(source);
|
875
|
+
}
|
876
|
+
|
877
|
+
// debug mixin for LR parser generators
|
878
|
+
|
879
|
+
function printAction (a, gen) {
|
880
|
+
var s = a[0] == 1 ? 'shift '+gen.symbols[a[1]] :
|
881
|
+
a[0] == 2 ? 'reduce by '+gen.productions[a[1]] :
|
882
|
+
'accept' ;
|
883
|
+
|
884
|
+
return s;
|
885
|
+
}
|
886
|
+
|
887
|
+
var lrGeneratorDebug = {
|
888
|
+
beforeparseTable: function () {
|
889
|
+
this.trace("Building parse table.");
|
890
|
+
},
|
891
|
+
afterparseTable: function () {
|
892
|
+
var self = this;
|
893
|
+
if (this.conflicts > 0) {
|
894
|
+
this.resolutions.forEach(function (r, i) {
|
895
|
+
if (r[2].bydefault) {
|
896
|
+
self.warn('Conflict at state:',r[0], ', Token:',r[1], "\n ", printAction(r[2].r, self), "\n ", printAction(r[2].s, self));
|
897
|
+
}
|
898
|
+
});
|
899
|
+
this.trace("\n"+this.conflicts+" Conflict(s) found in grammar.");
|
900
|
+
}
|
901
|
+
this.trace("Done.");
|
902
|
+
},
|
903
|
+
aftercanonicalCollection: function (states) {
|
904
|
+
var trace = this.trace;
|
905
|
+
trace("\nItem sets\n------");
|
906
|
+
|
907
|
+
states.forEach(function (state, i) {
|
908
|
+
trace("\nitem set",i,"\n"+state.join("\n"), '\ntransitions -> ', JSON.stringify(state.edges));
|
909
|
+
});
|
910
|
+
}
|
911
|
+
};
|
912
|
+
|
913
|
+
var parser = typal.beget();
|
914
|
+
|
915
|
+
lrGeneratorMixin.createParser = function createParser () {
|
916
|
+
var p = parser.beget();
|
917
|
+
|
918
|
+
p.init({
|
919
|
+
table: this.table,
|
920
|
+
productions_: this.productions_,
|
921
|
+
symbols_: this.symbols_,
|
922
|
+
terminals_: this.terminals_,
|
923
|
+
performAction: this.performAction
|
924
|
+
});
|
925
|
+
|
926
|
+
// for debugging
|
927
|
+
p.productions = this.productions;
|
928
|
+
|
929
|
+
// backwards compatability
|
930
|
+
p.generate = this.generate;
|
931
|
+
p.lexer = this.lexer;
|
932
|
+
p.generateModule = this.generateModule;
|
933
|
+
p.generateCommonJSModule = this.generateCommonJSModule;
|
934
|
+
p.generateModule_ = this.generateModule_;
|
935
|
+
|
936
|
+
return p;
|
937
|
+
};
|
938
|
+
|
939
|
+
parser.yy = {};
|
940
|
+
parser.trace = generator.trace;
|
941
|
+
parser.warn = generator.warn;
|
942
|
+
parser.error = generator.error;
|
943
|
+
|
944
|
+
parser.parseError = lrGeneratorMixin.parseError = function parseError (str, hash) {
|
945
|
+
throw new Error(str);
|
946
|
+
};
|
947
|
+
|
948
|
+
parser.parse = function parse (input) {
|
949
|
+
var self = this,
|
950
|
+
stack = [0],
|
951
|
+
vstack = [null], // semantic value stack
|
952
|
+
table = this.table,
|
953
|
+
yytext = '',
|
954
|
+
yylineno = 0,
|
955
|
+
yyleng = 0,
|
956
|
+
shifts = 0,
|
957
|
+
reductions = 0;
|
958
|
+
|
959
|
+
this.lexer.setInput(input);
|
960
|
+
this.lexer.yy = this.yy;
|
961
|
+
|
962
|
+
var parseError = this.yy.parseError = this.yy.parseError || this.parseError;
|
963
|
+
|
964
|
+
function lex() {
|
965
|
+
var token;
|
966
|
+
token = self.lexer.lex() || 1; // $end = 1
|
967
|
+
// if token isn't its numeric value, convert
|
968
|
+
if (typeof token !== 'number') {
|
969
|
+
token = self.symbols_[token];
|
970
|
+
}
|
971
|
+
return token;
|
972
|
+
};
|
973
|
+
|
974
|
+
var symbol, state, action, a, r, yyval={},p,len,ip=0,newState, expected;
|
975
|
+
symbol = lex();
|
976
|
+
while (true) {
|
977
|
+
// set first input
|
978
|
+
state = stack[stack.length-1];
|
979
|
+
// read action for current state and first input
|
980
|
+
action = table[state] && table[state][symbol];
|
981
|
+
|
982
|
+
if (typeof action == 'undefined' || !action.length || !action[0]) {
|
983
|
+
expected = [];
|
984
|
+
for (p in table[state]) if (this.terminals_[p] && p != 1) {
|
985
|
+
expected.push("'"+this.terminals_[p]+"'");
|
986
|
+
}
|
987
|
+
if (this.lexer.showPosition) {
|
988
|
+
parseError('Parse error on line '+(yylineno+1)+":\n"+this.lexer.showPosition()+'\nExpecting '+expected.join(', '),
|
989
|
+
{text: this.lexer.match, token: this.terminals_[symbol], line: this.lexer.yylineno, expected: expected});
|
990
|
+
} else {
|
991
|
+
parseError('Parse error on line '+(yylineno+1)+": Unexpected '"+this.terminals_[symbol]+"'",
|
992
|
+
{text: this.lexer.match, token: this.terminals_[symbol], line: this.lexer.yylineno, expected: expected});
|
993
|
+
}
|
994
|
+
}
|
995
|
+
|
996
|
+
this.trace('action:',action);
|
997
|
+
|
998
|
+
// this shouldn't happen, unless resolve defaults are off
|
999
|
+
if (action.length > 1) {
|
1000
|
+
throw new Error('Parse Error: multiple actions possible at state: '+state+', token: '+symbol);
|
1001
|
+
}
|
1002
|
+
|
1003
|
+
a = action[0];
|
1004
|
+
|
1005
|
+
switch (a[0]) {
|
1006
|
+
|
1007
|
+
case 1: // shift
|
1008
|
+
shifts++;
|
1009
|
+
|
1010
|
+
stack.push(symbol);++ip;
|
1011
|
+
yyleng = this.lexer.yyleng;
|
1012
|
+
yytext = this.lexer.yytext;
|
1013
|
+
yylineno = this.lexer.yylineno;
|
1014
|
+
symbol = lex();
|
1015
|
+
vstack.push(null); // semantic values or junk only, no terminals
|
1016
|
+
stack.push(a[1]); // push state
|
1017
|
+
break;
|
1018
|
+
|
1019
|
+
case 2: // reduce
|
1020
|
+
reductions++;
|
1021
|
+
|
1022
|
+
len = this.productions_[a[1]][1];
|
1023
|
+
|
1024
|
+
// perform semantic action
|
1025
|
+
yyval.$ = vstack[vstack.length-len]; // default to $$ = $1
|
1026
|
+
r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, a[1], vstack);
|
1027
|
+
|
1028
|
+
if (typeof r !== 'undefined') {
|
1029
|
+
return r;
|
1030
|
+
}
|
1031
|
+
|
1032
|
+
// pop off stack
|
1033
|
+
if (len) {
|
1034
|
+
stack = stack.slice(0,-1*len*2);
|
1035
|
+
vstack = vstack.slice(0, -1*len);
|
1036
|
+
}
|
1037
|
+
|
1038
|
+
stack.push(this.productions_[a[1]][0]); // push nonterminal (reduce)
|
1039
|
+
vstack.push(yyval.$);
|
1040
|
+
// goto new state = table[STATE][NONTERMINAL]
|
1041
|
+
newState = table[stack[stack.length-2]][stack[stack.length-1]];
|
1042
|
+
stack.push(newState);
|
1043
|
+
break;
|
1044
|
+
|
1045
|
+
case 3: // accept
|
1046
|
+
|
1047
|
+
this.reductionCount = reductions;
|
1048
|
+
this.shiftCount = shifts;
|
1049
|
+
return true;
|
1050
|
+
}
|
1051
|
+
|
1052
|
+
}
|
1053
|
+
|
1054
|
+
return true;
|
1055
|
+
};
|
1056
|
+
|
1057
|
+
parser.init = function parser_init (dict) {
|
1058
|
+
this.table = dict.table;
|
1059
|
+
this.performAction = dict.performAction;
|
1060
|
+
this.productions_ = dict.productions_;
|
1061
|
+
this.symbols_ = dict.symbols_;
|
1062
|
+
this.terminals_ = dict.terminals_;
|
1063
|
+
};
|
1064
|
+
|
1065
|
+
/*
|
1066
|
+
* LR(0) Parser
|
1067
|
+
* */
|
1068
|
+
|
1069
|
+
var lr0 = generator.beget(lookaheadMixin, lrGeneratorMixin, {
|
1070
|
+
type: "LR(0)",
|
1071
|
+
afterconstructor: function lr0_afterconstructor () {
|
1072
|
+
this.buildTable();
|
1073
|
+
}
|
1074
|
+
});
|
1075
|
+
|
1076
|
+
var LR0Generator = exports.LR0Generator = lr0.construct();
|
1077
|
+
|
1078
|
+
/*
|
1079
|
+
* Simple LALR(1)
|
1080
|
+
* */
|
1081
|
+
|
1082
|
+
var lalr = generator.beget(lookaheadMixin, lrGeneratorMixin, {
|
1083
|
+
type: "LALR(1)",
|
1084
|
+
|
1085
|
+
afterconstructor: function (grammar, options) {
|
1086
|
+
if (this.DEBUG) this.mix(lrGeneratorDebug, lalrGeneratorDebug); // mixin debug methods
|
1087
|
+
|
1088
|
+
options = options || {};
|
1089
|
+
this.states = this.canonicalCollection();
|
1090
|
+
this.terms_ = {};
|
1091
|
+
|
1092
|
+
var newg = this.newg = typal.beget(lookaheadMixin,{
|
1093
|
+
oldg: this,
|
1094
|
+
trace: this.trace,
|
1095
|
+
nterms_: {},
|
1096
|
+
DEBUG: false,
|
1097
|
+
go_: function (r, B) {
|
1098
|
+
r = r.split(":")[0]; // grab state #
|
1099
|
+
B = B.map(function (b) { return b.slice(b.indexOf(":")+1)});
|
1100
|
+
return this.oldg.go(r, B);
|
1101
|
+
}
|
1102
|
+
});
|
1103
|
+
newg.nonterminals = {};
|
1104
|
+
newg.productions = [];
|
1105
|
+
|
1106
|
+
this.inadequateStates = [];
|
1107
|
+
|
1108
|
+
// if true, only lookaheads in inadequate states are computed (faster, larger table)
|
1109
|
+
// if false, lookaheads for all reductions will be computed (slower, smaller table)
|
1110
|
+
this.onDemandLookahead = options.onDemandLookahead || false;
|
1111
|
+
|
1112
|
+
this.buildNewGrammar();
|
1113
|
+
newg.computeLookaheads();
|
1114
|
+
this.unionLookaheads();
|
1115
|
+
|
1116
|
+
this.table = this.parseTable(this.states);
|
1117
|
+
},
|
1118
|
+
|
1119
|
+
lookAheads: function LALR_lookaheads (state, item) {
|
1120
|
+
return (!!this.onDemandLookahead && !state.inadequate) ? this.terminals : item.follows;
|
1121
|
+
},
|
1122
|
+
go: function LALR_go (p, w) {
|
1123
|
+
var q = parseInt(p);
|
1124
|
+
for (var i=0;i<w.length;i++) {
|
1125
|
+
q = this.states.item(q).edges[w[i]] || q;
|
1126
|
+
}
|
1127
|
+
return q;
|
1128
|
+
},
|
1129
|
+
goPath: function LALR_goPath (p, w) {
|
1130
|
+
var q = parseInt(p),t,
|
1131
|
+
path = [];
|
1132
|
+
for (var i=0;i<w.length;i++) {
|
1133
|
+
t = w[i] ? q+":"+w[i] : '';
|
1134
|
+
if (t) this.newg.nterms_[t] = q;
|
1135
|
+
path.push(t);
|
1136
|
+
q = this.states.item(q).edges[w[i]] || q;
|
1137
|
+
this.terms_[t] = w[i];
|
1138
|
+
}
|
1139
|
+
return {path: path, endState: q};
|
1140
|
+
},
|
1141
|
+
// every disjoint reduction of a nonterminal becomes a produciton in G'
|
1142
|
+
buildNewGrammar: function LALR_buildNewGrammar () {
|
1143
|
+
var self = this,
|
1144
|
+
newg = this.newg;
|
1145
|
+
|
1146
|
+
this.states.forEach(function (state, i) {
|
1147
|
+
state.forEach(function (item) {
|
1148
|
+
if (item.dotPosition === 0) {
|
1149
|
+
// new symbols are a combination of state and transition symbol
|
1150
|
+
var symbol = i+":"+item.production.symbol;
|
1151
|
+
self.terms_[symbol] = item.production.symbol;
|
1152
|
+
newg.nterms_[symbol] = i;
|
1153
|
+
if (!newg.nonterminals[symbol])
|
1154
|
+
newg.nonterminals[symbol] = new Nonterminal(symbol);
|
1155
|
+
var pathInfo = self.goPath(i, item.production.handle);
|
1156
|
+
var p = new Production(symbol, pathInfo.path, newg.productions.length);
|
1157
|
+
newg.productions.push(p);
|
1158
|
+
newg.nonterminals[symbol].productions.push(p);
|
1159
|
+
|
1160
|
+
// store the transition that get's 'backed up to' after reduction on path
|
1161
|
+
var handle = item.production.handle.join(' ');
|
1162
|
+
var goes = self.states.item(pathInfo.endState).goes;
|
1163
|
+
if (!goes[handle])
|
1164
|
+
goes[handle] = [];
|
1165
|
+
goes[handle].push(symbol);
|
1166
|
+
|
1167
|
+
//self.trace('new production:',p);
|
1168
|
+
}
|
1169
|
+
});
|
1170
|
+
if (state.inadequate)
|
1171
|
+
self.inadequateStates.push(i);
|
1172
|
+
});
|
1173
|
+
},
|
1174
|
+
unionLookaheads: function LALR_unionLookaheads () {
|
1175
|
+
var self = this,
|
1176
|
+
newg = this.newg,
|
1177
|
+
states = !!this.onDemandLookahead ? this.inadequateStates : this.states;
|
1178
|
+
|
1179
|
+
states.forEach(function union_states_forEach (i) {
|
1180
|
+
var state = typeof i === 'number' ? self.states.item(i) : i,
|
1181
|
+
follows = [];
|
1182
|
+
if (state.reductions.length)
|
1183
|
+
state.reductions.forEach(function union_reduction_forEach (item) {
|
1184
|
+
var follows = {};
|
1185
|
+
for (var k=0;k<item.follows.length;k++) {
|
1186
|
+
follows[item.follows[k]] = true;
|
1187
|
+
}
|
1188
|
+
state.goes[item.production.handle.join(' ')].forEach(function reduction_goes_forEach (symbol) {
|
1189
|
+
newg.nonterminals[symbol].follows.forEach(function goes_follows_forEach (symbol) {
|
1190
|
+
var terminal = self.terms_[symbol];
|
1191
|
+
if (!follows[terminal]) {
|
1192
|
+
follows[terminal]=true;
|
1193
|
+
item.follows.push(terminal);
|
1194
|
+
}
|
1195
|
+
});
|
1196
|
+
});
|
1197
|
+
//self.trace('unioned item', item);
|
1198
|
+
});
|
1199
|
+
});
|
1200
|
+
}
|
1201
|
+
});
|
1202
|
+
|
1203
|
+
var LALRGenerator = exports.LALRGenerator = lalr.construct();
|
1204
|
+
|
1205
|
+
// LALR generator debug mixin
|
1206
|
+
|
1207
|
+
var lalrGeneratorDebug = {
|
1208
|
+
trace: function trace () {
|
1209
|
+
Jison.print.apply(null, arguments);
|
1210
|
+
},
|
1211
|
+
beforebuildNewGrammar: function () {
|
1212
|
+
this.trace(this.states.size()+" states.");
|
1213
|
+
this.trace("Building lookahead grammar.");
|
1214
|
+
},
|
1215
|
+
beforeunionLookaheads: function () {
|
1216
|
+
this.trace("Computing lookaheads.");
|
1217
|
+
}
|
1218
|
+
};
|
1219
|
+
|
1220
|
+
/*
|
1221
|
+
* Lookahead parser definitions
|
1222
|
+
*
|
1223
|
+
* Define base type
|
1224
|
+
* */
|
1225
|
+
var lrLookaheadGenerator = generator.beget(lookaheadMixin, lrGeneratorMixin, {
|
1226
|
+
afterconstructor: function lr_aftercontructor () {
|
1227
|
+
this.computeLookaheads();
|
1228
|
+
this.buildTable();
|
1229
|
+
}
|
1230
|
+
});
|
1231
|
+
|
1232
|
+
/*
|
1233
|
+
* SLR Parser
|
1234
|
+
* */
|
1235
|
+
var SLRGenerator = exports.SLRGenerator = lrLookaheadGenerator.construct({
|
1236
|
+
type: "SLR(1)",
|
1237
|
+
|
1238
|
+
lookAheads: function SLR_lookAhead (state, item) {
|
1239
|
+
return this.nonterminals[item.production.symbol].follows;
|
1240
|
+
}
|
1241
|
+
});
|
1242
|
+
|
1243
|
+
|
1244
|
+
/*
|
1245
|
+
* LR(1) Parser
|
1246
|
+
* */
|
1247
|
+
var lr1 = lrLookaheadGenerator.beget({
|
1248
|
+
type: "Canonical LR(1)",
|
1249
|
+
|
1250
|
+
lookAheads: function LR_lookAheads (state, item) {
|
1251
|
+
return item.follows;
|
1252
|
+
},
|
1253
|
+
Item: lrGeneratorMixin.Item.prototype.construct({
|
1254
|
+
afterconstructor: function () {
|
1255
|
+
this.id = this.production.id+'a'+this.dotPosition+'a'+this.follows.sort().join(',');
|
1256
|
+
},
|
1257
|
+
eq: function (e) {
|
1258
|
+
return e.id === this.id;
|
1259
|
+
}
|
1260
|
+
}),
|
1261
|
+
|
1262
|
+
closureOperation: function LR_ClosureOperation (itemSet /*, closureSet*/) {
|
1263
|
+
var closureSet = new this.ItemSet();
|
1264
|
+
var self = this;
|
1265
|
+
|
1266
|
+
var set = itemSet,
|
1267
|
+
itemQueue, syms = {};
|
1268
|
+
|
1269
|
+
do {
|
1270
|
+
itemQueue = new Set();
|
1271
|
+
closureSet.concat(set);
|
1272
|
+
set.forEach(function (item) {
|
1273
|
+
var symbol = item.markedSymbol;
|
1274
|
+
var b;
|
1275
|
+
|
1276
|
+
// if token is a nonterminal, recursively add closures
|
1277
|
+
if (symbol && self.nonterminals[symbol]) {
|
1278
|
+
b = self.first(item.remainingHandle());
|
1279
|
+
if (b.length === 0) b = item.follows;
|
1280
|
+
self.nonterminals[symbol].productions.forEach(function (production) {
|
1281
|
+
var newItem = new self.Item(production, 0, b);
|
1282
|
+
if(!closureSet.contains(newItem) && !itemQueue.contains(newItem)) {
|
1283
|
+
itemQueue.push(newItem);
|
1284
|
+
}
|
1285
|
+
});
|
1286
|
+
} else if (!symbol) {
|
1287
|
+
// reduction
|
1288
|
+
closureSet.reductions.push(item);
|
1289
|
+
}
|
1290
|
+
});
|
1291
|
+
|
1292
|
+
set = itemQueue;
|
1293
|
+
} while (!itemQueue.isEmpty());
|
1294
|
+
|
1295
|
+
return closureSet;
|
1296
|
+
}
|
1297
|
+
});
|
1298
|
+
|
1299
|
+
var LR1Generator = exports.LR1Generator = lr1.construct();
|
1300
|
+
|
1301
|
+
/*
|
1302
|
+
* LL Parser
|
1303
|
+
* */
|
1304
|
+
var ll = generator.beget(lookaheadMixin, {
|
1305
|
+
type: "LL(1)",
|
1306
|
+
|
1307
|
+
afterconstructor: function ll_aftercontructor () {
|
1308
|
+
this.computeLookaheads();
|
1309
|
+
this.table = this.parseTable(this.productions);
|
1310
|
+
},
|
1311
|
+
parseTable: function llParseTable (productions) {
|
1312
|
+
var table = {},
|
1313
|
+
self = this;
|
1314
|
+
productions.forEach(function (production, i) {
|
1315
|
+
var row = table[production.symbol] || {};
|
1316
|
+
var tokens = production.first;
|
1317
|
+
if (self.nullable(production.handle)) {
|
1318
|
+
Set.union(tokens, self.nonterminals[production.symbol].follows);
|
1319
|
+
}
|
1320
|
+
tokens.forEach(function (token) {
|
1321
|
+
if (row[token]) {
|
1322
|
+
row[token].push(i);
|
1323
|
+
self.conflicts++;
|
1324
|
+
} else {
|
1325
|
+
row[token] = [i];
|
1326
|
+
}
|
1327
|
+
});
|
1328
|
+
table[production.symbol] = row;
|
1329
|
+
});
|
1330
|
+
|
1331
|
+
return table;
|
1332
|
+
}
|
1333
|
+
});
|
1334
|
+
|
1335
|
+
var LLGenerator = exports.LLGenerator = ll.construct();
|
1336
|
+
|
1337
|
+
Jison.Generator = function Jison_Generator (g, options) {
|
1338
|
+
var opt = typal.mix.call({}, g.options, options);
|
1339
|
+
switch (opt.type) {
|
1340
|
+
case 'lr0':
|
1341
|
+
return new LR0Generator(g, opt);
|
1342
|
+
case 'slr':
|
1343
|
+
return new SLRGenerator(g, opt);
|
1344
|
+
case 'lr':
|
1345
|
+
return new LR1Generator(g, opt);
|
1346
|
+
case 'll':
|
1347
|
+
return new LLGenerator(g, opt);
|
1348
|
+
case 'lalr':
|
1349
|
+
default:
|
1350
|
+
return new LALRGenerator(g, opt);
|
1351
|
+
}
|
1352
|
+
}
|
1353
|
+
|
1354
|
+
return function Parser (g, options) {
|
1355
|
+
var opt = typal.mix.call({}, g.options, options);
|
1356
|
+
var gen;
|
1357
|
+
switch (opt.type) {
|
1358
|
+
case 'lr0':
|
1359
|
+
gen = new LR0Generator(g, opt);
|
1360
|
+
case 'slr':
|
1361
|
+
gen = new SLRGenerator(g, opt);
|
1362
|
+
case 'lr':
|
1363
|
+
gen = new LR1Generator(g, opt);
|
1364
|
+
case 'll':
|
1365
|
+
gen = new LLGenerator(g, opt);
|
1366
|
+
case 'lalr':
|
1367
|
+
default:
|
1368
|
+
gen = new LALRGenerator(g, opt);
|
1369
|
+
}
|
1370
|
+
return gen.createParser();
|
1371
|
+
}
|
1372
|
+
|
1373
|
+
})();
|
1374
|
+
|
1375
|
+
exports.main = function main (args) {
|
1376
|
+
//var parser = new require("args").Parser();
|
1377
|
+
var fs = require("file");
|
1378
|
+
gfile = fs.path(fs.cwd()).join(args[1]);
|
1379
|
+
|
1380
|
+
// try to parse as JSON, else use BNF parser
|
1381
|
+
if (gfile.extension() === '.json') {
|
1382
|
+
var grammar = JSON.parse(gfile.read({charset: "utf-8"}));
|
1383
|
+
} else if (gfile.extension() === '.jison') {
|
1384
|
+
var grammar = require("jison/bnf").parse(gfile.read({charset: "utf-8"}));
|
1385
|
+
}
|
1386
|
+
|
1387
|
+
var opt = grammar.options || {};
|
1388
|
+
|
1389
|
+
// lexer file
|
1390
|
+
if (args[2]) {
|
1391
|
+
var lfile = fs.path(fs.cwd()).join(args[2]);
|
1392
|
+
|
1393
|
+
// try to parse as JSON, else use BNF parser
|
1394
|
+
if (lfile.extension() === '.json') {
|
1395
|
+
grammar.lex = JSON.parse(lfile.read({charset: "utf-8"}));
|
1396
|
+
} else if (lfile.extension() === '.jisonlex') {
|
1397
|
+
grammar.lex = require("jison/jisonlex").parse(lfile.read({charset: "utf-8"}));
|
1398
|
+
}
|
1399
|
+
}
|
1400
|
+
|
1401
|
+
if (!opt.moduleName)
|
1402
|
+
opt.moduleName = gfile.basename().replace(new RegExp(gfile.extension()+"$"), "");
|
1403
|
+
if (!opt.moduleType)
|
1404
|
+
opt.moduleType = "commonjs";
|
1405
|
+
|
1406
|
+
var generator = new Jison.Generator(grammar, opt);
|
1407
|
+
fname = fs.path(fs.cwd()).join(opt.moduleName + ".js"),
|
1408
|
+
source = generator.generate(opt),
|
1409
|
+
stream = fname.open("w");
|
1410
|
+
|
1411
|
+
stream.print(source);
|
1412
|
+
stream.close();
|
1413
|
+
};
|
1414
|
+
|