antelope 0.2.0 → 0.2.2
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.
- checksums.yaml +4 -4
- data/.gitignore +25 -23
- data/.rspec +3 -3
- data/.travis.yml +10 -9
- data/.yardopts +7 -7
- data/CONTRIBUTING.md +38 -38
- data/GENERATORS.md +124 -124
- data/Gemfile +7 -7
- data/LICENSE.txt +22 -22
- data/README.md +104 -104
- data/Rakefile +2 -2
- data/TODO.md +58 -58
- data/antelope.gemspec +28 -28
- data/bin/antelope +7 -7
- data/examples/deterministic.ace +35 -35
- data/examples/example.ace +51 -50
- data/examples/example.err +192 -0
- data/examples/{example.output → example.inf} +384 -385
- data/examples/liquidscript.ace +233 -162
- data/examples/simple.ace +22 -22
- data/lib/antelope/ace/compiler.rb +334 -334
- data/lib/antelope/ace/errors.rb +48 -48
- data/lib/antelope/ace/grammar/generation.rb +80 -80
- data/lib/antelope/ace/grammar/loading.rb +53 -53
- data/lib/antelope/ace/grammar/precedences.rb +68 -65
- data/lib/antelope/ace/grammar/productions.rb +156 -150
- data/lib/antelope/ace/grammar/symbols.rb +66 -66
- data/lib/antelope/ace/grammar.rb +69 -69
- data/lib/antelope/ace/precedence.rb +61 -61
- data/lib/antelope/ace/production.rb +57 -57
- data/lib/antelope/ace/scanner/argument.rb +57 -57
- data/lib/antelope/ace/scanner/first.rb +89 -89
- data/lib/antelope/ace/scanner/second.rb +177 -177
- data/lib/antelope/ace/scanner/third.rb +27 -27
- data/lib/antelope/ace/scanner.rb +134 -134
- data/lib/antelope/ace/token/epsilon.rb +24 -24
- data/lib/antelope/ace/token/error.rb +26 -26
- data/lib/antelope/ace/token/nonterminal.rb +17 -17
- data/lib/antelope/ace/token/terminal.rb +17 -17
- data/lib/antelope/ace/token.rb +238 -238
- data/lib/antelope/ace.rb +53 -53
- data/lib/antelope/cli.rb +55 -55
- data/lib/antelope/errors.rb +8 -8
- data/lib/antelope/generation/constructor/first.rb +88 -88
- data/lib/antelope/generation/constructor/follow.rb +103 -103
- data/lib/antelope/generation/constructor/nullable.rb +64 -64
- data/lib/antelope/generation/constructor.rb +126 -126
- data/lib/antelope/generation/errors.rb +17 -17
- data/lib/antelope/generation/null.rb +13 -13
- data/lib/antelope/generation/recognizer/rule.rb +216 -216
- data/lib/antelope/generation/recognizer/state.rb +130 -130
- data/lib/antelope/generation/recognizer.rb +180 -180
- data/lib/antelope/generation/tableizer.rb +175 -154
- data/lib/antelope/generation.rb +15 -15
- data/lib/antelope/generator/base.rb +264 -264
- data/lib/antelope/generator/c.rb +11 -11
- data/lib/antelope/generator/c_header.rb +105 -105
- data/lib/antelope/generator/c_source.rb +39 -39
- data/lib/antelope/generator/error.rb +34 -0
- data/lib/antelope/generator/group.rb +57 -57
- data/lib/antelope/generator/html.rb +51 -0
- data/lib/antelope/generator/info.rb +47 -0
- data/lib/antelope/generator/null.rb +18 -18
- data/lib/antelope/generator/output.rb +17 -49
- data/lib/antelope/generator/ruby.rb +79 -79
- data/lib/antelope/generator/templates/c_header.ant +36 -36
- data/lib/antelope/generator/templates/c_source.ant +202 -202
- data/lib/antelope/generator/templates/error.ant +33 -0
- data/lib/antelope/generator/templates/html/antelope.css +1 -0
- data/lib/antelope/generator/templates/html/antelope.html +1 -0
- data/lib/antelope/generator/templates/html/antelope.js +1 -0
- data/lib/antelope/generator/templates/html/css.ant +53 -0
- data/lib/antelope/generator/templates/html/html.ant +82 -0
- data/lib/antelope/generator/templates/html/js.ant +9 -0
- data/lib/antelope/generator/templates/info.ant +53 -0
- data/lib/antelope/generator/templates/ruby.ant +178 -146
- data/lib/antelope/generator.rb +66 -63
- data/lib/antelope/template/compiler.rb +78 -78
- data/lib/antelope/template/errors.rb +9 -9
- data/lib/antelope/template/scanner.rb +109 -109
- data/lib/antelope/template.rb +65 -60
- data/lib/antelope/version.rb +6 -6
- data/lib/antelope.rb +13 -13
- data/optimizations.txt +42 -0
- data/spec/antelope/ace/compiler_spec.rb +60 -60
- data/spec/antelope/ace/scanner_spec.rb +27 -27
- data/spec/antelope/constructor_spec.rb +133 -136
- data/spec/antelope/template_spec.rb +50 -49
- data/spec/fixtures/simple.ace +22 -22
- data/spec/spec_helper.rb +39 -39
- data/spec/support/benchmark_helper.rb +5 -5
- data/spec/support/grammar_helper.rb +15 -15
- data/subl/Ace (Ruby).JSON-tmLanguage +94 -94
- data/subl/Ace (Ruby).tmLanguage +153 -153
- metadata +17 -6
- data/lib/antelope/generator/templates/output.ant +0 -68
@@ -0,0 +1,53 @@
|
|
1
|
+
body {
|
2
|
+
font-family: sans-serif;
|
3
|
+
color: #696265;
|
4
|
+
background-color: #fefefe;
|
5
|
+
}
|
6
|
+
|
7
|
+
h1, h2, h3, h4, h5, h6 {
|
8
|
+
font-family: serif;
|
9
|
+
color: #327CCB;
|
10
|
+
margin: 0;
|
11
|
+
}
|
12
|
+
|
13
|
+
code, kbd, pre {
|
14
|
+
font-family: monospace;
|
15
|
+
}
|
16
|
+
|
17
|
+
.body .section {
|
18
|
+
background-color: #f9f9f9;
|
19
|
+
padding: 0.5em;
|
20
|
+
}
|
21
|
+
|
22
|
+
.body .section h2 {
|
23
|
+
font-size: 1.5em;
|
24
|
+
}
|
25
|
+
|
26
|
+
.body .section h2, .body .section h3, .body .section h4,
|
27
|
+
.body .section h5, .body .section h6 {
|
28
|
+
padding: 0;
|
29
|
+
cursor: pointer;
|
30
|
+
|
31
|
+
}
|
32
|
+
|
33
|
+
.body .section .section-data {
|
34
|
+
display: none;
|
35
|
+
padding: 0.3em 2em;
|
36
|
+
}
|
37
|
+
|
38
|
+
.body .section .section-data.display {
|
39
|
+
display: block;
|
40
|
+
}
|
41
|
+
|
42
|
+
.body .section ul {
|
43
|
+
list-style-type: none;
|
44
|
+
}
|
45
|
+
|
46
|
+
.body .section ul, .body .section ol {
|
47
|
+
margin: 0;
|
48
|
+
padding: 0;
|
49
|
+
}
|
50
|
+
|
51
|
+
.conflict.resolved { color: #d9d9d9; }
|
52
|
+
.conflict.resolved:before { content: "resolved: "; color: #00B057; }
|
53
|
+
code.block { display: block; }
|
@@ -0,0 +1,82 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
|
3
|
+
<html>
|
4
|
+
<head>
|
5
|
+
<title>Antelope State Data</title>
|
6
|
+
|
7
|
+
<meta charset="utf-8">
|
8
|
+
<link rel="stylesheet" type="text/css" href="%{file}.css">
|
9
|
+
</head>
|
10
|
+
|
11
|
+
<body>
|
12
|
+
|
13
|
+
<div class="body">
|
14
|
+
<div class="section productions">
|
15
|
+
<h2>Productions</h2>
|
16
|
+
<ol class="rules section-data">
|
17
|
+
{{ grammar.all_productions.each do |prod| }}
|
18
|
+
<li>
|
19
|
+
<code>{{= prod.label }}: {{= prod.items.join(' ') }}</code>
|
20
|
+
<code class="block">{{= prod.block }}</code>
|
21
|
+
</li>
|
22
|
+
{{ end }}
|
23
|
+
</ol>
|
24
|
+
</div>
|
25
|
+
|
26
|
+
<div class="section states">
|
27
|
+
<h2>States</h2>
|
28
|
+
<ul class="section-data">
|
29
|
+
{{ states = grammar.states.to_a }}
|
30
|
+
{{ table.each_with_index do |v, i| }}
|
31
|
+
<li class="section state">
|
32
|
+
{{ state = states[i] }}
|
33
|
+
<h3>State %{i}</h3>
|
34
|
+
<div class="section-data">
|
35
|
+
{{ state.rules.each do |rule| }}
|
36
|
+
<pre>{{= rule }}
|
37
|
+
{{= "{" << rule.lookahead.to_a.join(", ") << "}" }}</pre>
|
38
|
+
{{ end }}
|
39
|
+
{{
|
40
|
+
transitions = v.each.select { |_, a| a && a[0] == :state }
|
41
|
+
reductions = v.each.select { |_, a| a && a[0] == :reduce}
|
42
|
+
accepting = v.each.select { |_, a| a && a[0] == :accept}
|
43
|
+
conflicts = tableizer.conflicts[i].each
|
44
|
+
thing = [:transitions, :reductions, :accepting]
|
45
|
+
num_type = {
|
46
|
+
transitions: "State",
|
47
|
+
reductions: "Rule",
|
48
|
+
accepting: "Rule"
|
49
|
+
}
|
50
|
+
h = Hash[thing.zip([transitions, reductions, accepting])]
|
51
|
+
}}
|
52
|
+
{{ h.each do |key, value| }}
|
53
|
+
{{ next unless value.any? }}
|
54
|
+
<div class="part">
|
55
|
+
<h4>{{= key }}</h4>
|
56
|
+
{{ value.each do |token, (_, name)| }}
|
57
|
+
{{ token_value = grammar.terminals.find { |_| _.name == token } || token }}
|
58
|
+
<div>
|
59
|
+
<code>{{= token_value}}: {{= num_type[key] }} {{= name }}</code class="block"></div>
|
60
|
+
{{ end }}
|
61
|
+
</div>
|
62
|
+
{{ end }}
|
63
|
+
{{ if conflicts.any? }}
|
64
|
+
<div class="part">
|
65
|
+
<h4>Conflicts</h4>
|
66
|
+
{{ conflicts.each do |token, (value, first, second, rule, terminal)| }}
|
67
|
+
<div class="conflict {{ if value != 0 }}resolved{{ end }}">
|
68
|
+
<code>{{= token }}: {{= first.join(" ") }}/{{= second.join(" ") }} ({{= rule }} vs {{= terminal }})</code>
|
69
|
+
</div>
|
70
|
+
{{ end }}
|
71
|
+
</div>
|
72
|
+
{{ end }}
|
73
|
+
</div>
|
74
|
+
</li>
|
75
|
+
{{ end }}
|
76
|
+
</ul>
|
77
|
+
</div>
|
78
|
+
</div>
|
79
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
80
|
+
<script src="%{file}.js"></script>
|
81
|
+
</body>
|
82
|
+
</html>
|
@@ -0,0 +1,53 @@
|
|
1
|
+
Productions:
|
2
|
+
%len = grammar.all_productions.size.to_s.size
|
3
|
+
%productions = grammar.all_productions.
|
4
|
+
% map { |x| ["#{x.label} → #{x.items.join(' ')}", x.block] }
|
5
|
+
%body = productions.map { |_| _.first.size }.max
|
6
|
+
%productions.each_with_index do |prod, i|
|
7
|
+
{{= sprintf("%#{len}s", i)}} {{= sprintf("%-#{body}s", prod[0])}} %{prod[1]}
|
8
|
+
%end
|
9
|
+
|
10
|
+
%if unused_symbols.any?
|
11
|
+
Symbols unused in grammar:
|
12
|
+
% unused_symbols.each do |sym|
|
13
|
+
%{sym}
|
14
|
+
% end
|
15
|
+
%end
|
16
|
+
|
17
|
+
Precedence:
|
18
|
+
--- highest
|
19
|
+
% grammar.precedence.each do |pr|
|
20
|
+
%{"%-8s" % pr.type} %{pr.level}:
|
21
|
+
{{= "{" << pr.tokens.to_a.join(", ") << "}" }}
|
22
|
+
% end
|
23
|
+
--- lowest
|
24
|
+
|
25
|
+
%states = grammar.states.to_a
|
26
|
+
%table.each_with_index do |v, i|
|
27
|
+
% state = states[i]
|
28
|
+
State %{i}:
|
29
|
+
% state.rules.each do |rule|
|
30
|
+
%{rule}
|
31
|
+
{%{rule.lookahead.to_a.join(", ")}}
|
32
|
+
% end
|
33
|
+
% transitions = v.each.select { |_, a| a && a[0] == :state }
|
34
|
+
% reductions = v.each.select { |_, a| a && a[0] == :reduce}
|
35
|
+
% accepting = v.each.select { |_, a| a && a[0] == :accept}
|
36
|
+
% thing = [:transitions, :reductions, :accepting]
|
37
|
+
% num_type = {
|
38
|
+
% transitions: "State",
|
39
|
+
% reductions: "Rule",
|
40
|
+
% accepting: "Rule"
|
41
|
+
% }
|
42
|
+
% h = Hash[thing.zip([transitions, reductions, accepting])]
|
43
|
+
% h.each do |key, value|
|
44
|
+
% next unless value.any?
|
45
|
+
%{key}:
|
46
|
+
% value.each do |token, (_, name)|
|
47
|
+
% token_value = grammar.terminals.
|
48
|
+
% find { |_| _.name == token } || token
|
49
|
+
%{token_value}: %{num_type[key]} %{name}
|
50
|
+
% end
|
51
|
+
% end
|
52
|
+
|
53
|
+
%end
|
@@ -1,146 +1,178 @@
|
|
1
|
-
|
2
|
-
# This file assumes that the output of the generator will be placed
|
3
|
-
# within a module or a class. However, the module/class requires a
|
4
|
-
# `type` method, which takes a terminal and gives its type, as a
|
5
|
-
# symbol. These types should line up with the terminals that were
|
6
|
-
# defined in the original grammar.
|
7
|
-
|
8
|
-
# The actions to take during parsing. In every state, there are a
|
9
|
-
# set of acceptable peek tokens; this table tells the parser what
|
10
|
-
# to do on each acceptable peek token. The possible actions include
|
11
|
-
# `:accept`, `:reduce`, and `:state`; `:accept` means to accept the
|
12
|
-
# input and return the value of the pasing. `:reduce` means to
|
13
|
-
# reduce the top of the stack into a given nonterminal. `:state`
|
14
|
-
# means to transition to another state.
|
15
|
-
#
|
16
|
-
# @return [Array<Hash<(Symbol, Array<(Symbol, Numeric)>)>>]
|
17
|
-
ACTION_TABLE = {{= generate_action_table }}.freeze
|
18
|
-
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
|
23
|
-
#
|
24
|
-
|
25
|
-
|
26
|
-
#
|
27
|
-
#
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
end
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
# @
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
end
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
stack.
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
1
|
+
|
2
|
+
# This file assumes that the output of the generator will be placed
|
3
|
+
# within a module or a class. However, the module/class requires a
|
4
|
+
# `type` method, which takes a terminal and gives its type, as a
|
5
|
+
# symbol. These types should line up with the terminals that were
|
6
|
+
# defined in the original grammar.
|
7
|
+
|
8
|
+
# The actions to take during parsing. In every state, there are a
|
9
|
+
# set of acceptable peek tokens; this table tells the parser what
|
10
|
+
# to do on each acceptable peek token. The possible actions include
|
11
|
+
# `:accept`, `:reduce`, and `:state`; `:accept` means to accept the
|
12
|
+
# input and return the value of the pasing. `:reduce` means to
|
13
|
+
# reduce the top of the stack into a given nonterminal. `:state`
|
14
|
+
# means to transition to another state.
|
15
|
+
#
|
16
|
+
# @return [Array<Hash<(Symbol, Array<(Symbol, Numeric)>)>>]
|
17
|
+
ACTION_TABLE = {{= generate_action_table }}.freeze
|
18
|
+
|
19
|
+
# The default action that is taken for most reductions.
|
20
|
+
#
|
21
|
+
# @return [Proc]
|
22
|
+
DEFAULT_PROC = proc { |_| _ }
|
23
|
+
# A list of all of the productions. Only includes the left-hand side,
|
24
|
+
# the number of tokens on the right-hand side, and the block to call
|
25
|
+
# on reduction.
|
26
|
+
#
|
27
|
+
# @return [Array<Array<(Symbol, Numeric, Proc)>>]
|
28
|
+
PRODUCTIONS = {{= generate_productions_list }}.freeze
|
29
|
+
|
30
|
+
# Runs the parser.
|
31
|
+
#
|
32
|
+
# @param input [Array] the input to run the parser over.
|
33
|
+
# @return [Object] the result of the accept.
|
34
|
+
def parse(input)
|
35
|
+
stack = []
|
36
|
+
stack.push([nil, 0])
|
37
|
+
last = nil
|
38
|
+
input = input.to_a.dup
|
39
|
+
|
40
|
+
until stack.empty? do
|
41
|
+
last = parse_action(stack, input)
|
42
|
+
end
|
43
|
+
|
44
|
+
last
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
# Actually performs the parsing action on the given stack on input.
|
49
|
+
# If you want to implement a push parser, than messing with this
|
50
|
+
# method is probably the way to go.
|
51
|
+
#
|
52
|
+
# @param stack [Array<Array<(Object, Numeric)>>] the stack of the
|
53
|
+
# parser. The actual order of the stack is important.
|
54
|
+
# @param input [Array<Object>] the input to run the parser over.
|
55
|
+
# The elements of this may be passed to the `type` method.
|
56
|
+
# @return [Object] the result of the last accepting reduction.
|
57
|
+
def parse_action(stack, input)
|
58
|
+
last = nil
|
59
|
+
peek_token = if input.empty?
|
60
|
+
:$end
|
61
|
+
else
|
62
|
+
type(input.first)
|
63
|
+
end
|
64
|
+
|
65
|
+
action = ACTION_TABLE[stack.last.last].fetch(peek_token) do
|
66
|
+
ACTION_TABLE[stack.last.last].fetch(:$default)
|
67
|
+
end
|
68
|
+
|
69
|
+
case action.first
|
70
|
+
when :accept
|
71
|
+
production = PRODUCTIONS[action.last]
|
72
|
+
last = stack.pop(production[1]).first.first
|
73
|
+
stack.pop
|
74
|
+
when :reduce
|
75
|
+
production = PRODUCTIONS[action.last]
|
76
|
+
removing = stack.pop(production[1])
|
77
|
+
value = instance_exec(*removing.map(&:first), &production[2])
|
78
|
+
goto = ACTION_TABLE[stack.last.last][production[0]]
|
79
|
+
stack.push([value, goto.last])
|
80
|
+
when :state
|
81
|
+
stack.push([input.shift, action.last])
|
82
|
+
else
|
83
|
+
raise NotImplementedError, "Unknown action #{action.first}"
|
84
|
+
end
|
85
|
+
|
86
|
+
last
|
87
|
+
|
88
|
+
rescue KeyError => e
|
89
|
+
peek = input.first
|
90
|
+
|
91
|
+
if handle_error({
|
92
|
+
:stack => stack,
|
93
|
+
:peek => peek_token,
|
94
|
+
:remaining => input,
|
95
|
+
:error => e,
|
96
|
+
:line => line_of(peek),
|
97
|
+
:column => column_of(peek),
|
98
|
+
:expected => ACTION_TABLE[stack.last.last].keys
|
99
|
+
})
|
100
|
+
retry
|
101
|
+
else
|
102
|
+
raise
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
def line_of(peek)
|
109
|
+
if peek.respond_to?(:line)
|
110
|
+
peek.line
|
111
|
+
else
|
112
|
+
0
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def column_of(peek)
|
117
|
+
if peek.respond_to?(:column)
|
118
|
+
peek.column
|
119
|
+
else
|
120
|
+
0
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
{{ if define_own_handler? }}
|
125
|
+
def handle_error(data, _ = false)
|
126
|
+
{{ if panic_mode? }}
|
127
|
+
if _ || data[:peek] == :$end # we can't recover if
|
128
|
+
# we're at the end
|
129
|
+
{{ end }}
|
130
|
+
raise {{= error_class }},
|
131
|
+
"Unexpected token #{data[:peek]} on line #{data[:line]}, " \
|
132
|
+
"column #{data[:column]}; expected one of " \
|
133
|
+
"#{data[:expected].join(', ')}",
|
134
|
+
data[:error].backtrace
|
135
|
+
{{ if panic_mode? }}
|
136
|
+
end
|
137
|
+
|
138
|
+
new_peek = :$error
|
139
|
+
acceptable_state = false
|
140
|
+
state = nil
|
141
|
+
|
142
|
+
until data[:stack].empty? or acceptable_state
|
143
|
+
state = data[:stack].last.last
|
144
|
+
|
145
|
+
if ACTION_TABLE[state].key?(new_peek)
|
146
|
+
acceptable_state = true
|
147
|
+
else
|
148
|
+
data[:stack].pop # discard
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
return handle_error(data, true) unless acceptable_state
|
153
|
+
|
154
|
+
action = ACTION_TABLE[state][new_peek]
|
155
|
+
lookaheads = nil
|
156
|
+
|
157
|
+
until lookaheads
|
158
|
+
if action[0] == :state
|
159
|
+
lookaheads = ACTION_TABLE[action.last].keys
|
160
|
+
elsif action[0] == :reduce
|
161
|
+
rule = PRODUCTIONS[action.last]
|
162
|
+
action = ACTION_TABLE[stack[-rule[1]].last][rule[0]]
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
begin
|
167
|
+
until lookaheads.include?(data[:remaining][0].peek)
|
168
|
+
data[:remaining].next
|
169
|
+
end
|
170
|
+
rescue StopIteration
|
171
|
+
end
|
172
|
+
|
173
|
+
data[:remaining].unshift([new_peek, data[:error]])
|
174
|
+
true
|
175
|
+
|
176
|
+
{{ end }}
|
177
|
+
end
|
178
|
+
{{ end }}
|
data/lib/antelope/generator.rb
CHANGED
@@ -1,63 +1,66 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
require "erb"
|
3
|
-
require "pathname"
|
4
|
-
|
5
|
-
module Antelope
|
6
|
-
|
7
|
-
# Contains the classes that generate parsers. This contains a
|
8
|
-
# registery of all of the generators available to antelope.
|
9
|
-
module Generator
|
10
|
-
|
11
|
-
# Returns a hash of all of the generators registered within this
|
12
|
-
# module. If a generator is accessed that does not exist on the
|
13
|
-
# hash, it by default returns the {Generator::Null} class.
|
14
|
-
#
|
15
|
-
# @return [Hash<(Symbol, String) => Generator::Base>]
|
16
|
-
def generators
|
17
|
-
@_generators ||= Hash.new { |h, k| h[k] = Generator::Null }
|
18
|
-
end
|
19
|
-
# Returns a hash of all of the directives that are available in
|
20
|
-
# the generators of this module.
|
21
|
-
#
|
22
|
-
# @see .generators
|
23
|
-
# @return [Hash]
|
24
|
-
def directives
|
25
|
-
generators.values.map(&:directives).
|
26
|
-
inject({}, :merge)
|
27
|
-
end
|
28
|
-
|
29
|
-
# Registers a generator with the given names. If multiple names
|
30
|
-
# are given, they are assigned the generator as a value in the
|
31
|
-
# {#generators} hash; otherwise, the one name is assigned the
|
32
|
-
# generator as a value.
|
33
|
-
#
|
34
|
-
# @param generator [Generator::Base] the generator class to
|
35
|
-
# associate the key with.
|
36
|
-
# @param name [String, Symbol] a name to associate the generator
|
37
|
-
# with.
|
38
|
-
def register_generator(generator, *names)
|
39
|
-
names = [names].flatten
|
40
|
-
raise ArgumentError,
|
41
|
-
"Requires at least one name" unless names.any?
|
42
|
-
raise ArgumentError,
|
43
|
-
"All name values must be a Symbol or string" unless names.
|
44
|
-
all? {|_| [Symbol, String].include?(_.class) }
|
45
|
-
|
46
|
-
names.each do |name|
|
47
|
-
generators[name.to_s.downcase] = generator
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
extend self
|
52
|
-
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
require "antelope/generator/base"
|
57
|
-
require "antelope/generator/group"
|
58
|
-
require "antelope/generator/
|
59
|
-
require "antelope/generator/
|
60
|
-
require "antelope/generator/
|
61
|
-
require "antelope/generator/
|
62
|
-
require "antelope/generator/
|
63
|
-
require "antelope/generator/
|
1
|
+
# encoding: utf-8
|
2
|
+
require "erb"
|
3
|
+
require "pathname"
|
4
|
+
|
5
|
+
module Antelope
|
6
|
+
|
7
|
+
# Contains the classes that generate parsers. This contains a
|
8
|
+
# registery of all of the generators available to antelope.
|
9
|
+
module Generator
|
10
|
+
|
11
|
+
# Returns a hash of all of the generators registered within this
|
12
|
+
# module. If a generator is accessed that does not exist on the
|
13
|
+
# hash, it by default returns the {Generator::Null} class.
|
14
|
+
#
|
15
|
+
# @return [Hash<(Symbol, String) => Generator::Base>]
|
16
|
+
def generators
|
17
|
+
@_generators ||= Hash.new { |h, k| h[k] = Generator::Null }
|
18
|
+
end
|
19
|
+
# Returns a hash of all of the directives that are available in
|
20
|
+
# the generators of this module.
|
21
|
+
#
|
22
|
+
# @see .generators
|
23
|
+
# @return [Hash]
|
24
|
+
def directives
|
25
|
+
generators.values.map(&:directives).
|
26
|
+
inject({}, :merge)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Registers a generator with the given names. If multiple names
|
30
|
+
# are given, they are assigned the generator as a value in the
|
31
|
+
# {#generators} hash; otherwise, the one name is assigned the
|
32
|
+
# generator as a value.
|
33
|
+
#
|
34
|
+
# @param generator [Generator::Base] the generator class to
|
35
|
+
# associate the key with.
|
36
|
+
# @param name [String, Symbol] a name to associate the generator
|
37
|
+
# with.
|
38
|
+
def register_generator(generator, *names)
|
39
|
+
names = [names].flatten
|
40
|
+
raise ArgumentError,
|
41
|
+
"Requires at least one name" unless names.any?
|
42
|
+
raise ArgumentError,
|
43
|
+
"All name values must be a Symbol or string" unless names.
|
44
|
+
all? {|_| [Symbol, String].include?(_.class) }
|
45
|
+
|
46
|
+
names.each do |name|
|
47
|
+
generators[name.to_s.downcase] = generator
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
extend self
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
require "antelope/generator/base"
|
57
|
+
require "antelope/generator/group"
|
58
|
+
require "antelope/generator/info"
|
59
|
+
require "antelope/generator/error"
|
60
|
+
require "antelope/generator/output"
|
61
|
+
require "antelope/generator/html"
|
62
|
+
require "antelope/generator/ruby"
|
63
|
+
require "antelope/generator/null"
|
64
|
+
require "antelope/generator/c_header"
|
65
|
+
require "antelope/generator/c_source"
|
66
|
+
require "antelope/generator/c"
|