aurum 0.1.1 → 0.2.0

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.
Files changed (77) hide show
  1. data/Rakefile +29 -0
  2. data/examples/dangling_else/grammar.rb +23 -0
  3. data/examples/expression/grammar.rb +28 -0
  4. data/examples/smalltalk/grammar.rb +151 -0
  5. data/examples/smalltalk/interpreter.rb +70 -0
  6. data/examples/yacc/grammar.rb +72 -0
  7. data/lib/aurum.rb +1 -9
  8. data/lib/aurum/engine.rb +39 -175
  9. data/lib/aurum/engine/parsing_facility.rb +107 -0
  10. data/lib/aurum/engine/tokenization_facility.rb +86 -0
  11. data/lib/aurum/grammar.rb +52 -219
  12. data/lib/aurum/grammar/automata.rb +194 -0
  13. data/lib/aurum/grammar/builder/augmented_grammar.rb +83 -0
  14. data/lib/aurum/grammar/builder/dot_logger.rb +66 -0
  15. data/lib/aurum/grammar/builder/lexical_table_builder.rb +55 -0
  16. data/lib/aurum/grammar/builder/parsing_table_builder.rb +238 -0
  17. data/lib/aurum/grammar/builder/set_of_items.rb +190 -0
  18. data/lib/aurum/grammar/compiled_tables.rb +20 -0
  19. data/lib/aurum/grammar/dsl/lexical_definition.rb +94 -0
  20. data/lib/aurum/grammar/dsl/syntax_definition.rb +79 -0
  21. data/lib/aurum/grammar/lexical_rules.rb +224 -0
  22. data/lib/aurum/grammar/metalang/grammar.rb +47 -0
  23. data/lib/aurum/grammar/syntax_rules.rb +95 -0
  24. data/spec/builder/dsl_definition/aurum_grammar_spec.rb +33 -0
  25. data/spec/engine/lexer_spec.rb +59 -0
  26. data/spec/engine/parser_spec.rb +90 -0
  27. data/spec/examples/dangling_else_example.rb +30 -0
  28. data/spec/examples/expression_example.rb +48 -0
  29. data/spec/examples/smalltalk_example.rb +50 -0
  30. data/spec/examples/yacc_spec.rb +30 -0
  31. data/spec/grammar/builder/lexical_table/automata_spec.rb +55 -0
  32. data/spec/grammar/builder/lexical_table/builder_spec.rb +78 -0
  33. data/spec/grammar/builder/lexical_table/character_set_spec.rb +100 -0
  34. data/spec/grammar/builder/lexical_table/pattern_spec.rb +11 -0
  35. data/spec/grammar/builder/lexical_table/regular_expression.rb +40 -0
  36. data/spec/grammar/builder/parsing_table/augmented_grammar_spec.rb +36 -0
  37. data/spec/grammar/builder/parsing_table/builder_spec.rb +152 -0
  38. data/spec/grammar/builder/parsing_table/digraph_traverser_spec.rb +42 -0
  39. data/spec/grammar/builder/parsing_table/item_spec.rb +51 -0
  40. data/spec/grammar/builder/parsing_table/sources_spec.rb +66 -0
  41. data/spec/grammar/builder/parsing_table/state_spec.rb +82 -0
  42. data/spec/grammar/dsl/character_classes_builder_spec.rb +50 -0
  43. data/spec/grammar/dsl/lexical_rules_builder_spec.rb +181 -0
  44. data/spec/grammar/dsl/precedence_builder_spec.rb +64 -0
  45. data/spec/grammar/dsl/productions_builder_spec.rb +78 -0
  46. data/spec/grammar/metalang/metalang_spec.rb +0 -0
  47. data/spec/grammar/precedence_spec.rb +42 -0
  48. data/spec/grammar/syntax_rules_spec.rb +31 -0
  49. data/spec/parser_matcher.rb +69 -0
  50. data/spec/pattern_matcher.rb +123 -0
  51. data/spec/spec_helper.rb +133 -0
  52. metadata +70 -36
  53. data/example/expression/expression.rb +0 -35
  54. data/example/expression/lisp.rb +0 -26
  55. data/lib/aurum/lexical_table_generator.rb +0 -429
  56. data/lib/aurum/parsing_table_generator.rb +0 -464
  57. data/test/engine/lexer_test.rb +0 -59
  58. data/test/engine/semantic_attributes_test.rb +0 -15
  59. data/test/grammar_definition/character_class_definition_test.rb +0 -28
  60. data/test/grammar_definition/grammar_definition_test.rb +0 -55
  61. data/test/grammar_definition/lexical_definition_test.rb +0 -56
  62. data/test/grammar_definition/operator_precedence_definition_test.rb +0 -35
  63. data/test/grammar_definition/production_definition_test.rb +0 -60
  64. data/test/lexical_table_generator/automata_test.rb +0 -74
  65. data/test/lexical_table_generator/character_set_test.rb +0 -73
  66. data/test/lexical_table_generator/interval_test.rb +0 -36
  67. data/test/lexical_table_generator/pattern_test.rb +0 -115
  68. data/test/lexical_table_generator/subset_determinizer_test.rb +0 -19
  69. data/test/lexical_table_generator/table_generator_test.rb +0 -126
  70. data/test/parsing_table_generator/augmented_grammar_test.rb +0 -45
  71. data/test/parsing_table_generator/lalr_n_computation_test.rb +0 -92
  72. data/test/parsing_table_generator/lr_0_automata_test.rb +0 -94
  73. data/test/parsing_table_generator/lr_item_test.rb +0 -27
  74. data/test/parsing_table_generator/parsing_table_state_test.rb +0 -39
  75. data/test/parsing_table_generator/precedence_table_test.rb +0 -28
  76. data/test/parsing_table_generator/production_test.rb +0 -9
  77. data/test/test_helper.rb +0 -103
@@ -0,0 +1,64 @@
1
+ helper_dir = File.join(File.dirname(__FILE__), '..', '..')
2
+ $:.unshift(helper_dir) unless $:.include?(helper_dir)
3
+
4
+ require 'spec_helper'
5
+
6
+ describe Aurum::Grammar::DSL::PrecedencesBuilder do
7
+ before :each do
8
+ @syntax_rules = Aurum::Grammar::SyntaxRules.new
9
+ @builder = Aurum::Grammar::DSL::PrecedencesBuilder.new(@syntax_rules)
10
+ end
11
+
12
+ it 'string should be declared as literal non-associative operator' do
13
+ @builder.nonassoc '+'
14
+ precedence = @syntax_rules.operator_precedence('$literal_+')
15
+ precedence.should eql?(Aurum::Grammar.precedence(:non_associative, 0))
16
+ end
17
+
18
+ it 'symbol should be declared as terminal non-associative operator' do
19
+ @builder.nonassoc :_id
20
+ precedence = @syntax_rules.operator_precedence('_id')
21
+ precedence.should eql?(Aurum::Grammar.precedence(:non_associative, 0))
22
+ end
23
+
24
+ it 'string should be declared as literal left-associative operator' do
25
+ @builder.left '+'
26
+ precedence = @syntax_rules.operator_precedence('$literal_+')
27
+ precedence.should eql?(Aurum::Grammar.precedence(:left_associative, 0))
28
+ end
29
+
30
+ it 'symbol should be declared as terminal left-associative operator' do
31
+ @builder.left :_id
32
+ precedence = @syntax_rules.operator_precedence('_id')
33
+ precedence.should eql?(Aurum::Grammar.precedence(:left_associative, 0))
34
+ end
35
+
36
+ it 'string should be declared as literal right-associative operator' do
37
+ @builder.right '+'
38
+ precedence = @syntax_rules.operator_precedence('$literal_+')
39
+ precedence.should eql?(Aurum::Grammar.precedence(:right_associative, 0))
40
+ end
41
+
42
+ it 'symbol should be declared as terminal right-associative operator' do
43
+ @builder.right :_id
44
+ precedence = @syntax_rules.operator_precedence('_id')
45
+ precedence.should eql?(Aurum::Grammar.precedence(:right_associative, 0))
46
+ end
47
+
48
+ it 'operators declared in the same time should have same precedence' do
49
+ @builder.nonassoc '+', '-'
50
+ precedence = @syntax_rules.operator_precedence('$literal_+')
51
+ precedence.should eql?(Aurum::Grammar.precedence(:non_associative, 0))
52
+ precedence = @syntax_rules.operator_precedence('$literal_-')
53
+ precedence.should eql?(Aurum::Grammar.precedence(:non_associative, 0))
54
+ end
55
+
56
+ it 'operators declared earlier should have higher precedence' do
57
+ @builder.nonassoc '+'
58
+ @builder.nonassoc '-'
59
+ precedence = @syntax_rules.operator_precedence('$literal_+')
60
+ precedence.should eql?(Aurum::Grammar.precedence(:non_associative, 0))
61
+ precedence = @syntax_rules.operator_precedence('$literal_-')
62
+ precedence.should eql?(Aurum::Grammar.precedence(:non_associative, -1))
63
+ end
64
+ end
@@ -0,0 +1,78 @@
1
+ helper_dir = File.join(File.dirname(__FILE__), '..', '..')
2
+ $:.unshift(helper_dir) unless $:.include?(helper_dir)
3
+
4
+ require 'spec_helper'
5
+
6
+ describe Aurum::Grammar::DSL::ProductionsBuilder do
7
+ before :each do
8
+ @syntax_rules, @actions = Aurum::Grammar::SyntaxRules.new, {}
9
+ @builder = Aurum::Grammar::DSL::ProductionsBuilder.new(@syntax_rules, @actions)
10
+ end
11
+
12
+ it 'should add terminal to terminal list' do
13
+ @builder.instance_eval do
14
+ nonterminal _terminal
15
+ end
16
+ terminals = @syntax_rules.instance_eval {@terminals}
17
+ terminals.size.should == 1
18
+ terminals['_terminal'].should == Aurum::Grammar.terminal('_terminal')
19
+ end
20
+
21
+ it 'should add literal to terminal and literal list' do
22
+ @builder.instance_eval do
23
+ nonterminal '+'
24
+ end
25
+ terminals, literals = @syntax_rules.instance_eval {[@terminals, @literals]}
26
+ terminals.size.should == 1
27
+ terminals['$literal_+'].should == Aurum::Grammar.terminal('$literal_+')
28
+ literals.should == ['+'].to_set
29
+ end
30
+
31
+ it 'should add production to nonterminal' do
32
+ @builder.instance_eval do
33
+ nonterminal _terminal
34
+ end
35
+ productions = @syntax_rules.productions(Aurum::Grammar.nonterminal('nonterminal'))
36
+ productions.map {|prod| prod.inspect}.join(' , ').should == 'nonterminal -> _terminal'
37
+ end
38
+
39
+ it 'should add empty production to nonterminal' do
40
+ @builder.instance_eval do
41
+ nonterminal _
42
+ end
43
+ productions = @syntax_rules.productions(Aurum::Grammar.nonterminal('nonterminal'))
44
+ productions.map {|prod| prod.inspect}.join(' , ').should == 'nonterminal -> '
45
+ end
46
+
47
+ it 'should use object_id as anonymouse production name' do
48
+ @builder.instance_eval do
49
+ nonterminal _terminal
50
+ end
51
+ production = @syntax_rules.productions(Aurum::Grammar.nonterminal('nonterminal')).to_a[0]
52
+ production.name.should == "$production_#{production.object_id}"
53
+ end
54
+
55
+ it 'should use last symbol as production name' do
56
+ @builder.instance_eval do
57
+ nonterminal _terminal, :production_name
58
+ end
59
+ production = @syntax_rules.productions(Aurum::Grammar.nonterminal('nonterminal')).to_a[0]
60
+ production.name.should == 'production_name'
61
+ end
62
+
63
+ it 'should add action to actions table for anonymouse production' do
64
+ @builder.instance_eval do
65
+ nonterminal _terminal { 'action' }
66
+ end
67
+ production = @syntax_rules.productions(Aurum::Grammar.nonterminal('nonterminal')).to_a[0]
68
+ @actions[production.name].should_not be_nil
69
+ end
70
+
71
+ it 'should add action to actions table for named production' do
72
+ @builder.instance_eval do
73
+ nonterminal _terminal, :name do 'action' end
74
+ end
75
+ production = @syntax_rules.productions(Aurum::Grammar.nonterminal('nonterminal')).to_a[0]
76
+ @actions[production.name].should_not be_nil
77
+ end
78
+ end
File without changes
@@ -0,0 +1,42 @@
1
+ helper_dir = File.join(File.dirname(__FILE__), '..')
2
+ $:.unshift(helper_dir) unless $:.include?(helper_dir)
3
+
4
+ require 'spec_helper'
5
+
6
+ describe Aurum::Grammar::SyntaxRules::Precedence do
7
+ it 'precedence2 should greater than precedence2 if operator1 has higher precedence' do
8
+ precedence1 = Aurum::Grammar::SyntaxRules::Precedence.new(:left_associative, 0)
9
+ precedence2 = Aurum::Grammar::SyntaxRules::Precedence.new(:left_associative, -1)
10
+ precedence1.should > precedence2
11
+ end
12
+
13
+ it 'precedence2 should less than precedence1 if precedence1 has higher precedence' do
14
+ precedence1 = Aurum::Grammar::SyntaxRules::Precedence.new(:left_associative, 0)
15
+ precedence2 = Aurum::Grammar::SyntaxRules::Precedence.new(:left_associative, -1)
16
+ precedence2.should < precedence1
17
+ end
18
+
19
+ it 'precedence1 should greater then precedence2 if operators are left-associative and same precedence' do
20
+ precedence1 = Aurum::Grammar::SyntaxRules::Precedence.new(:left_associative, 0)
21
+ precedence2 = Aurum::Grammar::SyntaxRules::Precedence.new(:left_associative, 0)
22
+ precedence2.should > precedence1
23
+ end
24
+
25
+ it 'precedence2 should greater then precedence1 if operators are left-associative and same precedence' do
26
+ precedence1 = Aurum::Grammar::SyntaxRules::Precedence.new(:left_associative, 0)
27
+ precedence2 = Aurum::Grammar::SyntaxRules::Precedence.new(:left_associative, 0)
28
+ precedence1.should > precedence2
29
+ end
30
+
31
+ it 'precedence1 should less then precedence2 if operators are left-associative and same precedence' do
32
+ precedence1 = Aurum::Grammar::SyntaxRules::Precedence.new(:right_associative, 0)
33
+ precedence2 = Aurum::Grammar::SyntaxRules::Precedence.new(:right_associative, 0)
34
+ precedence1.should < precedence2
35
+ end
36
+
37
+ it 'precedence2 should less then precedence1 if operators are left-associative and same precedence' do
38
+ precedence1 = Aurum::Grammar::SyntaxRules::Precedence.new(:right_associative, 0)
39
+ precedence2 = Aurum::Grammar::SyntaxRules::Precedence.new(:right_associative, 0)
40
+ precedence2.should < precedence1
41
+ end
42
+ end
@@ -0,0 +1,31 @@
1
+ helper_dir = File.join(File.dirname(__FILE__), '..')
2
+ $:.unshift(helper_dir) unless $:.include?(helper_dir)
3
+
4
+ require 'spec_helper'
5
+
6
+ describe Aurum::Grammar::SyntaxRules do
7
+ before :all do
8
+ @syntax_rules = Aurum::Grammar::SyntaxRules.new
9
+ @E, @T, @plus = Aurum::Grammar.nonterminal('E'), Aurum::Grammar.nonterminal('T'), Aurum::Grammar.terminal('$literal_+')
10
+ @syntax_rules.add_syntax_rule Aurum::Grammar.production(@E, [@E, @plus, @E])
11
+ @syntax_rules.add_syntax_rule Aurum::Grammar.production(@E, [@T, @plus, @T])
12
+ end
13
+
14
+ it 'should add productions to nonterminal' do
15
+ productions = @syntax_rules.productions(@E).map {|production| production.inspect}.to_set
16
+ productions.should == ['E -> T + T', 'E -> E + E'].to_set
17
+ end
18
+
19
+ it 'should not add duplicated productions' do
20
+ @syntax_rules.add_syntax_rule Aurum::Grammar.production(@E, [@T, @plus, @T])
21
+ productions = @syntax_rules.productions(@E).map {|production| production.inspect}.to_set
22
+ productions.size.should == 2
23
+ end
24
+
25
+ it 'should assign precedence to operator symbol' do
26
+ precedence = Aurum::Grammar.precedence(:left_associative, 1)
27
+ @syntax_rules.add_operator_precedence('$literal_+', precedence)
28
+ @syntax_rules.assign_operator_precedence_to_symbols
29
+ @syntax_rules.instance_eval {@terminals['$literal_+'].precedence}.should == precedence
30
+ end
31
+ end
@@ -0,0 +1,69 @@
1
+ module ParserMatcher
2
+ def token(terminal, value = terminal)
3
+ Aurum::Engine::Token.new(terminal.to_s, value)
4
+ end
5
+
6
+ def literal(terminal, value = terminal)
7
+ Aurum::Engine::Token.new("$literal_#{terminal}", value)
8
+ end
9
+
10
+ def be_parsed_as(nonterminal, value=nil)
11
+ parser_creator = Aurum::Parser.new(@grammar, nonterminal)
12
+ BeParsedAs.new(parser_creator.new, nonterminal, value)
13
+ end
14
+
15
+ class BeParsedAs
16
+ def initialize parser, nonterminal, value
17
+ @parser, @nonterminal, @value = parser, nonterminal, value
18
+ class << @parser
19
+ def error_recovery
20
+ raise 'error_recover'
21
+ end
22
+ end
23
+ end
24
+
25
+ def matches?(source)
26
+ @source = source
27
+ (result = @parser.parse(Lexer.new(source))) rescue return false
28
+ return true unless @value
29
+ @value.all? {|attr, value| result.__send__(attr) == value}
30
+ end
31
+
32
+ def failure_message
33
+ "[#{@source.join(', ')}] can't be parsed as #{@nonterminal}"
34
+ end
35
+
36
+ def negative_failure_message
37
+ "[#{@source.join(', ')}] can be parsed as #{@nonterminal}"
38
+ end
39
+
40
+ def description
41
+ "be parsed as #{@nonterminal} if [#{@source.join(', ')}] given"
42
+ end
43
+ end
44
+
45
+ class Lexer
46
+ def initialize source
47
+ @source = source.map do |token|
48
+ case token
49
+ when String : Aurum::Engine::Token.new("$literal_#{token}", token)
50
+ when Symbol : Aurum::Engine::Token.new(token.to_s, token)
51
+ when Aurum::Engine::Token : token
52
+ end
53
+ end
54
+ end
55
+
56
+ def next_symbol
57
+ symbol = @source.shift()
58
+ symbol ? symbol : Aurum::Engine::Token.new('$eof', '')
59
+ end
60
+
61
+ def pushback symbol
62
+ @source.unshift(symbol)
63
+ end
64
+
65
+ def inspect
66
+ @source.inspect
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,123 @@
1
+ module PatternMatcher
2
+ class BeMatchedBy
3
+ def initialize pattern_string, pattern
4
+ @pattern_string, @pattern = pattern_string, pattern
5
+ end
6
+
7
+ def matches?(lexeme)
8
+ @lexeme = lexeme
9
+ states = closure(@pattern.automata.table, [0])
10
+ lexeme.each_byte {|char| states = move(@pattern.automata.table, states, char)}
11
+ states.include?(@pattern.accept)
12
+ end
13
+
14
+ def failure_message
15
+ "'#@lexeme' is not matched by /#@pattern_string/"
16
+ end
17
+
18
+ def negative_failure_message
19
+ "'#@lexeme' is matched by /#@pattern_string/"
20
+ end
21
+
22
+ def description
23
+ "match '#@lexeme' by /#@pattern_string/"
24
+ end
25
+
26
+ private
27
+ def move automata, states, char
28
+ result = []
29
+ states.each {|state| automata[state].each {|tran| result.concat(closure(automata, [tran.destination])) if tran.character_set.include?(char)} }
30
+ result.uniq
31
+ end
32
+
33
+ def closure automata, states
34
+ closure, unvisited = Set.new(states.dup), states.dup
35
+ while !unvisited.empty?
36
+ automata[unvisited.pop].each do |tran|
37
+ [closure, unvisited].each {|x| x << tran.destination} if tran.character_set == Aurum::Grammar::LexicalRules::Epsilon && !closure.include?(tran.destination)
38
+ end
39
+ end
40
+ closure.to_a
41
+ end
42
+ end
43
+ def be_matched_by pattern_string, pattern
44
+ BeMatchedBy.new(pattern_string, pattern)
45
+ end
46
+ end
47
+
48
+ module DeterminizedPatternMatcher
49
+ class BeMatchedBy
50
+ def initialize pattern_string, pattern
51
+ @pattern_string, = pattern_string
52
+ @automata, @accepts = Aurum::Grammar::LexicalRules::SubsetDeterminizer.new(pattern.automata, [pattern.accept]).determinize
53
+ end
54
+
55
+ def matches?(lexeme)
56
+ @lexeme = lexeme
57
+ state = 0
58
+ lexeme.each_byte {|char| state = move(state, char)} rescue return false
59
+ @accepts.include?(state)
60
+ end
61
+
62
+ def failure_message
63
+ "'#@lexeme' is not matched by /#@pattern_string/"
64
+ end
65
+
66
+ def negative_failure_message
67
+ "'#@lexeme' is matched by /#@pattern_string/"
68
+ end
69
+
70
+ def description
71
+ "match '#@lexeme' by /#@pattern_string/"
72
+ end
73
+
74
+ private
75
+ def move state, char
76
+ @automata.table[state].each {|tran| return tran.destination if tran.character_set.include?(char)}
77
+ raise 'not matched'
78
+ end
79
+ end
80
+ def be_matched_by pattern_string, pattern
81
+ BeMatchedBy.new(pattern_string, pattern)
82
+ end
83
+ end
84
+
85
+ module MinimizedPatternMatcher
86
+ class BeMatchedBy
87
+ def initialize pattern_string, pattern
88
+ @pattern_string, = pattern_string
89
+ automata, accepts = Aurum::Grammar::LexicalRules::SubsetDeterminizer.new(pattern.automata, [pattern.accept]).determinize
90
+ accept_actions = {}
91
+ accepts.keys.each {|state| accept_actions[state] = 'action'}
92
+ @automata, @accepts = Aurum::Grammar::LexicalRules::HopcroftMinimizer.new(automata, accept_actions).minimize
93
+ end
94
+
95
+ def matches?(lexeme)
96
+ @lexeme = lexeme
97
+ state = 0
98
+ lexeme.each_byte {|char| state = move(state, char)} rescue return false
99
+ @accepts.include?(state)
100
+ end
101
+
102
+ def failure_message
103
+ "'#@lexeme' is not matched by /#@pattern_string/"
104
+ end
105
+
106
+ def negative_failure_message
107
+ "'#@lexeme' is matched by /#@pattern_string/"
108
+ end
109
+
110
+ def description
111
+ "match '#@lexeme' by /#@pattern_string/"
112
+ end
113
+
114
+ private
115
+ def move state, char
116
+ @automata.table[state].each {|tran| return tran.destination if tran.character_set.include?(char)}
117
+ raise 'not matched'
118
+ end
119
+ end
120
+ def be_matched_by pattern_string, pattern
121
+ BeMatchedBy.new(pattern_string, pattern)
122
+ end
123
+ end
@@ -0,0 +1,133 @@
1
+ lib_dir = File.join(File.dirname(__FILE__), '..', 'lib')
2
+ examples_dir = File.join(File.dirname(__FILE__), '..', 'examples')
3
+ $:.unshift(lib_dir) unless $:.include?(lib_dir)
4
+ $:.unshift(examples_dir) unless $:.include?(examples_dir)
5
+
6
+ require 'delegate'
7
+ require 'aurum/grammar'
8
+ require 'aurum/engine'
9
+
10
+ require File.join(File.dirname(__FILE__), 'pattern_matcher')
11
+ require File.join(File.dirname(__FILE__), 'parser_matcher')
12
+
13
+ class SimpleLR0Grammar < Aurum::Grammar
14
+ syntax_rules do
15
+ expression term, '+', term
16
+ term _id
17
+ end
18
+ end
19
+
20
+ class Grammar419InDragonBook < Aurum::Grammar
21
+ syntax_rules do
22
+ expression expression, '+', term
23
+ expression term
24
+ term term, '*', factor
25
+ term factor
26
+ factor '(', expression, ')'
27
+ factor _id
28
+ end
29
+ end
30
+
31
+ class ExpressionGrammar < Aurum::Grammar
32
+ syntax_rules do
33
+ expression expression, '+', expression
34
+ expression expression, '*', expression
35
+ expression '(', expression, ')'
36
+ expression _id
37
+ end
38
+ end
39
+
40
+ class ExpressionGrammarWithOperatorPrecedence < Aurum::Grammar
41
+ precedences do
42
+ left '*'
43
+ left '+'
44
+ end
45
+
46
+ productions do
47
+ expression expression, '+', expression
48
+ expression expression, '*', expression
49
+ expression '(', expression, ')'
50
+ expression _id
51
+ end
52
+ end
53
+
54
+ class BnfGrammarInCharlesThesis < Aurum::Grammar
55
+ productions do
56
+ bnf rlist
57
+ rlist rlist, rule
58
+ rlist _
59
+ rule _s, '->', slist
60
+ slist slist, _s
61
+ slist _
62
+ end
63
+ end
64
+
65
+ class Grammar411InDragonBook < Aurum::Grammar
66
+ productions do
67
+ expression term, expression1
68
+ expression1 '+', term, expression1
69
+ expression1 _
70
+ term factor, term1
71
+ term1 '*', factor, term1
72
+ term1 _
73
+ factor '(', expression, ')'
74
+ factor _id
75
+ end
76
+ end
77
+
78
+ class GrammarWithNullableSymbols < Aurum::Grammar
79
+ productions do
80
+ expression term
81
+ expression factor
82
+ term _
83
+ factor _id
84
+ end
85
+ end
86
+
87
+ class LALR4Grammar < Aurum::Grammar
88
+ productions do
89
+ s b, _x, _x, _x, _y, _z
90
+ s c, _x, _x, _x, _x, _z
91
+ s _x, b, _x, _x, _x, _x, _y
92
+ b _w
93
+ c _w
94
+ end
95
+ end
96
+
97
+ class BnfGrammarWithActions < Aurum::Grammar
98
+ productions do
99
+ bnf rlist
100
+ rlist rlist, rule {rlist.s_exp = rlist1.s_exp + [rule.s_exp]}
101
+ rlist _ {rlist.s_exp = []}
102
+ rule _s, '->', slist {rule.s_exp = [:rule, _s.value, slist.s_exp]}
103
+ slist slist, _s {slist.s_exp = slist1.s_exp + [_s.value]}
104
+ slist _ {slist.s_exp = []}
105
+ end
106
+ end
107
+
108
+ class GrammarForLexerTesting < Aurum::Grammar
109
+ tokens do
110
+ _numeric range(?0, ?9).one_or_more
111
+ match 'state_a_begin', :shift_to => :state_a
112
+ match 'state_b_begin', :shift_to => :state_b, :recognize => :_state_b_begin
113
+ match 'state_b_beg', :recognize => :_state_b_beg
114
+ ignore 'ignore'
115
+ within :state_a, :state_b do
116
+ _numeric range(?0, ?9).one_or_more
117
+ end
118
+ end
119
+ end
120
+
121
+ class BNFGrammar < Aurum::Grammar
122
+ productions do
123
+ bnf bnf, rules
124
+ bnf _
125
+ rules rules, '|', symbol_list
126
+ rules rule
127
+ rule _nonterminal, '->', symbol_list
128
+ symbol_list symbol_list, _nonterminal
129
+ symbol_list _
130
+ end
131
+ end
132
+
133
+ $pattern = Aurum::Grammar::LexicalRules::Pattern