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,64 +1,64 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Antelope
|
4
|
-
module Generation
|
5
|
-
class Constructor
|
6
|
-
|
7
|
-
# Contains the methods to determine if an object is nullable.
|
8
|
-
module Nullable
|
9
|
-
|
10
|
-
# Initialize.
|
11
|
-
def initialize
|
12
|
-
@nullifying = Set.new
|
13
|
-
end
|
14
|
-
|
15
|
-
# Determine if a given token is nullable. This is how the
|
16
|
-
# method should behave:
|
17
|
-
#
|
18
|
-
# nullable?(ϵ) == true # if ϵ is the epsilon token
|
19
|
-
# nullable?(x) == false # if x is a terminal
|
20
|
-
# nullable?(αβ) == nullable?(α) && nullable?(β)
|
21
|
-
# nullable?(A) == nullable?(a_1) || nullable?(a_2) || ... nullable?(a_n)
|
22
|
-
# # if A is a nonterminal and a_1, a_2, ..., a_n are all
|
23
|
-
# # of the right-hand sides of its productions
|
24
|
-
#
|
25
|
-
# @param token [Ace::Token, Array<Ace::Token>] the token to
|
26
|
-
# check.
|
27
|
-
# @return [Boolean] if the token can reduce to ϵ.
|
28
|
-
def nullable?(token)
|
29
|
-
case token
|
30
|
-
when Ace::Token::Nonterminal
|
31
|
-
nullifying(token) do
|
32
|
-
productions = grammar.productions[token.name]
|
33
|
-
!!productions.any? { |prod| nullable?(prod[:items]) }
|
34
|
-
end
|
35
|
-
when Array
|
36
|
-
token.dup.delete_if { |tok|
|
37
|
-
@nullifying.include?(tok) }.all? { |tok| nullable?(tok) }
|
38
|
-
when Ace::Token::Epsilon
|
39
|
-
true
|
40
|
-
when Ace::Token::Terminal
|
41
|
-
false
|
42
|
-
else
|
43
|
-
incorrect_argument! token, Ace::Token, Array
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
private
|
48
|
-
|
49
|
-
# Helps keep track of the nonterminals we're checking for
|
50
|
-
# nullability. This helps prevent recursion.
|
51
|
-
#
|
52
|
-
# @param tok [Ace::Token::Nonterminal]
|
53
|
-
# @yield once.
|
54
|
-
# @return [Boolean]
|
55
|
-
def nullifying(tok)
|
56
|
-
@nullifying << tok
|
57
|
-
out = yield
|
58
|
-
@nullifying.delete tok
|
59
|
-
out
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Antelope
|
4
|
+
module Generation
|
5
|
+
class Constructor
|
6
|
+
|
7
|
+
# Contains the methods to determine if an object is nullable.
|
8
|
+
module Nullable
|
9
|
+
|
10
|
+
# Initialize.
|
11
|
+
def initialize
|
12
|
+
@nullifying = Set.new
|
13
|
+
end
|
14
|
+
|
15
|
+
# Determine if a given token is nullable. This is how the
|
16
|
+
# method should behave:
|
17
|
+
#
|
18
|
+
# nullable?(ϵ) == true # if ϵ is the epsilon token
|
19
|
+
# nullable?(x) == false # if x is a terminal
|
20
|
+
# nullable?(αβ) == nullable?(α) && nullable?(β)
|
21
|
+
# nullable?(A) == nullable?(a_1) || nullable?(a_2) || ... nullable?(a_n)
|
22
|
+
# # if A is a nonterminal and a_1, a_2, ..., a_n are all
|
23
|
+
# # of the right-hand sides of its productions
|
24
|
+
#
|
25
|
+
# @param token [Ace::Token, Array<Ace::Token>] the token to
|
26
|
+
# check.
|
27
|
+
# @return [Boolean] if the token can reduce to ϵ.
|
28
|
+
def nullable?(token)
|
29
|
+
case token
|
30
|
+
when Ace::Token::Nonterminal
|
31
|
+
nullifying(token) do
|
32
|
+
productions = grammar.productions[token.name]
|
33
|
+
!!productions.any? { |prod| nullable?(prod[:items]) }
|
34
|
+
end
|
35
|
+
when Array
|
36
|
+
token.dup.delete_if { |tok|
|
37
|
+
@nullifying.include?(tok) }.all? { |tok| nullable?(tok) }
|
38
|
+
when Ace::Token::Epsilon
|
39
|
+
true
|
40
|
+
when Ace::Token::Terminal
|
41
|
+
false
|
42
|
+
else
|
43
|
+
incorrect_argument! token, Ace::Token, Array
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
# Helps keep track of the nonterminals we're checking for
|
50
|
+
# nullability. This helps prevent recursion.
|
51
|
+
#
|
52
|
+
# @param tok [Ace::Token::Nonterminal]
|
53
|
+
# @yield once.
|
54
|
+
# @return [Boolean]
|
55
|
+
def nullifying(tok)
|
56
|
+
@nullifying << tok
|
57
|
+
out = yield
|
58
|
+
@nullifying.delete tok
|
59
|
+
out
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -1,126 +1,126 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require "set"
|
4
|
-
require "antelope/generation/constructor/nullable"
|
5
|
-
require "antelope/generation/constructor/first"
|
6
|
-
require "antelope/generation/constructor/follow"
|
7
|
-
|
8
|
-
module Antelope
|
9
|
-
module Generation
|
10
|
-
|
11
|
-
# Constructs the lookahead sets for all of the rules in the
|
12
|
-
# grammar.
|
13
|
-
class Constructor
|
14
|
-
|
15
|
-
include Nullable
|
16
|
-
include First
|
17
|
-
include Follow
|
18
|
-
|
19
|
-
# The grammar.
|
20
|
-
#
|
21
|
-
# @return [Ace::Grammar]
|
22
|
-
attr_reader :grammar
|
23
|
-
|
24
|
-
# The augmented productions generated by the constructor.
|
25
|
-
#
|
26
|
-
# @return [Set<Ace::Production>]
|
27
|
-
attr_reader :productions
|
28
|
-
|
29
|
-
# Initialize.
|
30
|
-
#
|
31
|
-
# @param grammar [Ace::Grammar] the grammar.
|
32
|
-
def initialize(grammar)
|
33
|
-
@productions = Set.new
|
34
|
-
@grammar = grammar
|
35
|
-
super()
|
36
|
-
end
|
37
|
-
|
38
|
-
# Performs the construction. First, it goes through every state
|
39
|
-
# and augments the state. It then goes through every rule and
|
40
|
-
# augments it.
|
41
|
-
#
|
42
|
-
# @return [void]
|
43
|
-
# @see #augment_state
|
44
|
-
# @see #augment_rule
|
45
|
-
def call
|
46
|
-
grammar.states.each do |state|
|
47
|
-
augment_state(state)
|
48
|
-
end.each do |state|
|
49
|
-
augment_rules(state)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
# Augments the given state. On every rule within that state
|
54
|
-
# that has a position of zero, it follows the rule throughout
|
55
|
-
# the DFA until the end; it marks every nonterminal it
|
56
|
-
# encounters with the transitions it took on that nonterminal.
|
57
|
-
#
|
58
|
-
# @param state [Recognizer::State] the state to augment.
|
59
|
-
# @return [void]
|
60
|
-
def augment_state(state)
|
61
|
-
state.rules.select { |x| x.position.zero? }.each do |rule|
|
62
|
-
production = rule.production.clone
|
63
|
-
production.items = []
|
64
|
-
|
65
|
-
current_state = state
|
66
|
-
old_state = state
|
67
|
-
|
68
|
-
production.label.from = state
|
69
|
-
production.label.to = state.transitions[rule.left.name]
|
70
|
-
|
71
|
-
rule.right.each_with_index do |part, pos|
|
72
|
-
transition = current_state.transitions[part.name]
|
73
|
-
new_item = part.dup
|
74
|
-
|
75
|
-
if part.nonterminal?
|
76
|
-
new_item.from = current_state
|
77
|
-
new_item.to = transition
|
78
|
-
end
|
79
|
-
|
80
|
-
production.items << new_item
|
81
|
-
|
82
|
-
old_state = current_state
|
83
|
-
current_state = transition
|
84
|
-
end
|
85
|
-
|
86
|
-
productions << production
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
# Augments every final rule. For every rule in the current
|
91
|
-
# state that has a position of zero, it follows the rule through
|
92
|
-
# the DFA until the ending state; it then modifies the ending
|
93
|
-
# state's lookahead set to be the FOLLOW set of the nonterminal
|
94
|
-
# it reduces to.
|
95
|
-
#
|
96
|
-
# @param state [Recognizer::State]
|
97
|
-
# @return [void]
|
98
|
-
# @see Follow#follow
|
99
|
-
def augment_rules(state)
|
100
|
-
state.rules.select { |x| x.position.zero? }.each do |rule|
|
101
|
-
current_state = state
|
102
|
-
|
103
|
-
label = rule.left.dup
|
104
|
-
label.from = state
|
105
|
-
label.to = state.transitions[label.name]
|
106
|
-
|
107
|
-
rule.right.each do |part|
|
108
|
-
transition = current_state.transitions[part.name]
|
109
|
-
current_state = transition
|
110
|
-
end
|
111
|
-
|
112
|
-
final = current_state.rule_for(rule)
|
113
|
-
|
114
|
-
final.lookahead = Set.new unless final.lookahead
|
115
|
-
final.lookahead.merge follow(label)
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
private
|
120
|
-
|
121
|
-
def incorrect_argument!(arg, *types)
|
122
|
-
raise ArgumentError, "Expected one of #{types.join(", ")}, got #{arg.class}"
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "set"
|
4
|
+
require "antelope/generation/constructor/nullable"
|
5
|
+
require "antelope/generation/constructor/first"
|
6
|
+
require "antelope/generation/constructor/follow"
|
7
|
+
|
8
|
+
module Antelope
|
9
|
+
module Generation
|
10
|
+
|
11
|
+
# Constructs the lookahead sets for all of the rules in the
|
12
|
+
# grammar.
|
13
|
+
class Constructor
|
14
|
+
|
15
|
+
include Nullable
|
16
|
+
include First
|
17
|
+
include Follow
|
18
|
+
|
19
|
+
# The grammar.
|
20
|
+
#
|
21
|
+
# @return [Ace::Grammar]
|
22
|
+
attr_reader :grammar
|
23
|
+
|
24
|
+
# The augmented productions generated by the constructor.
|
25
|
+
#
|
26
|
+
# @return [Set<Ace::Production>]
|
27
|
+
attr_reader :productions
|
28
|
+
|
29
|
+
# Initialize.
|
30
|
+
#
|
31
|
+
# @param grammar [Ace::Grammar] the grammar.
|
32
|
+
def initialize(grammar)
|
33
|
+
@productions = Set.new
|
34
|
+
@grammar = grammar
|
35
|
+
super()
|
36
|
+
end
|
37
|
+
|
38
|
+
# Performs the construction. First, it goes through every state
|
39
|
+
# and augments the state. It then goes through every rule and
|
40
|
+
# augments it.
|
41
|
+
#
|
42
|
+
# @return [void]
|
43
|
+
# @see #augment_state
|
44
|
+
# @see #augment_rule
|
45
|
+
def call
|
46
|
+
grammar.states.each do |state|
|
47
|
+
augment_state(state)
|
48
|
+
end.each do |state|
|
49
|
+
augment_rules(state)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Augments the given state. On every rule within that state
|
54
|
+
# that has a position of zero, it follows the rule throughout
|
55
|
+
# the DFA until the end; it marks every nonterminal it
|
56
|
+
# encounters with the transitions it took on that nonterminal.
|
57
|
+
#
|
58
|
+
# @param state [Recognizer::State] the state to augment.
|
59
|
+
# @return [void]
|
60
|
+
def augment_state(state)
|
61
|
+
state.rules.select { |x| x.position.zero? }.each do |rule|
|
62
|
+
production = rule.production.clone
|
63
|
+
production.items = []
|
64
|
+
|
65
|
+
current_state = state
|
66
|
+
old_state = state
|
67
|
+
|
68
|
+
production.label.from = state
|
69
|
+
production.label.to = state.transitions[rule.left.name]
|
70
|
+
|
71
|
+
rule.right.each_with_index do |part, pos|
|
72
|
+
transition = current_state.transitions[part.name]
|
73
|
+
new_item = part.dup
|
74
|
+
|
75
|
+
if part.nonterminal?
|
76
|
+
new_item.from = current_state
|
77
|
+
new_item.to = transition
|
78
|
+
end
|
79
|
+
|
80
|
+
production.items << new_item
|
81
|
+
|
82
|
+
old_state = current_state
|
83
|
+
current_state = transition
|
84
|
+
end
|
85
|
+
|
86
|
+
productions << production
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Augments every final rule. For every rule in the current
|
91
|
+
# state that has a position of zero, it follows the rule through
|
92
|
+
# the DFA until the ending state; it then modifies the ending
|
93
|
+
# state's lookahead set to be the FOLLOW set of the nonterminal
|
94
|
+
# it reduces to.
|
95
|
+
#
|
96
|
+
# @param state [Recognizer::State]
|
97
|
+
# @return [void]
|
98
|
+
# @see Follow#follow
|
99
|
+
def augment_rules(state)
|
100
|
+
state.rules.select { |x| x.position.zero? }.each do |rule|
|
101
|
+
current_state = state
|
102
|
+
|
103
|
+
label = rule.left.dup
|
104
|
+
label.from = state
|
105
|
+
label.to = state.transitions[label.name]
|
106
|
+
|
107
|
+
rule.right.each do |part|
|
108
|
+
transition = current_state.transitions[part.name]
|
109
|
+
current_state = transition
|
110
|
+
end
|
111
|
+
|
112
|
+
final = current_state.rule_for(rule)
|
113
|
+
|
114
|
+
final.lookahead = Set.new unless final.lookahead
|
115
|
+
final.lookahead.merge follow(label)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
def incorrect_argument!(arg, *types)
|
122
|
+
raise ArgumentError, "Expected one of #{types.join(", ")}, got #{arg.class}"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -1,17 +1,17 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Antelope
|
4
|
-
module Generation
|
5
|
-
|
6
|
-
# Defines an error that can occur within the Generation module.
|
7
|
-
# All errors that are raised within the Generation module are
|
8
|
-
# subclasses of this.
|
9
|
-
class Error < Antelope::Error
|
10
|
-
end
|
11
|
-
|
12
|
-
# Used mainly in the {Tableizer}, this is raised when a conflict
|
13
|
-
# could not be resolved.
|
14
|
-
class UnresolvableConflictError < Error
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Antelope
|
4
|
+
module Generation
|
5
|
+
|
6
|
+
# Defines an error that can occur within the Generation module.
|
7
|
+
# All errors that are raised within the Generation module are
|
8
|
+
# subclasses of this.
|
9
|
+
class Error < Antelope::Error
|
10
|
+
end
|
11
|
+
|
12
|
+
# Used mainly in the {Tableizer}, this is raised when a conflict
|
13
|
+
# could not be resolved.
|
14
|
+
class UnresolvableConflictError < Error
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -1,13 +1,13 @@
|
|
1
|
-
module Antelope
|
2
|
-
module Generation
|
3
|
-
class Null
|
4
|
-
|
5
|
-
|
6
|
-
def initialize(*)
|
7
|
-
end
|
8
|
-
|
9
|
-
def call(*)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
1
|
+
module Antelope
|
2
|
+
module Generation
|
3
|
+
class Null
|
4
|
+
|
5
|
+
|
6
|
+
def initialize(*)
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(*)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|