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
@@ -1,154 +1,175 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Antelope
|
4
|
-
module Generation
|
5
|
-
|
6
|
-
# Constructs the table required for the parser.
|
7
|
-
class Tableizer
|
8
|
-
|
9
|
-
# The grammar that the table is based off of.
|
10
|
-
#
|
11
|
-
# @return [Ace::Grammar]
|
12
|
-
attr_accessor :grammar
|
13
|
-
|
14
|
-
# The table itself.
|
15
|
-
#
|
16
|
-
# @return [Array<Hash<(Symbol, Array<(Symbol, Numeric)>)>>]
|
17
|
-
attr_accessor :table
|
18
|
-
|
19
|
-
# All rules in the grammar.
|
20
|
-
#
|
21
|
-
# @return [Hash<(Numeric, Recognizer::Rule)>]
|
22
|
-
attr_accessor :rules
|
23
|
-
|
24
|
-
attr_reader :conflicts
|
25
|
-
|
26
|
-
# Initialize.
|
27
|
-
#
|
28
|
-
# @param grammar [Ace::Grammar]
|
29
|
-
def initialize(grammar)
|
30
|
-
@grammar = grammar
|
31
|
-
end
|
32
|
-
|
33
|
-
# Construct the table, and then check the table for conflicts.
|
34
|
-
#
|
35
|
-
# @return [void]
|
36
|
-
# @see #tablize
|
37
|
-
# @see #conflictize
|
38
|
-
def call
|
39
|
-
tablize
|
40
|
-
conflictize
|
41
|
-
defaultize
|
42
|
-
end
|
43
|
-
|
44
|
-
# Construct a table based on the grammar. The table itself is
|
45
|
-
# an array whose elements are hashes; the index of the array
|
46
|
-
# corresponds to the state ID, and the keys of the hashes
|
47
|
-
# correspond to acceptable tokens. The values of the hashes
|
48
|
-
# should be an array of arrays (at this point).
|
49
|
-
#
|
50
|
-
# @return [void]
|
51
|
-
def tablize
|
52
|
-
@table = Array.new(grammar.states.size) do
|
53
|
-
Hash.new { |h, k| h[k] = [] }
|
54
|
-
end
|
55
|
-
@rules = []
|
56
|
-
|
57
|
-
grammar.states.each do |state|
|
58
|
-
state.transitions.each do |on, to|
|
59
|
-
table[state.id][on] << [:state, to.id]
|
60
|
-
end
|
61
|
-
|
62
|
-
state.rules.each do |rule|
|
63
|
-
@rules[rule.production.id] = rule.production
|
64
|
-
if rule.final?
|
65
|
-
rule.lookahead.each do |look|
|
66
|
-
table[state.id][look.name] <<
|
67
|
-
[:reduce, rule.production.id]
|
68
|
-
end
|
69
|
-
|
70
|
-
if rule.production.id.zero?
|
71
|
-
table[state.id][:$end] =
|
72
|
-
[[:accept, rule.production.id]]
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
table
|
79
|
-
end
|
80
|
-
|
81
|
-
# Resolve any conflicts through precedence, if we can. If we
|
82
|
-
# can't, let the user know. This makes sure that every value
|
83
|
-
# of the hashes is a single array.
|
84
|
-
#
|
85
|
-
# @raise [UnresolvableConflictError] if a conflict could not be
|
86
|
-
# resolved using precedence rules.
|
87
|
-
# @return [void]
|
88
|
-
def conflictize
|
89
|
-
|
90
|
-
@
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
rule_part, other_part = data.sort_by { |(t, _)| t }
|
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
|
-
state
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Antelope
|
4
|
+
module Generation
|
5
|
+
|
6
|
+
# Constructs the table required for the parser.
|
7
|
+
class Tableizer
|
8
|
+
|
9
|
+
# The grammar that the table is based off of.
|
10
|
+
#
|
11
|
+
# @return [Ace::Grammar]
|
12
|
+
attr_accessor :grammar
|
13
|
+
|
14
|
+
# The table itself.
|
15
|
+
#
|
16
|
+
# @return [Array<Hash<(Symbol, Array<(Symbol, Numeric)>)>>]
|
17
|
+
attr_accessor :table
|
18
|
+
|
19
|
+
# All rules in the grammar.
|
20
|
+
#
|
21
|
+
# @return [Hash<(Numeric, Recognizer::Rule)>]
|
22
|
+
attr_accessor :rules
|
23
|
+
|
24
|
+
attr_reader :conflicts
|
25
|
+
|
26
|
+
# Initialize.
|
27
|
+
#
|
28
|
+
# @param grammar [Ace::Grammar]
|
29
|
+
def initialize(grammar)
|
30
|
+
@grammar = grammar
|
31
|
+
end
|
32
|
+
|
33
|
+
# Construct the table, and then check the table for conflicts.
|
34
|
+
#
|
35
|
+
# @return [void]
|
36
|
+
# @see #tablize
|
37
|
+
# @see #conflictize
|
38
|
+
def call
|
39
|
+
tablize
|
40
|
+
conflictize
|
41
|
+
defaultize
|
42
|
+
end
|
43
|
+
|
44
|
+
# Construct a table based on the grammar. The table itself is
|
45
|
+
# an array whose elements are hashes; the index of the array
|
46
|
+
# corresponds to the state ID, and the keys of the hashes
|
47
|
+
# correspond to acceptable tokens. The values of the hashes
|
48
|
+
# should be an array of arrays (at this point).
|
49
|
+
#
|
50
|
+
# @return [void]
|
51
|
+
def tablize
|
52
|
+
@table = Array.new(grammar.states.size) do
|
53
|
+
Hash.new { |h, k| h[k] = [] }
|
54
|
+
end
|
55
|
+
@rules = []
|
56
|
+
|
57
|
+
grammar.states.each do |state|
|
58
|
+
state.transitions.each do |on, to|
|
59
|
+
table[state.id][on] << [:state, to.id]
|
60
|
+
end
|
61
|
+
|
62
|
+
state.rules.each do |rule|
|
63
|
+
@rules[rule.production.id] = rule.production
|
64
|
+
if rule.final?
|
65
|
+
rule.lookahead.each do |look|
|
66
|
+
table[state.id][look.name] <<
|
67
|
+
[:reduce, rule.production.id]
|
68
|
+
end
|
69
|
+
|
70
|
+
if rule.production.id.zero?
|
71
|
+
table[state.id][:$end] =
|
72
|
+
[[:accept, rule.production.id]]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
table
|
79
|
+
end
|
80
|
+
|
81
|
+
# Resolve any conflicts through precedence, if we can. If we
|
82
|
+
# can't, let the user know. This makes sure that every value
|
83
|
+
# of the hashes is a single array.
|
84
|
+
#
|
85
|
+
# @raise [UnresolvableConflictError] if a conflict could not be
|
86
|
+
# resolved using precedence rules.
|
87
|
+
# @return [void]
|
88
|
+
def conflictize
|
89
|
+
states = grammar.states.to_a.sort_by(&:id)
|
90
|
+
@conflicts = Hash.new { |h, k| h[k] = {} }
|
91
|
+
@table.each_with_index do |v, state|
|
92
|
+
v.each do |on, data|
|
93
|
+
if data.size == 1
|
94
|
+
@table[state][on] = data[0]
|
95
|
+
next
|
96
|
+
end
|
97
|
+
|
98
|
+
terminal = grammar.precedence_for(on)
|
99
|
+
rule_part, other_part = data.sort_by { |(t, _)| t }
|
100
|
+
|
101
|
+
conflict = proc do |result|
|
102
|
+
hash = { result: result,
|
103
|
+
terminal: terminal,
|
104
|
+
prec: @rules[rule_part[1]].prec,
|
105
|
+
data: data,
|
106
|
+
rules: [], transitions: [] }
|
107
|
+
|
108
|
+
hash[:rules].concat(data.select { |part|
|
109
|
+
part[0] == :reduce || part[0] == :accept
|
110
|
+
}.map { |(_, id)|
|
111
|
+
states[state].rules.select(&:final?).
|
112
|
+
detect { |rule| rule.production.id == id }
|
113
|
+
})
|
114
|
+
hash[:transitions].concat(data.select { |part|
|
115
|
+
part[0] == :state
|
116
|
+
}.map { |_|
|
117
|
+
states[state].rules.
|
118
|
+
detect { |rule| rule.active.name == on }
|
119
|
+
})
|
120
|
+
|
121
|
+
#conflicts[state][on] = [result, rule_part, other_part,
|
122
|
+
# terminal, @rules[rule_part[1]].prec]
|
123
|
+
conflicts[state][on] = hash
|
124
|
+
end
|
125
|
+
|
126
|
+
unless other_part[0] == :state
|
127
|
+
conflict.call(0)
|
128
|
+
$stderr.puts \
|
129
|
+
"Could not determine move for #{on} in state " \
|
130
|
+
"#{state} (reduce/reduce conflict)"
|
131
|
+
next
|
132
|
+
end
|
133
|
+
|
134
|
+
result = @rules[rule_part[1]].prec <=> terminal
|
135
|
+
conflict.call(result)
|
136
|
+
|
137
|
+
case result
|
138
|
+
when 0
|
139
|
+
@table[state][on] = nil
|
140
|
+
$stderr.puts \
|
141
|
+
"Could not determine move for #{on} in state " \
|
142
|
+
"#{state} (shift/reduce conflict)"
|
143
|
+
when 1
|
144
|
+
@table[state][on] = rule_part
|
145
|
+
when -1
|
146
|
+
@table[state][on] = other_part
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Reduce many transitions into a single `$default` transition.
|
153
|
+
# This only works if there is no `$empty` transition; if there
|
154
|
+
# is an `$empty` transition, then the `$default` transition is
|
155
|
+
# set to be the `$empty` transition.
|
156
|
+
#
|
157
|
+
# @return [void]
|
158
|
+
def defaultize
|
159
|
+
max = @table.map { |s| s.keys.size }.max
|
160
|
+
@table.each_with_index do |state|
|
161
|
+
common = state.group_by { |k, v| v }.values.
|
162
|
+
sort_by(&:size).first
|
163
|
+
|
164
|
+
if common.size > (max / 2)
|
165
|
+
action = common[0][1]
|
166
|
+
|
167
|
+
keys = common.map(&:first)
|
168
|
+
state.delete_if { |k, _| keys.include?(k) }
|
169
|
+
state[:$default] = action
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
data/lib/antelope/generation.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require "antelope/generation/errors"
|
4
|
-
require "antelope/generation/constructor"
|
5
|
-
require "antelope/generation/recognizer"
|
6
|
-
require "antelope/generation/tableizer"
|
7
|
-
require "antelope/generation/null"
|
8
|
-
|
9
|
-
module Antelope
|
10
|
-
|
11
|
-
# Contains the generation mods.
|
12
|
-
module Generation
|
13
|
-
|
14
|
-
end
|
15
|
-
end
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "antelope/generation/errors"
|
4
|
+
require "antelope/generation/constructor"
|
5
|
+
require "antelope/generation/recognizer"
|
6
|
+
require "antelope/generation/tableizer"
|
7
|
+
require "antelope/generation/null"
|
8
|
+
|
9
|
+
module Antelope
|
10
|
+
|
11
|
+
# Contains the generation mods.
|
12
|
+
module Generation
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|