haml-more 0.4.0.a
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|