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.
- data/Rakefile +29 -0
- data/examples/dangling_else/grammar.rb +23 -0
- data/examples/expression/grammar.rb +28 -0
- data/examples/smalltalk/grammar.rb +151 -0
- data/examples/smalltalk/interpreter.rb +70 -0
- data/examples/yacc/grammar.rb +72 -0
- data/lib/aurum.rb +1 -9
- data/lib/aurum/engine.rb +39 -175
- data/lib/aurum/engine/parsing_facility.rb +107 -0
- data/lib/aurum/engine/tokenization_facility.rb +86 -0
- data/lib/aurum/grammar.rb +52 -219
- data/lib/aurum/grammar/automata.rb +194 -0
- data/lib/aurum/grammar/builder/augmented_grammar.rb +83 -0
- data/lib/aurum/grammar/builder/dot_logger.rb +66 -0
- data/lib/aurum/grammar/builder/lexical_table_builder.rb +55 -0
- data/lib/aurum/grammar/builder/parsing_table_builder.rb +238 -0
- data/lib/aurum/grammar/builder/set_of_items.rb +190 -0
- data/lib/aurum/grammar/compiled_tables.rb +20 -0
- data/lib/aurum/grammar/dsl/lexical_definition.rb +94 -0
- data/lib/aurum/grammar/dsl/syntax_definition.rb +79 -0
- data/lib/aurum/grammar/lexical_rules.rb +224 -0
- data/lib/aurum/grammar/metalang/grammar.rb +47 -0
- data/lib/aurum/grammar/syntax_rules.rb +95 -0
- data/spec/builder/dsl_definition/aurum_grammar_spec.rb +33 -0
- data/spec/engine/lexer_spec.rb +59 -0
- data/spec/engine/parser_spec.rb +90 -0
- data/spec/examples/dangling_else_example.rb +30 -0
- data/spec/examples/expression_example.rb +48 -0
- data/spec/examples/smalltalk_example.rb +50 -0
- data/spec/examples/yacc_spec.rb +30 -0
- data/spec/grammar/builder/lexical_table/automata_spec.rb +55 -0
- data/spec/grammar/builder/lexical_table/builder_spec.rb +78 -0
- data/spec/grammar/builder/lexical_table/character_set_spec.rb +100 -0
- data/spec/grammar/builder/lexical_table/pattern_spec.rb +11 -0
- data/spec/grammar/builder/lexical_table/regular_expression.rb +40 -0
- data/spec/grammar/builder/parsing_table/augmented_grammar_spec.rb +36 -0
- data/spec/grammar/builder/parsing_table/builder_spec.rb +152 -0
- data/spec/grammar/builder/parsing_table/digraph_traverser_spec.rb +42 -0
- data/spec/grammar/builder/parsing_table/item_spec.rb +51 -0
- data/spec/grammar/builder/parsing_table/sources_spec.rb +66 -0
- data/spec/grammar/builder/parsing_table/state_spec.rb +82 -0
- data/spec/grammar/dsl/character_classes_builder_spec.rb +50 -0
- data/spec/grammar/dsl/lexical_rules_builder_spec.rb +181 -0
- data/spec/grammar/dsl/precedence_builder_spec.rb +64 -0
- data/spec/grammar/dsl/productions_builder_spec.rb +78 -0
- data/spec/grammar/metalang/metalang_spec.rb +0 -0
- data/spec/grammar/precedence_spec.rb +42 -0
- data/spec/grammar/syntax_rules_spec.rb +31 -0
- data/spec/parser_matcher.rb +69 -0
- data/spec/pattern_matcher.rb +123 -0
- data/spec/spec_helper.rb +133 -0
- metadata +70 -36
- data/example/expression/expression.rb +0 -35
- data/example/expression/lisp.rb +0 -26
- data/lib/aurum/lexical_table_generator.rb +0 -429
- data/lib/aurum/parsing_table_generator.rb +0 -464
- data/test/engine/lexer_test.rb +0 -59
- data/test/engine/semantic_attributes_test.rb +0 -15
- data/test/grammar_definition/character_class_definition_test.rb +0 -28
- data/test/grammar_definition/grammar_definition_test.rb +0 -55
- data/test/grammar_definition/lexical_definition_test.rb +0 -56
- data/test/grammar_definition/operator_precedence_definition_test.rb +0 -35
- data/test/grammar_definition/production_definition_test.rb +0 -60
- data/test/lexical_table_generator/automata_test.rb +0 -74
- data/test/lexical_table_generator/character_set_test.rb +0 -73
- data/test/lexical_table_generator/interval_test.rb +0 -36
- data/test/lexical_table_generator/pattern_test.rb +0 -115
- data/test/lexical_table_generator/subset_determinizer_test.rb +0 -19
- data/test/lexical_table_generator/table_generator_test.rb +0 -126
- data/test/parsing_table_generator/augmented_grammar_test.rb +0 -45
- data/test/parsing_table_generator/lalr_n_computation_test.rb +0 -92
- data/test/parsing_table_generator/lr_0_automata_test.rb +0 -94
- data/test/parsing_table_generator/lr_item_test.rb +0 -27
- data/test/parsing_table_generator/parsing_table_state_test.rb +0 -39
- data/test/parsing_table_generator/precedence_table_test.rb +0 -28
- data/test/parsing_table_generator/production_test.rb +0 -9
- data/test/test_helper.rb +0 -103
@@ -0,0 +1,30 @@
|
|
1
|
+
helper_dir = File.join(File.dirname(__FILE__), '..')
|
2
|
+
$:.unshift(helper_dir) unless $:.include?(helper_dir)
|
3
|
+
|
4
|
+
require 'spec_helper'
|
5
|
+
require 'yacc/grammar'
|
6
|
+
|
7
|
+
describe 'Yacc Grammar' do
|
8
|
+
before :all do
|
9
|
+
YaccLexer = Aurum::Lexer.new(Aurum::Examples::YaccGrammar)
|
10
|
+
#YaccParser = Aurum::Parser.new(Aurum::Examples::YaccGrammar, :grammar)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should ' do
|
14
|
+
lines = File.open('ruby.y').readlines
|
15
|
+
content = lines.join("\n")
|
16
|
+
scanner = scanner(content)
|
17
|
+
while (a = scanner.next_symbol)
|
18
|
+
p a
|
19
|
+
break if a.terminal == '$unknown' || a.terminal == '$eof'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def scanner source
|
24
|
+
YaccLexer.new(source)
|
25
|
+
end
|
26
|
+
|
27
|
+
def parse source
|
28
|
+
YaccParser.new.parse(YaccLexer.new(source)).s_exp
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
helper_dir = File.join(File.dirname(__FILE__), '..', '..', '..')
|
2
|
+
$:.unshift(helper_dir) unless $:.include?(helper_dir)
|
3
|
+
|
4
|
+
require 'spec_helper'
|
5
|
+
|
6
|
+
require File.dirname(__FILE__) + '/regular_expression'
|
7
|
+
|
8
|
+
describe Aurum::Grammar::LexicalRules::Automata, ' alphabet' do
|
9
|
+
before :each do
|
10
|
+
@automata = Aurum::Grammar::LexicalRules::Automata.new(4)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should return ac and mq' do
|
14
|
+
@automata.connect(0, interval(?a, ?c), 1)
|
15
|
+
@automata.connect(2, interval(?m, ?q), 3)
|
16
|
+
result = []
|
17
|
+
@automata.alphabet([0, 2]) {|states, character_set| result << [states, character_set]}
|
18
|
+
result.should == [[[1], interval(?a, ?c)], [[3], interval(?m, ?q)]]
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should return ac df and g' do
|
22
|
+
@automata.connect(0, interval(?a, ?f), 1)
|
23
|
+
@automata.connect(2, interval(?d, ?g), 3)
|
24
|
+
result = []
|
25
|
+
@automata.alphabet([0, 2]) {|states, character_set| result << [states, character_set]}
|
26
|
+
result.should == [[[1], interval(?a, ?c)], [[1, 3], interval(?d, ?f)], [[3], interval(?g, ?g)]]
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should return ac dg and hz' do
|
30
|
+
@automata.connect(0, interval(?a, ?z), 1)
|
31
|
+
@automata.connect(2, interval(?d, ?g), 3)
|
32
|
+
result = []
|
33
|
+
@automata.alphabet([0, 2]) {|states, character_set| result << [states, character_set]}
|
34
|
+
result.should == [[[1], interval(?a, ?c)], [[1, 3], interval(?d, ?g)], [[1], interval(?h, ?z)]]
|
35
|
+
end
|
36
|
+
|
37
|
+
def interval first, last
|
38
|
+
Aurum::Grammar::LexicalRules::CharacterSet::Interval.new(first, last).to_char_set
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe Aurum::Grammar::LexicalRules::Automata, ' subset determinizer' do
|
43
|
+
include DeterminizedPatternMatcher
|
44
|
+
it_should_behave_like 'regular expression'
|
45
|
+
end
|
46
|
+
|
47
|
+
describe Aurum::Grammar::LexicalRules::Automata, ' hopcroft minimizer' do
|
48
|
+
include MinimizedPatternMatcher
|
49
|
+
it_should_behave_like 'regular expression'
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
|
@@ -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
|
+
def scan(lexical_state, lexeme)
|
7
|
+
begin
|
8
|
+
state = - @table.lexical_states.index(lexical_state.to_s) - 1
|
9
|
+
state = (@table.states[0].find {|tran| tran.character_set.include?(state)}).destination
|
10
|
+
lexeme.each_byte {|char| state = (@table.states[state].find {|tran| tran.character_set.include?(char)}).destination}
|
11
|
+
@table.actions[state]
|
12
|
+
rescue
|
13
|
+
raise 'error'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe Aurum::Builder::LexicalTableBuilder, ' no reserved literal' do
|
18
|
+
before :all do
|
19
|
+
@pattern_a, @pattern_b = $pattern.string('pattern_a'), $pattern.string('pattern_b')
|
20
|
+
@action_a, @action_b = Aurum::LexicalTable::Action.new('pattern_a'), Aurum::LexicalTable::Action.new('pattern_b')
|
21
|
+
@lexical_rules = Aurum::Grammar::LexicalRules.new
|
22
|
+
@lexical_rules.add_lexical_action(:initial, @pattern_a, @action_a)
|
23
|
+
@lexical_rules.add_lexical_action(:state_a, @pattern_b, @action_b)
|
24
|
+
end
|
25
|
+
|
26
|
+
before :each do
|
27
|
+
@builder = Aurum::Builder::LexicalTableBuilder.new(@lexical_rules, [], [])
|
28
|
+
@table = @builder.build
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should recognize pattern_a in initial state' do
|
32
|
+
scan(:initial, 'pattern_a').should == @action_a
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should not recognize pattern_b in initial state' do
|
36
|
+
lambda {scan(:initial, 'pattern_b')}.should raise_error
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should recognize pattern_b in state_a' do
|
40
|
+
scan(:state_a, 'pattern_b').should == @action_b
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should not recognize pattern_a in state_a' do
|
44
|
+
lambda {scan(:state_a, 'pattern_a')}.should raise_error
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe Aurum::Builder::LexicalTableBuilder, ' reserved literal in all states' do
|
49
|
+
before :all do
|
50
|
+
@pattern_a, @pattern_b = $pattern.enum('abcdefghijklmnopqrstuvwxyz').one_or_more, $pattern.string('pattern_b')
|
51
|
+
@action_a, @action_b = Aurum::LexicalTable::Action.new('pattern_a'), Aurum::LexicalTable::Action.new('pattern_b')
|
52
|
+
@lexical_rules = Aurum::Grammar::LexicalRules.new
|
53
|
+
@lexical_rules.add_lexical_action(:initial, @pattern_a, @action_a)
|
54
|
+
@lexical_rules.add_lexical_action(:state_a, @pattern_b, @action_b)
|
55
|
+
@action_keyword = Aurum::LexicalTable::Action.new('$literal_keyword')
|
56
|
+
end
|
57
|
+
|
58
|
+
before :each do
|
59
|
+
@builder = Aurum::Builder::LexicalTableBuilder.new(@lexical_rules, ['all'], ['keyword'])
|
60
|
+
@table = @builder.build
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should recognize keyword in initial state' do
|
64
|
+
scan(:initial, 'keyword').should == @action_keyword
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should recognize pattern_a in initial state' do
|
68
|
+
scan(:initial, 'keywore').should == @action_a
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should recognize keyword in state_a' do
|
72
|
+
scan(:state_a, 'keyword').should == @action_keyword
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should recognize pattern_a in initial state' do
|
76
|
+
scan(:state_a, 'pattern_b').should == @action_b
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,100 @@
|
|
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::LexicalRules::CharacterSet::Interval do
|
7
|
+
before :each do
|
8
|
+
@interval = Aurum::Grammar::LexicalRules::CharacterSet::Interval.new ?a, ?c
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should contain character within interval' do
|
12
|
+
(?a..?c).each {|character| @interval.should be_include(character)}
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should not contain character out of interval' do
|
16
|
+
@interval.should_not be_include(?d)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should not merge intervals if they do not have any character in common' do
|
20
|
+
interval = Aurum::Grammar::LexicalRules::CharacterSet::Interval.new ?e, ?f
|
21
|
+
@interval.merge!(interval).should be_nil
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should merge two intervals if they have characters in common' do
|
25
|
+
interval = Aurum::Grammar::LexicalRules::CharacterSet::Interval.new ?b, ?e
|
26
|
+
@interval.merge!(interval).should_not be_nil
|
27
|
+
@interval.should == Aurum::Grammar::LexicalRules::CharacterSet::Interval.new(?a, ?e)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should merge [b-e] and [a-c]' do
|
31
|
+
interval = Aurum::Grammar::LexicalRules::CharacterSet::Interval.new ?b, ?e
|
32
|
+
interval.merge!(@interval).should_not be_nil
|
33
|
+
interval.should == Aurum::Grammar::LexicalRules::CharacterSet::Interval.new(?a, ?e)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should merge two intervals if they are adjacent' do
|
37
|
+
interval = Aurum::Grammar::LexicalRules::CharacterSet::Interval.new ?d, ?e
|
38
|
+
@interval.merge!(interval).should_not be_nil
|
39
|
+
@interval.should == Aurum::Grammar::LexicalRules::CharacterSet::Interval.new(?a, ?e)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should merge [d-e] and [a-c]' do
|
43
|
+
interval = Aurum::Grammar::LexicalRules::CharacterSet::Interval.new ?d, ?e
|
44
|
+
interval.merge!(@interval).should_not be_nil
|
45
|
+
interval.should == Aurum::Grammar::LexicalRules::CharacterSet::Interval.new(?a, ?e)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe Aurum::Grammar::LexicalRules::CharacterSet do
|
50
|
+
it 'should construct character set for string literal' do
|
51
|
+
character_set = Aurum::Grammar::LexicalRules::CharacterSet.enum('age')
|
52
|
+
[?a, ?g, ?e].each {|char | character_set.should be_include(char)}
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should merge intervals as many as possible' do
|
56
|
+
character_set = Aurum::Grammar::LexicalRules::CharacterSet.enum('abc')
|
57
|
+
character_set.intervals.size.should == 1
|
58
|
+
character_set.intervals.should be_include(Aurum::Grammar::LexicalRules::CharacterSet::Interval.new(?a, ?c))
|
59
|
+
end
|
60
|
+
|
61
|
+
it '[aec] + [dbf] should be [a-f]' do
|
62
|
+
char_set_aec, char_set_dbf = Aurum::Grammar::LexicalRules::CharacterSet.enum('aec'), Aurum::Grammar::LexicalRules::CharacterSet.enum('dbf')
|
63
|
+
result = char_set_aec + char_set_dbf
|
64
|
+
result.intervals.size.should == 1
|
65
|
+
result.intervals.should be_include(Aurum::Grammar::LexicalRules::CharacterSet::Interval.new(?a, ?f))
|
66
|
+
end
|
67
|
+
|
68
|
+
it '[a-d] - [bc] should be [a] and [d]' do
|
69
|
+
char_set_ad, char_set_bc = Aurum::Grammar::LexicalRules::CharacterSet.enum('abcd'), Aurum::Grammar::LexicalRules::CharacterSet.enum('bc')
|
70
|
+
result = char_set_ad - char_set_bc
|
71
|
+
result.intervals.size.should == 2
|
72
|
+
result.intervals.should be_include(Aurum::Grammar::LexicalRules::CharacterSet::Interval.new(?a))
|
73
|
+
result.intervals.should be_include(Aurum::Grammar::LexicalRules::CharacterSet::Interval.new(?d))
|
74
|
+
end
|
75
|
+
|
76
|
+
it '[a-d] - [e-f] should be [a-d]' do
|
77
|
+
char_set_ad, char_set_ef = Aurum::Grammar::LexicalRules::CharacterSet.enum('abcd'), Aurum::Grammar::LexicalRules::CharacterSet.enum('ef')
|
78
|
+
result = char_set_ad - char_set_ef
|
79
|
+
result.intervals.size.should == 1
|
80
|
+
result.intervals.should be_include(Aurum::Grammar::LexicalRules::CharacterSet::Interval.new(?a, ?d))
|
81
|
+
end
|
82
|
+
|
83
|
+
it '[a-d] - [a-d] should be []' do
|
84
|
+
char_set_ad = Aurum::Grammar::LexicalRules::CharacterSet.enum('abcd')
|
85
|
+
result = char_set_ad - char_set_ad
|
86
|
+
result.intervals.size.should == 0
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe Aurum::Grammar::LexicalRules::Point do
|
91
|
+
before :each do
|
92
|
+
@point = Aurum::Grammar::LexicalRules::Point.new(?a, true, 1)
|
93
|
+
end
|
94
|
+
|
95
|
+
it {@point.should == @point}
|
96
|
+
it {@point.should < Aurum::Grammar::LexicalRules::Point.new(?b, true, 1)}
|
97
|
+
it {@point.should > Aurum::Grammar::LexicalRules::Point.new(?A, true, 1)}
|
98
|
+
it {@point.should < Aurum::Grammar::LexicalRules::Point.new(?a, false, 1)}
|
99
|
+
it {Aurum::Grammar::LexicalRules::Point.new(?a, false, 1).should > @point}
|
100
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
helper_dir = File.join(File.dirname(__FILE__), '..', '..', '..')
|
2
|
+
$:.unshift(helper_dir) unless $:.include?(helper_dir)
|
3
|
+
|
4
|
+
require 'spec_helper'
|
5
|
+
|
6
|
+
require File.dirname(__FILE__) + '/regular_expression'
|
7
|
+
|
8
|
+
describe Aurum::Grammar::LexicalRules::Pattern do
|
9
|
+
include PatternMatcher
|
10
|
+
it_should_behave_like 'regular expression'
|
11
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
describe 'regular expression', :shared => true do
|
2
|
+
it {'string'.should be_matched_by('string', $pattern.string('string'))}
|
3
|
+
it {'string'.should_not be_matched_by('other_string', $pattern.string('other_string'))}
|
4
|
+
it {'a'.should be_matched_by('a|b|c', $pattern.enum('abc'))}
|
5
|
+
it {'b'.should be_matched_by('a|b|c', $pattern.enum('abc'))}
|
6
|
+
it {'c'.should be_matched_by('a|b|c', $pattern.enum('abc'))}
|
7
|
+
it {'d'.should_not be_matched_by('a|b|c', $pattern.enum('abc'))}
|
8
|
+
it {''.should be_matched_by('(abc)*', $pattern.string('abc').zero_or_more)}
|
9
|
+
it {'abc'.should be_matched_by('(abc)*', $pattern.string('abc').zero_or_more)}
|
10
|
+
it {'abcabcabcabc'.should be_matched_by('(abc)*', $pattern.string('abc').zero_or_more)}
|
11
|
+
it {''.should_not be_matched_by('(abc)+', $pattern.string('abc').one_or_more)}
|
12
|
+
it {'abc'.should be_matched_by('(abc)+', $pattern.string('abc').one_or_more)}
|
13
|
+
it {'abcabcabcabc'.should be_matched_by('(abc)+', $pattern.string('abc').one_or_more)}
|
14
|
+
it {''.should be_matched_by('(abc)+', $pattern.string('abc').zero_or_one)}
|
15
|
+
it {'abc'.should be_matched_by('(abc)+', $pattern.string('abc').zero_or_one)}
|
16
|
+
it {'abcabc'.should_not be_matched_by('(abc)+', $pattern.string('abc').zero_or_one)}
|
17
|
+
it {'abcdef'.should be_matched_by('(abc)(def)', $pattern.concat([$pattern.string('abc'), $pattern.string('def')]))}
|
18
|
+
it {'abcdeg'.should_not be_matched_by('(abc)(def)', $pattern.concat([$pattern.string('abc'), $pattern.string('def')]))}
|
19
|
+
it {'abcabc'.should be_matched_by('(abc){2}', $pattern.string('abc')[2])}
|
20
|
+
it {'abc'.should_not be_matched_by('(abc){2}', $pattern.string('abc')[2])}
|
21
|
+
it {'abcabcabc'.should_not be_matched_by('(abc){2}', $pattern.string('abc')[2])}
|
22
|
+
it {'abcabc'.should be_matched_by('(abc){2,4}', $pattern.string('abc')[2, 4])}
|
23
|
+
it {'abcabcabc'.should be_matched_by('(abc){2,4}', $pattern.string('abc')[2, 4])}
|
24
|
+
it {'abcabcabcabc'.should be_matched_by('(abc){2,4}', $pattern.string('abc')[2, 4])}
|
25
|
+
it {'abc'.should_not be_matched_by('(abc){2,4}', $pattern.string('abc')[2, 4])}
|
26
|
+
it {'abcabcabcabcabc'.should_not be_matched_by('(abc){2,4}', $pattern.string('abc')[2, 4])}
|
27
|
+
it {'abc'.should be_matched_by('(abc)|(def)', $pattern.string('abc') | $pattern.string('def'))}
|
28
|
+
it {'def'.should be_matched_by('(abc)|(def)', $pattern.string('abc') | $pattern.string('def'))}
|
29
|
+
it {'deg'.should_not be_matched_by('(abc)|(def)', $pattern.string('abc') | $pattern.string('def'))}
|
30
|
+
it {'abc'.should_not be_matched_by('!abc', $pattern.string('abc').not)}
|
31
|
+
it {'ade'.should be_matched_by('!abc', $pattern.string('abc').not)}
|
32
|
+
it {'a'.should be_matched_by('!abc', $pattern.string('abc').not)}
|
33
|
+
it {'abcdefhijk'.should be_matched_by('!abc', $pattern.string('abc').not)}
|
34
|
+
it {''.should be_matched_by('!abc', $pattern.string('abc').not)}
|
35
|
+
it {'abcdef */'.should be_matched_by('~*/', ~ $pattern.string('*/'))}
|
36
|
+
it {'/* abcdef */'.should be_matched_by('/*~*/', $pattern.concat([$pattern.string('/*'), ~ $pattern.string('*/')]))}
|
37
|
+
it {'abcdef */ /'.should_not be_matched_by('~*/', ~ $pattern.string('*/'))}
|
38
|
+
it {'abcdef'.should_not be_matched_by('~*/', ~ $pattern.string('*/'))}
|
39
|
+
it {'abcdef *'.should_not be_matched_by('~*/', ~ $pattern.string('*/'))}
|
40
|
+
end
|
@@ -0,0 +1,36 @@
|
|
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::Builder::AugmentedGrammar do
|
7
|
+
before :all do
|
8
|
+
@syntax_rules = Aurum::Grammar::SyntaxRules.new
|
9
|
+
@E, @T = Aurum::Grammar.nonterminal('E'), Aurum::Grammar.nonterminal('T')
|
10
|
+
@F, @id = Aurum::Grammar.nonterminal('F'), Aurum::Grammar.terminal('id')
|
11
|
+
@syntax_rules.add_syntax_rule Aurum::Grammar.production(@E, [@T])
|
12
|
+
@syntax_rules.add_syntax_rule Aurum::Grammar.production(@E, [@F])
|
13
|
+
@syntax_rules.add_syntax_rule Aurum::Grammar.production(@T, [])
|
14
|
+
@syntax_rules.add_syntax_rule Aurum::Grammar.production(@F, [@id])
|
15
|
+
@augmented_grammar = Aurum::Builder::AugmentedGrammar.new(@syntax_rules, @E)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should compute all nullable symbols' do
|
19
|
+
@augmented_grammar.compute_nullables
|
20
|
+
@augmented_grammar.should be_nullable(@E)
|
21
|
+
@augmented_grammar.should be_nullable(@T)
|
22
|
+
@augmented_grammar.should_not be_nullable(@F)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'first set of terminal should be itself' do
|
26
|
+
@augmented_grammar.compute_first_sets
|
27
|
+
@augmented_grammar.first_set(@id).should == [@id].to_set
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'first set of symbols should be included to nonterminal' do
|
31
|
+
@augmented_grammar.compute_first_sets
|
32
|
+
@augmented_grammar.first_set(@E).should == [@id].to_set
|
33
|
+
@augmented_grammar.first_set(@F).should == [@id].to_set
|
34
|
+
@augmented_grammar.first_set(@T).should == [].to_set
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
helper_dir = File.join(File.dirname(__FILE__), '..', '..', '..')
|
2
|
+
$:.unshift(helper_dir) unless $:.include?(helper_dir)
|
3
|
+
|
4
|
+
require 'spec_helper'
|
5
|
+
|
6
|
+
describe 'LR(0)', :shared => true do
|
7
|
+
it 'should not have any inconsistent state' do
|
8
|
+
@builder.instance_eval {@inconsistent_states}.should be_empty
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'lookahead level should be 0' do
|
12
|
+
@parsing_table.lookahead.should == 0
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'LALR(1)', :shared => true do
|
17
|
+
it 'should have inconsistent states' do
|
18
|
+
@builder.instance_eval {@inconsistent_states}.should_not be_empty
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should not have any conflict state' do
|
22
|
+
@builder.instance_eval {@conflict_states}.should be_empty
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'lookahead level should be 1' do
|
26
|
+
@parsing_table.lookahead.should == 1
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'LALR(n)', :shared => true do
|
31
|
+
it 'should have inconsistent states' do
|
32
|
+
@builder.instance_eval {@inconsistent_states}.should_not be_empty
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should have conflict states in LALR(1) automata' do
|
36
|
+
@builder.instance_eval {@conflict_states}.should_not be_empty
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should not have any conflict state in LALR(n) automata' do
|
40
|
+
@builder.instance_eval {@states}.all? {|state| !state.conflict?}.should be_true
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should have lookahead states' do
|
44
|
+
@builder.instance_eval {@states}.any? {|state| state.empty?}.should be_true
|
45
|
+
end
|
46
|
+
|
47
|
+
it "lookahead level should be n" do
|
48
|
+
@parsing_table.lookahead.should == @lookahead_level
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe Aurum::Builder::ParsingTableBuilder, ' LR(0) : Simple LR(0) Grammar' do
|
53
|
+
before :each do
|
54
|
+
syntax_rules = SimpleLR0Grammar.instance_eval {@syntax_rules}
|
55
|
+
augmented_grammar = Aurum::Builder::AugmentedGrammar.new(syntax_rules, Aurum::Grammar.nonterminal('expression'))
|
56
|
+
@builder = Aurum::Builder::ParsingTableBuilder.new(augmented_grammar, nil)
|
57
|
+
@parsing_table = @builder.build
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should use set of items as parsing state' do
|
61
|
+
states = @builder.instance_eval {@states}
|
62
|
+
states.size.should == 3
|
63
|
+
states[0].inspect.should == '[$start -> .expression ]'
|
64
|
+
states[1].inspect.should == '[expression -> term .+ term ]'
|
65
|
+
states[2].inspect.should == '[expression -> term + .term ]'
|
66
|
+
end
|
67
|
+
|
68
|
+
it_should_behave_like 'LR(0)'
|
69
|
+
end
|
70
|
+
|
71
|
+
describe Aurum::Builder::ParsingTableBuilder, ' LALR(1) : Grammar 4.19 in Dragon book' do
|
72
|
+
before :each do
|
73
|
+
syntax_rules = Grammar419InDragonBook.instance_eval {@syntax_rules}
|
74
|
+
augmented_grammar = Aurum::Builder::AugmentedGrammar.new(syntax_rules, Aurum::Grammar.nonterminal('expression'))
|
75
|
+
@builder = Aurum::Builder::ParsingTableBuilder.new(augmented_grammar, nil)
|
76
|
+
@parsing_table = @builder.build
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should compute lookahead symbol for inconsistent states' do
|
80
|
+
@parsing_table.actions[1]['$eof'].should_not be_read_reduce
|
81
|
+
@parsing_table.actions[2]['$eof'].should_not be_read_reduce
|
82
|
+
@parsing_table.actions[2]['$literal_)'].should_not be_read_reduce
|
83
|
+
@parsing_table.actions[2]['$literal_+'].should_not be_read_reduce
|
84
|
+
@parsing_table.actions[6]['$eof'].should_not be_read_reduce
|
85
|
+
@parsing_table.actions[6]['$literal_)'].should_not be_read_reduce
|
86
|
+
@parsing_table.actions[6]['$literal_+'].should_not be_read_reduce
|
87
|
+
end
|
88
|
+
|
89
|
+
it_should_behave_like 'LALR(1)'
|
90
|
+
end
|
91
|
+
|
92
|
+
describe Aurum::Builder::ParsingTableBuilder, ' LALR(1) : Expression Grammar with operator precedences' do
|
93
|
+
before :each do
|
94
|
+
syntax_rules = ExpressionGrammarWithOperatorPrecedence.instance_eval {@syntax_rules}
|
95
|
+
syntax_rules.assign_operator_precedence_to_symbols
|
96
|
+
augmented_grammar = Aurum::Builder::AugmentedGrammar.new(syntax_rules, Aurum::Grammar.nonterminal('expression'))
|
97
|
+
@builder = Aurum::Builder::ParsingTableBuilder.new(augmented_grammar, nil)
|
98
|
+
@parsing_table = @builder.build
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'should be reduce action if equal precedence operator given' do
|
102
|
+
@parsing_table.actions[7]['$literal_+'].should be_reduce
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should be reduce action if ) given' do
|
106
|
+
@parsing_table.actions[7]['$literal_)'].should be_reduce
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'should be reduce action if EOF given' do
|
110
|
+
@parsing_table.actions[7]['$eof'].should be_reduce
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'should be shift action if higer precedence operator given' do
|
114
|
+
@parsing_table.actions[7]['$literal_*'].should be_shift
|
115
|
+
end
|
116
|
+
|
117
|
+
it_should_behave_like 'LALR(1)'
|
118
|
+
end
|
119
|
+
|
120
|
+
describe Aurum::Builder::ParsingTableBuilder, ' LALR(2) : BNF grammar in Philippe Charles\' thesis' do
|
121
|
+
before :each do
|
122
|
+
syntax_rules = BnfGrammarInCharlesThesis.instance_eval {@syntax_rules}
|
123
|
+
augmented_grammar = Aurum::Builder::AugmentedGrammar.new(syntax_rules, Aurum::Grammar.nonterminal('bnf'))
|
124
|
+
@builder = Aurum::Builder::ParsingTableBuilder.new(augmented_grammar, nil)
|
125
|
+
@parsing_table = @builder.build
|
126
|
+
@lookahead_level = 2
|
127
|
+
end
|
128
|
+
|
129
|
+
it_should_behave_like 'LALR(n)'
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
describe Aurum::Builder::ParsingTableBuilder, ' LALR(4) : simple LALR(4) grammar' do
|
134
|
+
before :each do
|
135
|
+
syntax_rules = LALR4Grammar.instance_eval {@syntax_rules}
|
136
|
+
augmented_grammar = Aurum::Builder::AugmentedGrammar.new(syntax_rules, Aurum::Grammar.nonterminal('s'))
|
137
|
+
@builder = Aurum::Builder::ParsingTableBuilder.new(augmented_grammar, nil)
|
138
|
+
@parsing_table = @builder.build
|
139
|
+
@lookahead_level = 4
|
140
|
+
end
|
141
|
+
|
142
|
+
it_should_behave_like 'LALR(n)'
|
143
|
+
end
|
144
|
+
|
145
|
+
describe Aurum::Builder::ParsingTableBuilder, ' not LR(n) : Expression Grammar without operator precedences' do
|
146
|
+
it 'should raise not LR(n) error' do
|
147
|
+
syntax_rules = ExpressionGrammar.instance_eval {@syntax_rules}
|
148
|
+
augmented_grammar = Aurum::Builder::AugmentedGrammar.new(syntax_rules, Aurum::Grammar.nonterminal('expression'))
|
149
|
+
builder = Aurum::Builder::ParsingTableBuilder.new(augmented_grammar, nil)
|
150
|
+
lambda {builder.build}.should raise_error(RuntimeError, 'not LALR(n)')
|
151
|
+
end
|
152
|
+
end
|