antelope 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +25 -25
  3. data/.rspec +3 -3
  4. data/.travis.yml +10 -10
  5. data/.yardopts +7 -7
  6. data/CONTRIBUTING.md +50 -38
  7. data/GENERATORS.md +180 -124
  8. data/Gemfile +7 -7
  9. data/LICENSE.txt +22 -22
  10. data/README.md +240 -104
  11. data/Rakefile +2 -2
  12. data/TODO.md +58 -58
  13. data/antelope.gemspec +29 -28
  14. data/bin/antelope +7 -7
  15. data/examples/deterministic.ace +35 -35
  16. data/examples/example.ace +52 -51
  17. data/examples/example.ace.err +192 -192
  18. data/examples/example.ace.inf +432 -432
  19. data/examples/example.ate +70 -70
  20. data/examples/example.ate.err +192 -192
  21. data/examples/example.ate.inf +432 -432
  22. data/examples/liquidscript.ace +233 -233
  23. data/examples/simple.ace +22 -22
  24. data/lib/antelope/ace/compiler.rb +334 -334
  25. data/lib/antelope/ace/errors.rb +30 -30
  26. data/lib/antelope/ace/scanner/argument.rb +57 -57
  27. data/lib/antelope/ace/scanner/first.rb +89 -89
  28. data/lib/antelope/ace/scanner/second.rb +178 -178
  29. data/lib/antelope/ace/scanner/third.rb +27 -27
  30. data/lib/antelope/ace/scanner.rb +144 -144
  31. data/lib/antelope/ace.rb +47 -47
  32. data/lib/antelope/cli.rb +60 -60
  33. data/lib/antelope/errors.rb +25 -25
  34. data/lib/antelope/generation/constructor/first.rb +86 -86
  35. data/lib/antelope/generation/constructor/follow.rb +105 -105
  36. data/lib/antelope/generation/constructor/nullable.rb +64 -64
  37. data/lib/antelope/generation/constructor.rb +127 -127
  38. data/lib/antelope/generation/errors.rb +17 -17
  39. data/lib/antelope/generation/null.rb +13 -13
  40. data/lib/antelope/generation/recognizer/rule.rb +216 -216
  41. data/lib/antelope/generation/recognizer/state.rb +129 -129
  42. data/lib/antelope/generation/recognizer.rb +177 -177
  43. data/lib/antelope/generation/tableizer.rb +176 -176
  44. data/lib/antelope/generation.rb +15 -15
  45. data/lib/antelope/generator/base/coerce.rb +115 -0
  46. data/lib/antelope/generator/base/extra.rb +50 -0
  47. data/lib/antelope/generator/base.rb +134 -264
  48. data/lib/antelope/generator/c.rb +11 -11
  49. data/lib/antelope/generator/c_header.rb +105 -105
  50. data/lib/antelope/generator/c_source.rb +39 -39
  51. data/lib/antelope/generator/error.rb +34 -34
  52. data/lib/antelope/generator/group.rb +60 -57
  53. data/lib/antelope/generator/html.rb +51 -51
  54. data/lib/antelope/generator/info.rb +47 -47
  55. data/lib/antelope/generator/null.rb +18 -18
  56. data/lib/antelope/generator/output.rb +17 -17
  57. data/lib/antelope/generator/ruby.rb +112 -79
  58. data/lib/antelope/generator/templates/c_header.ant +36 -36
  59. data/lib/antelope/generator/templates/c_source.ant +202 -202
  60. data/lib/antelope/generator/templates/error.erb +40 -0
  61. data/lib/antelope/generator/templates/html/antelope.css +53 -1
  62. data/lib/antelope/generator/templates/html/antelope.html +82 -1
  63. data/lib/antelope/generator/templates/html/antelope.js +9 -1
  64. data/lib/antelope/generator/templates/html/css.ant +53 -53
  65. data/lib/antelope/generator/templates/html/html.ant +82 -82
  66. data/lib/antelope/generator/templates/html/js.ant +9 -9
  67. data/lib/antelope/generator/templates/info.erb +61 -0
  68. data/lib/antelope/generator/templates/{ruby.ant → ruby.erb} +171 -178
  69. data/lib/antelope/generator.rb +62 -66
  70. data/lib/antelope/grammar/generation.rb +76 -76
  71. data/lib/antelope/grammar/loading.rb +84 -84
  72. data/lib/antelope/grammar/precedence.rb +59 -59
  73. data/lib/antelope/grammar/precedences.rb +64 -64
  74. data/lib/antelope/grammar/production.rb +56 -56
  75. data/lib/antelope/grammar/productions.rb +154 -154
  76. data/lib/antelope/grammar/symbols.rb +64 -64
  77. data/lib/antelope/grammar/token/epsilon.rb +23 -23
  78. data/lib/antelope/grammar/token/error.rb +24 -24
  79. data/lib/antelope/grammar/token/nonterminal.rb +15 -15
  80. data/lib/antelope/grammar/token/terminal.rb +15 -15
  81. data/lib/antelope/grammar/token.rb +231 -231
  82. data/lib/antelope/grammar.rb +68 -68
  83. data/lib/antelope/version.rb +6 -6
  84. data/lib/antelope.rb +18 -19
  85. data/optimizations.txt +42 -42
  86. data/spec/antelope/ace/compiler_spec.rb +60 -60
  87. data/spec/antelope/ace/scanner_spec.rb +27 -27
  88. data/spec/antelope/generation/constructor_spec.rb +131 -131
  89. data/spec/fixtures/simple.ace +22 -22
  90. data/spec/spec_helper.rb +39 -39
  91. data/spec/support/benchmark_helper.rb +5 -5
  92. data/spec/support/grammar_helper.rb +14 -14
  93. data/subl/Ace (Ruby).JSON-tmLanguage +94 -94
  94. data/subl/Ace (Ruby).tmLanguage +153 -153
  95. metadata +22 -11
  96. data/lib/antelope/generator/templates/error.ant +0 -34
  97. data/lib/antelope/generator/templates/info.ant +0 -53
  98. data/lib/antelope/template/compiler.rb +0 -78
  99. data/lib/antelope/template/errors.rb +0 -9
  100. data/lib/antelope/template/scanner.rb +0 -109
  101. data/lib/antelope/template.rb +0 -64
  102. data/spec/antelope/template_spec.rb +0 -50
@@ -1,86 +1,86 @@
1
- # encoding: utf-8
2
-
3
- module Antelope
4
- module Generation
5
- class Constructor
6
- # Contains the methods to construct first sets for tokens.
7
- module First
8
- # Initialize.
9
- def initialize
10
- @firstifying = []
11
- super
12
- end
13
-
14
- # Constructs the first set for a given token. This is how
15
- # the method should behave:
16
- #
17
- # FIRST(ε) == [] # if ε is the epsilon token
18
- # FIRST(x) == [x] # if x is a terminal
19
- # FIRST(αβ) == if nullable?(α)
20
- # FIRST(α) U FIRST(β)
21
- # else
22
- # FIRST(α)
23
- # end
24
- # FIRST(A) == FIRST(a_1) U FIRST(a_2) U ... U FIRST(a_n)
25
- # # if A is a nonterminal and a_1, a_2, ..., a_3 are all
26
- # # of the right-hand sides of its productions.
27
- #
28
- # @param token [Grammar::Token, Array<Grammar::Token>]
29
- # @return [Set<Grammar::Token::Terminal>]
30
- # @see #first_array
31
- def first(token)
32
- case token
33
- when Grammar::Token::Nonterminal
34
- firstifying(token) do
35
- productions = grammar.productions[token.name]
36
- productions.map { |prod|
37
- first(prod[:items]) }.inject(Set.new, :+)
38
- end
39
- when Array
40
- first_array(token)
41
- when Grammar::Token::Epsilon
42
- Set.new
43
- when Grammar::Token::Terminal
44
- Set.new([token])
45
- else
46
- incorrect_argument! token, Grammar::Token, Array
47
- end
48
- end
49
-
50
- private
51
-
52
- # Determines the FIRST set of an array of tokens. First, it
53
- # removes any terminals we are finding the FIRST set for;
54
- # then, it determines which tokens we have to find the FIRST
55
- # sets for (since some tokens may be nullable). We then add
56
- # those sets to our set.
57
- #
58
- # @param tokens [Array<Grammar::Token>]
59
- # @return [Set<Grammar::Token>]
60
- def first_array(tokens)
61
- tokens.dup.delete_if { |_| @firstifying.include?(_) }.
62
- each_with_index.take_while do |token, i|
63
- if i.zero?
64
- true
65
- else
66
- nullable?(tokens[i - 1])
67
- end
68
- end.map(&:first).map { |_| first(_) }.inject(Set.new, :+)
69
- end
70
-
71
- # Helps keep track of the nonterminals we're finding FIRST
72
- # sets for. This helps prevent recursion.
73
- #
74
- # @param tok [Grammar::Token::Nonterminal]
75
- # @yield once.
76
- # @return [Set<Grammar::Token>]
77
- def firstifying(tok)
78
- @firstifying << tok
79
- out = yield
80
- @firstifying.delete tok
81
- out
82
- end
83
- end
84
- end
85
- end
86
- end
1
+ # encoding: utf-8
2
+
3
+ module Antelope
4
+ module Generation
5
+ class Constructor
6
+ # Contains the methods to construct first sets for tokens.
7
+ module First
8
+ # Initialize.
9
+ def initialize
10
+ @firstifying = []
11
+ super
12
+ end
13
+
14
+ # Constructs the first set for a given token. This is how
15
+ # the method should behave:
16
+ #
17
+ # FIRST(ε) == [] # if ε is the epsilon token
18
+ # FIRST(x) == [x] # if x is a terminal
19
+ # FIRST(αβ) == if nullable?(α)
20
+ # FIRST(α) U FIRST(β)
21
+ # else
22
+ # FIRST(α)
23
+ # end
24
+ # FIRST(A) == FIRST(a_1) U FIRST(a_2) U ... U FIRST(a_n)
25
+ # # if A is a nonterminal and a_1, a_2, ..., a_3 are all
26
+ # # of the right-hand sides of its productions.
27
+ #
28
+ # @param token [Grammar::Token, Array<Grammar::Token>]
29
+ # @return [Set<Grammar::Token::Terminal>]
30
+ # @see #first_array
31
+ def first(token)
32
+ case token
33
+ when Grammar::Token::Nonterminal
34
+ firstifying(token) do
35
+ productions = grammar.productions[token.name]
36
+ productions.map { |prod|
37
+ first(prod[:items]) }.inject(Set.new, :+)
38
+ end
39
+ when Array
40
+ first_array(token)
41
+ when Grammar::Token::Epsilon
42
+ Set.new
43
+ when Grammar::Token::Terminal
44
+ Set.new([token])
45
+ else
46
+ incorrect_argument! token, Grammar::Token, Array
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ # Determines the FIRST set of an array of tokens. First, it
53
+ # removes any terminals we are finding the FIRST set for;
54
+ # then, it determines which tokens we have to find the FIRST
55
+ # sets for (since some tokens may be nullable). We then add
56
+ # those sets to our set.
57
+ #
58
+ # @param tokens [Array<Grammar::Token>]
59
+ # @return [Set<Grammar::Token>]
60
+ def first_array(tokens)
61
+ tokens.dup.delete_if { |_| @firstifying.include?(_) }.
62
+ each_with_index.take_while do |token, i|
63
+ if i.zero?
64
+ true
65
+ else
66
+ nullable?(tokens[i - 1])
67
+ end
68
+ end.map(&:first).map { |_| first(_) }.inject(Set.new, :+)
69
+ end
70
+
71
+ # Helps keep track of the nonterminals we're finding FIRST
72
+ # sets for. This helps prevent recursion.
73
+ #
74
+ # @param tok [Grammar::Token::Nonterminal]
75
+ # @yield once.
76
+ # @return [Set<Grammar::Token>]
77
+ def firstifying(tok)
78
+ @firstifying << tok
79
+ out = yield
80
+ @firstifying.delete tok
81
+ out
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -1,105 +1,105 @@
1
- # encoding: utf-8
2
-
3
- module Antelope
4
- module Generation
5
- class Constructor
6
-
7
- # Contains the methods to find the FOLLOW sets of nonterminals.
8
- module Follow
9
-
10
- # Initialize.
11
- def initialize
12
- @follows = {}
13
- super
14
- end
15
-
16
- # Returns the FOLLOW set of the given token. If the given
17
- # token isn't a nonterminal, it raises an error. It then
18
- # generates the FOLLOW set for the given token, and then
19
- # caches it.
20
- #
21
- # @return [Set<Grammar::Token>]
22
- # @see Constructor#incorrect_argument!
23
- # @see #generate_follow_set
24
- def follow(token)
25
- unless token.is_a? Grammar::Token::Nonterminal
26
- incorrect_argument! token, Grammar::Token::Nonterminal
27
- end
28
-
29
- @follows.fetch(token) { generate_follow_set(token) }
30
- end
31
-
32
- private
33
-
34
- # Generates the FOLLOW set for the given token. It finds the
35
- # positions at which the token appears in the grammar, and
36
- # sees what could possibly follow it. For example, given the
37
- # following production:
38
- #
39
- # A -> aBz
40
- #
41
- # With `a` and `z` being any combination of terminals and
42
- # nonterminals, and we're trying to find the FOLLOW set of
43
- # `B` we add the FIRST set of `z` to the FOLLOW set of `B`:
44
- #
45
- # FOLLOW(B) = FOLLOW(B) ∪ FIRST(z)
46
- #
47
- # In the case that `B` is at the end of a production, like so:
48
- #
49
- # A -> aB
50
- #
51
- # or
52
- #
53
- # A -> aBw
54
- #
55
- # (with `w` being nullable) We also add the FOLLOW set of `A`
56
- # to `B`:
57
- #
58
- # FOLLOW(B) = FOLLOW(B) ∪ FOLLOW(A)
59
- #
60
- # In case this operation is potentially recursive, we make
61
- # sure to set the FOLLOW set of `B` to an empty set (since we
62
- # cache the result of a FOLLOW set, the empty set will be
63
- # returned).
64
- #
65
- # @param token [Grammar::Token::Nonterminal]
66
- # @return [Set<Grammar::Token>]
67
- # @see First#first
68
- # @see Nullable#nullable?
69
- def generate_follow_set(token)
70
- # Set it to the empty set so we don't end up recursing.
71
- @follows[token] = Set.new
72
- set = Set.new
73
-
74
- productions.each do |rule|
75
- items = rule.items
76
- i = 0
77
-
78
- # Find all of the positions within the rule that our token
79
- # occurs, and then increment that position by one.
80
- while i < items.size
81
- next i += 1 unless items[i] == token
82
- position = i.succ
83
-
84
- # Find the FIRST set of every item after our token, and
85
- # put that in our set.
86
- set.merge first(items[position..-1])
87
-
88
- # If we're at the end of the rule...
89
- if position == items.size || nullable?(items[position..-1])
90
- # Then add the FOLLOW set of the left-hand side to our
91
- # set.
92
- set.merge follow(rule.label)
93
- end
94
-
95
- i += 1
96
- end
97
- end
98
-
99
- # ReplGrammar the cached empty set with our filled set.
100
- @follows[token] = set
101
- end
102
- end
103
- end
104
- end
105
- end
1
+ # encoding: utf-8
2
+
3
+ module Antelope
4
+ module Generation
5
+ class Constructor
6
+
7
+ # Contains the methods to find the FOLLOW sets of nonterminals.
8
+ module Follow
9
+
10
+ # Initialize.
11
+ def initialize
12
+ @follows = {}
13
+ super
14
+ end
15
+
16
+ # Returns the FOLLOW set of the given token. If the given
17
+ # token isn't a nonterminal, it raises an error. It then
18
+ # generates the FOLLOW set for the given token, and then
19
+ # caches it.
20
+ #
21
+ # @return [Set<Grammar::Token>]
22
+ # @see Constructor#incorrect_argument!
23
+ # @see #generate_follow_set
24
+ def follow(token)
25
+ unless token.is_a? Grammar::Token::Nonterminal
26
+ incorrect_argument! token, Grammar::Token::Nonterminal
27
+ end
28
+
29
+ @follows.fetch(token) { generate_follow_set(token) }
30
+ end
31
+
32
+ private
33
+
34
+ # Generates the FOLLOW set for the given token. It finds the
35
+ # positions at which the token appears in the grammar, and
36
+ # sees what could possibly follow it. For example, given the
37
+ # following production:
38
+ #
39
+ # A -> aBz
40
+ #
41
+ # With `a` and `z` being any combination of terminals and
42
+ # nonterminals, and we're trying to find the FOLLOW set of
43
+ # `B` we add the FIRST set of `z` to the FOLLOW set of `B`:
44
+ #
45
+ # FOLLOW(B) = FOLLOW(B) ∪ FIRST(z)
46
+ #
47
+ # In the case that `B` is at the end of a production, like so:
48
+ #
49
+ # A -> aB
50
+ #
51
+ # or
52
+ #
53
+ # A -> aBw
54
+ #
55
+ # (with `w` being nullable) We also add the FOLLOW set of `A`
56
+ # to `B`:
57
+ #
58
+ # FOLLOW(B) = FOLLOW(B) ∪ FOLLOW(A)
59
+ #
60
+ # In case this operation is potentially recursive, we make
61
+ # sure to set the FOLLOW set of `B` to an empty set (since we
62
+ # cache the result of a FOLLOW set, the empty set will be
63
+ # returned).
64
+ #
65
+ # @param token [Grammar::Token::Nonterminal]
66
+ # @return [Set<Grammar::Token>]
67
+ # @see First#first
68
+ # @see Nullable#nullable?
69
+ def generate_follow_set(token)
70
+ # Set it to the empty set so we don't end up recursing.
71
+ @follows[token] = Set.new
72
+ set = Set.new
73
+
74
+ productions.each do |rule|
75
+ items = rule.items
76
+ i = 0
77
+
78
+ # Find all of the positions within the rule that our token
79
+ # occurs, and then increment that position by one.
80
+ while i < items.size
81
+ next i += 1 unless items[i] == token
82
+ position = i.succ
83
+
84
+ # Find the FIRST set of every item after our token, and
85
+ # put that in our set.
86
+ set.merge first(items[position..-1])
87
+
88
+ # If we're at the end of the rule...
89
+ if position == items.size || nullable?(items[position..-1])
90
+ # Then add the FOLLOW set of the left-hand side to our
91
+ # set.
92
+ set.merge follow(rule.label)
93
+ end
94
+
95
+ i += 1
96
+ end
97
+ end
98
+
99
+ # ReplGrammar the cached empty set with our filled set.
100
+ @follows[token] = set
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -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 [Grammar::Token, Array<Grammar::Token>] the token to
26
- # check.
27
- # @return [Boolean] if the token can reduce to ϵ.
28
- def nullable?(token)
29
- case token
30
- when Grammar::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 Grammar::Token::Epsilon
39
- true
40
- when Grammar::Token::Terminal
41
- false
42
- else
43
- incorrect_argument! token, Grammar::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 [Grammar::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 [Grammar::Token, Array<Grammar::Token>] the token to
26
+ # check.
27
+ # @return [Boolean] if the token can reduce to ϵ.
28
+ def nullable?(token)
29
+ case token
30
+ when Grammar::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 Grammar::Token::Epsilon
39
+ true
40
+ when Grammar::Token::Terminal
41
+ false
42
+ else
43
+ incorrect_argument! token, Grammar::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 [Grammar::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