dhaka 0.0.3 → 0.0.4
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/lib/dhaka.rb +40 -39
- data/lib/grammar/grammar.rb +25 -2
- data/lib/grammar/grammar_symbol.rb +1 -1
- data/lib/grammar/precedence.rb +14 -0
- data/lib/grammar/production.rb +16 -2
- data/lib/parser/parser.rb +66 -12
- data/test/all_tests.rb +3 -1
- data/test/arithmetic_precedence_evaluator.rb +40 -0
- data/test/arithmetic_precedence_grammar.rb +22 -0
- data/test/arithmetic_precedence_grammar_test.rb +28 -0
- data/test/arithmetic_precedence_parser_test.rb +30 -0
- data/test/parser_test.rb +1 -6
- metadata +7 -2
data/lib/dhaka.rb
CHANGED
@@ -1,44 +1,45 @@
|
|
1
|
-
#--
|
2
|
-
# Copyright (c) 2006 Mushfeq Khan
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
-
# a copy of this software and associated documentation files (the
|
6
|
-
# "Software"), to deal in the Software without restriction, including
|
7
|
-
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
-
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
-
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
-
# the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be
|
13
|
-
# included in all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
-
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
-
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
-
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
-
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
-
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
-
#++
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2006 Mushfeq Khan
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
23
|
|
24
|
-
require 'grammar/grammar_symbol'
|
25
|
-
require 'grammar/production'
|
26
|
-
require 'grammar/closure_hash'
|
27
|
-
require 'grammar/grammar'
|
24
|
+
require File.dirname(__FILE__)+'/grammar/grammar_symbol'
|
25
|
+
require File.dirname(__FILE__)+'/grammar/production'
|
26
|
+
require File.dirname(__FILE__)+'/grammar/closure_hash'
|
27
|
+
require File.dirname(__FILE__)+'/grammar/grammar'
|
28
|
+
require File.dirname(__FILE__)+'/grammar/precedence'
|
28
29
|
|
29
|
-
require 'parser/parse_result'
|
30
|
-
require 'parser/item'
|
31
|
-
require 'parser/channel'
|
32
|
-
require 'parser/parser_methods'
|
33
|
-
require 'parser/parse_tree'
|
34
|
-
require 'parser/parser_state'
|
35
|
-
require 'parser/token'
|
36
|
-
require 'parser/action'
|
37
|
-
require 'parser/parser_run'
|
38
|
-
require 'parser/parser'
|
39
|
-
require 'parser/compiled_parser'
|
30
|
+
require File.dirname(__FILE__)+'/parser/parse_result'
|
31
|
+
require File.dirname(__FILE__)+'/parser/item'
|
32
|
+
require File.dirname(__FILE__)+'/parser/channel'
|
33
|
+
require File.dirname(__FILE__)+'/parser/parser_methods'
|
34
|
+
require File.dirname(__FILE__)+'/parser/parse_tree'
|
35
|
+
require File.dirname(__FILE__)+'/parser/parser_state'
|
36
|
+
require File.dirname(__FILE__)+'/parser/token'
|
37
|
+
require File.dirname(__FILE__)+'/parser/action'
|
38
|
+
require File.dirname(__FILE__)+'/parser/parser_run'
|
39
|
+
require File.dirname(__FILE__)+'/parser/parser'
|
40
|
+
require File.dirname(__FILE__)+'/parser/compiled_parser'
|
40
41
|
|
41
|
-
require 'tokenizer/tokenizer'
|
42
|
-
require 'evaluator/evaluator'
|
42
|
+
require File.dirname(__FILE__)+'/tokenizer/tokenizer'
|
43
|
+
require File.dirname(__FILE__)+'/evaluator/evaluator'
|
43
44
|
|
44
45
|
|
data/lib/grammar/grammar.rb
CHANGED
@@ -11,15 +11,34 @@ module Dhaka
|
|
11
11
|
@symbol = symbol
|
12
12
|
end
|
13
13
|
|
14
|
-
def method_missing(production_name, expansion)
|
14
|
+
def method_missing(production_name, expansion, options = {})
|
15
15
|
expansion_symbols = expansion.collect {|name| @grammar.symbols[name]}
|
16
|
-
|
16
|
+
if precedence_symbol_name = options[:prec]
|
17
|
+
production = Production.new(@symbol, expansion_symbols, production_name.to_s, @grammar.symbol_for_name(precedence_symbol_name).precedence)
|
18
|
+
else
|
19
|
+
production = Production.new(@symbol, expansion_symbols, production_name.to_s)
|
20
|
+
end
|
17
21
|
@symbol.nullable = true if expansion_symbols.empty?
|
18
22
|
@grammar.productions_by_symbol[production.symbol] << production
|
23
|
+
raise "Duplicate production named #{production.name}" if @grammar.productions_by_name[production.name]
|
19
24
|
@grammar.productions_by_name[production.name] = production
|
20
25
|
end
|
21
26
|
end
|
22
27
|
|
28
|
+
class PrecedenceBuilder
|
29
|
+
def initialize(grammar)
|
30
|
+
@grammar = grammar
|
31
|
+
@precedence_level = 0
|
32
|
+
end
|
33
|
+
def method_missing(associativity, symbol_names)
|
34
|
+
symbol_names.each do |symbol_name|
|
35
|
+
symbol = @grammar.symbols[symbol_name]
|
36
|
+
symbol.precedence = Precedence.new(@precedence_level, associativity)
|
37
|
+
end
|
38
|
+
@precedence_level += 1
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
23
42
|
class Grammar
|
24
43
|
|
25
44
|
def self.inherited(grammar)
|
@@ -83,6 +102,10 @@ module Dhaka
|
|
83
102
|
return channels, result
|
84
103
|
end
|
85
104
|
|
105
|
+
def self.precedences &blk
|
106
|
+
PrecedenceBuilder.new(self).instance_eval(&blk)
|
107
|
+
end
|
108
|
+
|
86
109
|
def self.first(given_symbol)
|
87
110
|
cached_result = self.__first_cache[given_symbol]
|
88
111
|
return cached_result if cached_result
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Dhaka
|
2
|
+
class Precedence
|
3
|
+
include Comparable
|
4
|
+
attr_reader :precedence_level, :associativity
|
5
|
+
def initialize(precedence_level, associativity)
|
6
|
+
@precedence_level = precedence_level
|
7
|
+
@associativity = associativity
|
8
|
+
end
|
9
|
+
|
10
|
+
def <=> other
|
11
|
+
self.precedence_level <=> other.precedence_level
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/grammar/production.rb
CHANGED
@@ -1,14 +1,28 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
module Dhaka
|
3
3
|
class Production
|
4
|
-
|
5
|
-
|
4
|
+
|
5
|
+
attr_reader :symbol, :expansion, :name, :precedence
|
6
|
+
|
7
|
+
def initialize(symbol, expansion, name, precedence = nil)
|
6
8
|
@symbol = symbol
|
7
9
|
@expansion = expansion
|
8
10
|
@name = name
|
11
|
+
if precedence
|
12
|
+
@precedence = precedence
|
13
|
+
else
|
14
|
+
@expansion.reverse_each do |symbol|
|
15
|
+
if symbol.terminal
|
16
|
+
@precedence = symbol.precedence
|
17
|
+
break
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
9
21
|
end
|
22
|
+
|
10
23
|
def to_s
|
11
24
|
"#{@name} #{@symbol} ::= #{@expansion.join(' ')}"
|
12
25
|
end
|
26
|
+
|
13
27
|
end
|
14
28
|
end
|
data/lib/parser/parser.rb
CHANGED
@@ -1,11 +1,19 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'set'
|
3
|
+
require 'logger'
|
4
|
+
|
3
5
|
module Dhaka
|
4
6
|
class Parser
|
5
7
|
include ParserMethods
|
6
8
|
attr_reader :grammar, :start_state
|
7
9
|
|
8
|
-
def initialize(grammar)
|
10
|
+
def initialize(grammar, logger = nil)
|
11
|
+
if logger
|
12
|
+
@logger = logger
|
13
|
+
else
|
14
|
+
@logger = Logger.new(STDOUT)
|
15
|
+
@logger.level = Logger::WARN
|
16
|
+
end
|
9
17
|
@transitions = Hash.new {|hash, state| hash[state] = {}}
|
10
18
|
@grammar = grammar
|
11
19
|
@channels = []
|
@@ -14,6 +22,7 @@ module Dhaka
|
|
14
22
|
@channels += channels.to_a
|
15
23
|
new_state = ParserState.new(self, closure)
|
16
24
|
hash[kernel] = new_state
|
25
|
+
@logger.debug("Created #{new_state}.")
|
17
26
|
new_state.transition_items.each do |symbol, items|
|
18
27
|
destination_kernel = ItemSet.new(items.collect{|item| item.next_item})
|
19
28
|
destination_state = hash[destination_kernel]
|
@@ -31,8 +40,11 @@ module Dhaka
|
|
31
40
|
start_items = ItemSet.new(start_productions.collect {|production| Item.new(production, 0)})
|
32
41
|
start_items.each {|start_item| start_item.lookaheadset << @grammar.end_symbol}
|
33
42
|
@start_state = @states[start_items]
|
43
|
+
@logger.debug("Pumping #{@channels.size} channels...")
|
34
44
|
pump_channels
|
45
|
+
@logger.debug("Generating shift actions...")
|
35
46
|
generate_shift_actions
|
47
|
+
@logger.debug("Generating reduce actions...")
|
36
48
|
generate_reduce_actions
|
37
49
|
end
|
38
50
|
|
@@ -80,10 +92,13 @@ module Dhaka
|
|
80
92
|
|
81
93
|
def create_reduction_actions_for_item_and_state item, state
|
82
94
|
item.lookaheadset.each do |lookahead|
|
83
|
-
existing_action = state.actions[lookahead.name]
|
84
95
|
new_action = ReduceAction.new(item.production)
|
85
|
-
if existing_action
|
86
|
-
|
96
|
+
if existing_action = state.actions[lookahead.name]
|
97
|
+
if ReduceAction === existing_action
|
98
|
+
raise ParserReduceReduceConflictError.new(build_conflict_message(state, lookahead, new_action).join("\n"))
|
99
|
+
else
|
100
|
+
resolve_conflict state, lookahead, new_action
|
101
|
+
end
|
87
102
|
else
|
88
103
|
state.actions[lookahead.name] = new_action
|
89
104
|
end
|
@@ -91,25 +106,64 @@ module Dhaka
|
|
91
106
|
end
|
92
107
|
|
93
108
|
|
109
|
+
def resolve_conflict state, lookahead, new_action
|
110
|
+
message = build_conflict_message(state, lookahead, new_action)
|
111
|
+
shift_precedence = lookahead.precedence
|
112
|
+
reduce_precedence = new_action.production.precedence
|
113
|
+
if (shift_precedence && reduce_precedence)
|
114
|
+
if (shift_precedence > reduce_precedence)
|
115
|
+
message << "Resolving with precedence. Choosing shift over reduce."
|
116
|
+
elsif (shift_precedence < reduce_precedence)
|
117
|
+
message << "Resolving with precedence. Choosing reduce over shift."
|
118
|
+
state.actions[lookahead.name] = new_action
|
119
|
+
else
|
120
|
+
case shift_precedence.associativity
|
121
|
+
when :left
|
122
|
+
message << "Resolving with left associativity. Choosing reduce over shift."
|
123
|
+
state.actions[lookahead.name] = new_action
|
124
|
+
when :right
|
125
|
+
message << "Resolving with right associativity. Choosing shift over reduce."
|
126
|
+
when :nonassoc
|
127
|
+
message << "Resolving with non-associativity. Eliminating action."
|
128
|
+
state.actions[lookahead.name] = nil
|
129
|
+
end
|
130
|
+
end
|
131
|
+
else
|
132
|
+
message << "No precedence rule. Choosing shift over reduce."
|
133
|
+
end
|
134
|
+
@logger.warn(message.join("\n"))
|
135
|
+
end
|
136
|
+
|
137
|
+
def build_conflict_message state, lookahead, new_action
|
138
|
+
message = ["Parser Conflict at State:"] + state.items.values.collect{|it| it.to_s}
|
139
|
+
message << "Existing: #{state.actions[lookahead.name]}"
|
140
|
+
message << "New: #{new_action}"
|
141
|
+
message << "Lookahead: #{lookahead}"
|
142
|
+
message
|
143
|
+
end
|
144
|
+
|
94
145
|
def pump_channels
|
95
146
|
while true
|
96
|
-
|
97
|
-
|
147
|
+
unstable_count = 0
|
148
|
+
@channels.each do |channel|
|
149
|
+
if channel.pump
|
150
|
+
unstable_count += 1
|
151
|
+
end
|
98
152
|
end
|
153
|
+
break if unstable_count == 0
|
154
|
+
@logger.debug("#{unstable_count} unstable channels...")
|
99
155
|
end
|
100
156
|
end
|
101
157
|
|
102
158
|
end
|
103
159
|
|
104
160
|
|
105
|
-
class
|
106
|
-
def initialize(
|
107
|
-
@
|
108
|
-
@existing_action = existing_action
|
109
|
-
@new_action = new_action
|
161
|
+
class ParserReduceReduceConflictError < StandardError
|
162
|
+
def initialize(message)
|
163
|
+
@message = message
|
110
164
|
end
|
111
165
|
def to_s
|
112
|
-
|
166
|
+
@message
|
113
167
|
end
|
114
168
|
end
|
115
169
|
|
data/test/all_tests.rb
CHANGED
@@ -8,4 +8,6 @@ require 'compiled_parser_test'
|
|
8
8
|
require 'evaluator_test'
|
9
9
|
require 'arithmetic_tokenizer_test'
|
10
10
|
require 'malformed_grammar_test'
|
11
|
-
require 'brackets_test'
|
11
|
+
require 'brackets_test'
|
12
|
+
require 'arithmetic_precedence_grammar_test'
|
13
|
+
require 'arithmetic_precedence_parser_test'
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require File.dirname(__FILE__)+'/../lib/dhaka'
|
2
|
+
require 'arithmetic_precedence_grammar'
|
3
|
+
|
4
|
+
class ArithmeticPrecedenceEvaluator < Dhaka::Evaluator
|
5
|
+
|
6
|
+
self.grammar = ArithmeticPrecedenceGrammar
|
7
|
+
|
8
|
+
define_evaluation_rules do
|
9
|
+
|
10
|
+
for_subtraction do
|
11
|
+
child_nodes[0] - child_nodes[2]
|
12
|
+
end
|
13
|
+
|
14
|
+
for_addition do
|
15
|
+
child_nodes[0] + child_nodes[2]
|
16
|
+
end
|
17
|
+
|
18
|
+
for_division do
|
19
|
+
child_nodes[0].to_f/child_nodes[2]
|
20
|
+
end
|
21
|
+
|
22
|
+
for_multiplication do
|
23
|
+
child_nodes[0] * child_nodes[2]
|
24
|
+
end
|
25
|
+
|
26
|
+
for_literal do
|
27
|
+
child_nodes[0].token.value
|
28
|
+
end
|
29
|
+
|
30
|
+
for_parenthetized_expression do
|
31
|
+
child_nodes[1]
|
32
|
+
end
|
33
|
+
|
34
|
+
for_negated_expression do
|
35
|
+
-child_nodes[1]
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.dirname(__FILE__)+'/../lib/dhaka'
|
2
|
+
|
3
|
+
class ArithmeticPrecedenceGrammar < Dhaka::Grammar
|
4
|
+
precedences do
|
5
|
+
left ['+', '-']
|
6
|
+
left ['*', '/']
|
7
|
+
end
|
8
|
+
|
9
|
+
for_symbol(Dhaka::START_SYMBOL_NAME) do
|
10
|
+
expression ['E']
|
11
|
+
end
|
12
|
+
|
13
|
+
for_symbol('E') do
|
14
|
+
addition ['E', '+', 'E']
|
15
|
+
subtraction ['E', '-', 'E']
|
16
|
+
multiplication ['E', '*', 'E']
|
17
|
+
division ['E', '/', 'E']
|
18
|
+
literal ['n']
|
19
|
+
parenthetized_expression ['(', 'E', ')']
|
20
|
+
negated_expression ['-', 'E'], :prec => '*'
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require 'arithmetic_precedence_grammar'
|
3
|
+
|
4
|
+
class TestArithmeticPrecedenceGrammar < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@addop = ArithmeticPrecedenceGrammar.symbol_for_name('+')
|
8
|
+
@subop = ArithmeticPrecedenceGrammar.symbol_for_name('-')
|
9
|
+
@mulop = ArithmeticPrecedenceGrammar.symbol_for_name('*')
|
10
|
+
@divop = ArithmeticPrecedenceGrammar.symbol_for_name('/')
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_precedence_levels_and_associativity_of_terminals
|
14
|
+
assert_equal(0, @addop.precedence.precedence_level)
|
15
|
+
assert_equal(0, @subop.precedence.precedence_level)
|
16
|
+
assert_equal(1, @mulop.precedence.precedence_level)
|
17
|
+
assert_equal(1, @divop.precedence.precedence_level)
|
18
|
+
assert_equal(:left, @addop.precedence.associativity)
|
19
|
+
assert_equal(:left, @subop.precedence.associativity)
|
20
|
+
assert_equal(:left, @mulop.precedence.associativity)
|
21
|
+
assert_equal(:left, @divop.precedence.associativity)
|
22
|
+
end
|
23
|
+
def test_precedence_of_production
|
24
|
+
assert_equal(@addop.precedence, ArithmeticPrecedenceGrammar.production_named("addition").precedence)
|
25
|
+
assert_equal(@mulop.precedence, ArithmeticPrecedenceGrammar.production_named("multiplication").precedence)
|
26
|
+
assert_equal(@mulop.precedence, ArithmeticPrecedenceGrammar.production_named("negated_expression").precedence)
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require "arithmetic_precedence_grammar"
|
3
|
+
require "arithmetic_tokenizer"
|
4
|
+
require "arithmetic_precedence_evaluator"
|
5
|
+
|
6
|
+
class TestArithmeticPrecedenceParser < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def test_parses_arithmetic_expressions
|
9
|
+
fake_logger = FakeLogger.new
|
10
|
+
parser = Dhaka::Parser.new(ArithmeticPrecedenceGrammar, fake_logger)
|
11
|
+
assert_equal(20, fake_logger.messages.size)
|
12
|
+
|
13
|
+
syntax_tree = parser.parse(ArithmeticTokenizer.tokenize("5 * -14/(2*7 - 7) + 2")).syntax_tree
|
14
|
+
# File.open('precedence.dot', 'w') {|file| file << syntax_tree.to_dot}
|
15
|
+
# File.open('precedence_parser.dot', 'w') {|file| file << parser.to_dot}
|
16
|
+
assert_equal(-8, ArithmeticPrecedenceEvaluator.new(syntax_tree).result)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class FakeLogger
|
21
|
+
attr_reader :messages
|
22
|
+
def initialize
|
23
|
+
@messages = []
|
24
|
+
end
|
25
|
+
def debug message
|
26
|
+
end
|
27
|
+
def warn(message)
|
28
|
+
@messages << message
|
29
|
+
end
|
30
|
+
end
|
data/test/parser_test.rb
CHANGED
@@ -144,12 +144,7 @@ class ParserTest < Test::Unit::TestCase
|
|
144
144
|
|
145
145
|
def test_with_a_grammar_that_should_generate_an_RR_conflict
|
146
146
|
grammar = RRConflictGrammar
|
147
|
-
assert_raise(Dhaka::
|
148
|
-
end
|
149
|
-
|
150
|
-
def test_with_a_grammar_that_should_generate_an_SR_conflict
|
151
|
-
grammar = SRConflictGrammar
|
152
|
-
assert_raise(Dhaka::ParserConflictError) { Dhaka::Parser.new(grammar) }
|
147
|
+
assert_raise(Dhaka::ParserReduceReduceConflictError) { Dhaka::Parser.new(grammar) }
|
153
148
|
end
|
154
149
|
|
155
150
|
def set_finder(set1, set2)
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
|
|
3
3
|
specification_version: 1
|
4
4
|
name: dhaka
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.0.
|
7
|
-
date: 2006-12-
|
6
|
+
version: 0.0.4
|
7
|
+
date: 2006-12-11 00:00:00 -05:00
|
8
8
|
summary: An LALR1 parser generator written in Ruby
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -34,6 +34,7 @@ files:
|
|
34
34
|
- lib/grammar/closure_hash.rb
|
35
35
|
- lib/grammar/grammar.rb
|
36
36
|
- lib/grammar/grammar_symbol.rb
|
37
|
+
- lib/grammar/precedence.rb
|
37
38
|
- lib/grammar/production.rb
|
38
39
|
- lib/parser/action.rb
|
39
40
|
- lib/parser/channel.rb
|
@@ -52,6 +53,10 @@ files:
|
|
52
53
|
- test/arithmetic_evaluator_test.rb
|
53
54
|
- test/arithmetic_grammar.rb
|
54
55
|
- test/arithmetic_grammar_test.rb
|
56
|
+
- test/arithmetic_precedence_evaluator.rb
|
57
|
+
- test/arithmetic_precedence_grammar.rb
|
58
|
+
- test/arithmetic_precedence_grammar_test.rb
|
59
|
+
- test/arithmetic_precedence_parser_test.rb
|
55
60
|
- test/arithmetic_test_methods.rb
|
56
61
|
- test/arithmetic_tokenizer.rb
|
57
62
|
- test/arithmetic_tokenizer_test.rb
|