rltk 1.1.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/AUTHORS +1 -0
- data/LICENSE +27 -0
- data/README +386 -0
- data/Rakefile +67 -0
- data/lib/rltk/ast.rb +264 -0
- data/lib/rltk/cfg.rb +491 -0
- data/lib/rltk/lexer.rb +298 -0
- data/lib/rltk/lexers/calculator.rb +41 -0
- data/lib/rltk/lexers/ebnf.rb +40 -0
- data/lib/rltk/parser.rb +1354 -0
- data/lib/rltk/parsers/infix_calc.rb +43 -0
- data/lib/rltk/parsers/postfix_calc.rb +34 -0
- data/lib/rltk/parsers/prefix_calc.rb +34 -0
- data/lib/rltk/token.rb +66 -0
- data/test/tc_ast.rb +85 -0
- data/test/tc_cfg.rb +149 -0
- data/test/tc_lexer.rb +217 -0
- data/test/tc_parser.rb +275 -0
- data/test/tc_token.rb +34 -0
- metadata +87 -0
@@ -0,0 +1,43 @@
|
|
1
|
+
# Author: Chris Wailes <chris.wailes@gmail.com>
|
2
|
+
# Project: Ruby Language Toolkit
|
3
|
+
# Date: 2011/03/04
|
4
|
+
# Description: This file contains a parser for a simple infix calculator.
|
5
|
+
|
6
|
+
############
|
7
|
+
# Requires #
|
8
|
+
############
|
9
|
+
|
10
|
+
# Ruby Language Toolkit
|
11
|
+
require 'rltk/parser'
|
12
|
+
|
13
|
+
#######################
|
14
|
+
# Classes and Modules #
|
15
|
+
#######################
|
16
|
+
|
17
|
+
module RLTK # :nodoc:
|
18
|
+
|
19
|
+
# The RLTK::Parsers module contains the parsers that are included as part
|
20
|
+
# of the RLKT project.
|
21
|
+
module Parsers
|
22
|
+
|
23
|
+
# A parser for a simple infix calculator.
|
24
|
+
class InfixCalc < Parser
|
25
|
+
|
26
|
+
left :PLS, :SUB
|
27
|
+
right :MUL, :DIV
|
28
|
+
|
29
|
+
production(:e) do
|
30
|
+
clause('NUM') { |n| n }
|
31
|
+
|
32
|
+
clause('LPAREN e RPAREN') { |_, e, _| e }
|
33
|
+
|
34
|
+
clause('e PLS e') { |e0, _, e1| e0 + e1 }
|
35
|
+
clause('e SUB e') { |e0, _, e1| e0 - e1 }
|
36
|
+
clause('e MUL e') { |e0, _, e1| e0 * e1 }
|
37
|
+
clause('e DIV e') { |e0, _, e1| e0 / e1 }
|
38
|
+
end
|
39
|
+
|
40
|
+
finalize
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Author: Chris Wailes <chris.wailes@gmail.com>
|
2
|
+
# Project: Ruby Language Toolkit
|
3
|
+
# Date: 2011/04/06
|
4
|
+
# Description: This file contains a parser for a simple postfix calculator.
|
5
|
+
|
6
|
+
############
|
7
|
+
# Requires #
|
8
|
+
############
|
9
|
+
|
10
|
+
# Ruby Language Toolkit
|
11
|
+
require 'rltk/parser'
|
12
|
+
|
13
|
+
#######################
|
14
|
+
# Classes and Modules #
|
15
|
+
#######################
|
16
|
+
|
17
|
+
module RLTK # :nodoc:
|
18
|
+
module Parsers # :nodoc:
|
19
|
+
|
20
|
+
# A parser for a simple post-fix calculator.
|
21
|
+
class PostfixCalc < Parser
|
22
|
+
production(:e) do
|
23
|
+
clause('NUM') { |n| n }
|
24
|
+
|
25
|
+
clause('e e PLS') { |e0, e1, _| e0 + e1 }
|
26
|
+
clause('e e SUB') { |e0, e1, _| e0 - e1 }
|
27
|
+
clause('e e MUL') { |e0, e1, _| e0 * e1 }
|
28
|
+
clause('e e DIV') { |e0, e1, _| e0 / e1 }
|
29
|
+
end
|
30
|
+
|
31
|
+
finalize
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Author: Chris Wailes <chris.wailes@gmail.com>
|
2
|
+
# Project: Ruby Language Toolkit
|
3
|
+
# Date: 2011/04/06
|
4
|
+
# Description: This file contains a parser for a simple prefix calculator.
|
5
|
+
|
6
|
+
############
|
7
|
+
# Requires #
|
8
|
+
############
|
9
|
+
|
10
|
+
# Ruby Language Toolkit
|
11
|
+
require 'rltk/parser'
|
12
|
+
|
13
|
+
#######################
|
14
|
+
# Classes and Modules #
|
15
|
+
#######################
|
16
|
+
|
17
|
+
module RLTK # :nodoc:
|
18
|
+
module Parsers # :nodoc:
|
19
|
+
|
20
|
+
# A parser for a simple prefix calculator.
|
21
|
+
class PrefixCalc < Parser
|
22
|
+
production(:e) do
|
23
|
+
clause('NUM') { |n| n }
|
24
|
+
|
25
|
+
clause('PLS e e') { |_, e0, e1| e0 + e1 }
|
26
|
+
clause('SUB e e') { |_, e0, e1| e0 - e1 }
|
27
|
+
clause('MUL e e') { |_, e0, e1| e0 * e1 }
|
28
|
+
clause('DIV e e') { |_, e0, e1| e0 / e1 }
|
29
|
+
end
|
30
|
+
|
31
|
+
finalize
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/rltk/token.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# Author: Chris Wailes <chris.wailes@gmail.com>
|
2
|
+
# Project: Ruby Language Toolkit
|
3
|
+
# Date: 2011/01/17
|
4
|
+
# Description: This file contains code having to do with tokens.
|
5
|
+
|
6
|
+
#######################
|
7
|
+
# Classes and Modules #
|
8
|
+
#######################
|
9
|
+
|
10
|
+
module RLTK # :nodoc:
|
11
|
+
|
12
|
+
# The StreamPosition class is used to indicate the position of a token or
|
13
|
+
# other text inside a stream.
|
14
|
+
class StreamPosition
|
15
|
+
attr_accessor :stream_offset
|
16
|
+
attr_accessor :line_number
|
17
|
+
attr_accessor :line_offset
|
18
|
+
attr_accessor :length
|
19
|
+
|
20
|
+
attr_accessor :file_name
|
21
|
+
|
22
|
+
alias :start :line_offset
|
23
|
+
|
24
|
+
# Instantiates a new StreamPosition object with the values specified.
|
25
|
+
def initialize(stream_offset = 0, line_number = 0, line_offset = 0, length = 0, file_name = nil)
|
26
|
+
@stream_offset = stream_offset
|
27
|
+
@line_number = line_number
|
28
|
+
@line_offset = line_offset
|
29
|
+
@length = length
|
30
|
+
@file_name = file_name
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# The Token class is used to represent the output of a RLTK::Lexer and the
|
35
|
+
# input of a RLTK::Parser.
|
36
|
+
class Token
|
37
|
+
attr_reader :type
|
38
|
+
attr_reader :value
|
39
|
+
|
40
|
+
# The StreamPosition object associated with this token.
|
41
|
+
attr_reader :position
|
42
|
+
|
43
|
+
# Instantiates a new Token object with the values specified.
|
44
|
+
def initialize(type, value = nil, position = nil)
|
45
|
+
@type = type
|
46
|
+
@value = value
|
47
|
+
|
48
|
+
@position = position
|
49
|
+
end
|
50
|
+
|
51
|
+
# Compares one token to another. This only tests the token's _type_
|
52
|
+
# and _value_ and not the location of the token in its source.
|
53
|
+
def ==(other)
|
54
|
+
self.type == other.type and self.value == other.value
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns a string representing the tokens _type_ and _value_.
|
58
|
+
def to_s
|
59
|
+
if value
|
60
|
+
"#{self.type}(#{self.value})"
|
61
|
+
else
|
62
|
+
self.type.to_s
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/test/tc_ast.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
# Author: Chris Wailes <chris.wailes@gmail.com>
|
2
|
+
# Project: Ruby Language Toolkit
|
3
|
+
# Date: 2011/04/06
|
4
|
+
# Description: This file contains unit tests for the RLTK::ASTNode class.
|
5
|
+
|
6
|
+
############
|
7
|
+
# Requires #
|
8
|
+
############
|
9
|
+
|
10
|
+
# Standard Library
|
11
|
+
require 'test/unit'
|
12
|
+
require 'pp'
|
13
|
+
|
14
|
+
# Ruby Language Toolkit
|
15
|
+
require 'rltk/ast'
|
16
|
+
|
17
|
+
#######################
|
18
|
+
# Classes and Modules #
|
19
|
+
#######################
|
20
|
+
|
21
|
+
class ANode < RLTK::ASTNode
|
22
|
+
child :left, ANode
|
23
|
+
child :right, ANode
|
24
|
+
end
|
25
|
+
|
26
|
+
class BNode < ANode; end
|
27
|
+
class CNode < ANode; end
|
28
|
+
|
29
|
+
class DNode < RLTK::ASTNode; end
|
30
|
+
|
31
|
+
class ASTNodeTester < Test::Unit::TestCase
|
32
|
+
def setup
|
33
|
+
@leaf0 = CNode.new(nil, nil)
|
34
|
+
@tree0 = ANode.new(BNode.new(@leaf0, nil), BNode.new(nil, nil))
|
35
|
+
|
36
|
+
@tree1 = ANode.new(BNode.new(CNode.new(nil, nil), nil), BNode.new(nil, nil))
|
37
|
+
@tree2 = ANode.new(BNode.new(nil, nil), BNode.new(CNode.new(nil, nil), nil))
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_children
|
41
|
+
node = ANode.new(nil, nil)
|
42
|
+
|
43
|
+
assert_equal(node.children, [nil, nil])
|
44
|
+
|
45
|
+
node.children = (expected_children = [BNode.new(nil, nil), CNode.new(nil, nil)])
|
46
|
+
|
47
|
+
assert_equal(node.children, expected_children)
|
48
|
+
|
49
|
+
node.map do |child|
|
50
|
+
if child.is_a?(BNode)
|
51
|
+
CNode.new(nil, nil)
|
52
|
+
else
|
53
|
+
BNode.new(nil, nil)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
assert_equal(node.children, expected_children.reverse)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_equal
|
61
|
+
assert_equal(@tree0, @tree1)
|
62
|
+
assert_not_equal(@tree0, @tree2)
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_initialize
|
66
|
+
assert_raise(Exception) { RLTK::ASTNode.new }
|
67
|
+
assert_nothing_raised(Exception) { ANode.new(nil, nil) }
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_notes
|
71
|
+
node = ANode.new(nil, nil)
|
72
|
+
|
73
|
+
assert_nil(node[:a])
|
74
|
+
assert_equal(node[:a] = :b, :b)
|
75
|
+
assert_equal(node.note?(:a), true)
|
76
|
+
assert_equal(node.note?(:b), false)
|
77
|
+
assert_equal(node.delete_note(:a), :b)
|
78
|
+
assert_nil(node[:a])
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_root
|
82
|
+
assert_same(@tree0, @tree0.root)
|
83
|
+
assert_same(@tree0, @leaf0.root)
|
84
|
+
end
|
85
|
+
end
|
data/test/tc_cfg.rb
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
# Author: Chris Wailes <chris.wailes@gmail.com>
|
2
|
+
# Project: Ruby Language Toolkit
|
3
|
+
# Date: 2011/04/06
|
4
|
+
# Description: This file contains unit tests for the RLTK::CFG class.
|
5
|
+
|
6
|
+
############
|
7
|
+
# Requires #
|
8
|
+
############
|
9
|
+
|
10
|
+
# Standard Library
|
11
|
+
require 'test/unit'
|
12
|
+
|
13
|
+
# Ruby Language Toolkit
|
14
|
+
require 'rltk/cfg'
|
15
|
+
|
16
|
+
#######################
|
17
|
+
# Classes and Modules #
|
18
|
+
#######################
|
19
|
+
|
20
|
+
class CFGTester < Test::Unit::TestCase
|
21
|
+
def setup
|
22
|
+
@grammar = RLTK::CFG.new
|
23
|
+
|
24
|
+
@grammar.production(:s) do
|
25
|
+
clause('A G D')
|
26
|
+
clause('A a C')
|
27
|
+
clause('B a D')
|
28
|
+
clause('B G C')
|
29
|
+
end
|
30
|
+
|
31
|
+
@grammar.production(:a, 'b')
|
32
|
+
@grammar.production(:b, 'G')
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_callback
|
36
|
+
grammar = RLTK::CFG.new
|
37
|
+
|
38
|
+
first = true
|
39
|
+
grammar.callback do |p, type, num|
|
40
|
+
assert_not_nil(p)
|
41
|
+
assert_equal(type, :'?')
|
42
|
+
|
43
|
+
if first
|
44
|
+
assert_equal(num, :first)
|
45
|
+
first = false
|
46
|
+
else
|
47
|
+
assert_equal(num, :second)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
grammar.production(:a, 'A?') { |a| a }
|
52
|
+
|
53
|
+
first = true
|
54
|
+
grammar.callback do |p, type, num|
|
55
|
+
assert_not_nil(p)
|
56
|
+
assert_equal(type, :*)
|
57
|
+
|
58
|
+
if first
|
59
|
+
assert_equal(num, :first)
|
60
|
+
first = false
|
61
|
+
else
|
62
|
+
assert_equal(num, :second)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
grammar.production(:a, 'A*') { |a| a }
|
67
|
+
|
68
|
+
first = true
|
69
|
+
grammar.callback do |p, type, num|
|
70
|
+
assert_not_nil(p)
|
71
|
+
assert_equal(type, :+)
|
72
|
+
|
73
|
+
if first
|
74
|
+
assert_equal(num, :first)
|
75
|
+
first = false
|
76
|
+
else
|
77
|
+
assert_equal(num, :second)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
grammar.production(:a, 'A+') { |a| a }
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_first_set
|
85
|
+
@grammar.first_set(:s).each do |sym|
|
86
|
+
assert([:A, :B].include?(sym))
|
87
|
+
end
|
88
|
+
|
89
|
+
assert_equal(@grammar.first_set(:b), [:G])
|
90
|
+
assert_equal(@grammar.first_set(:a), [:G])
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_follow_set
|
94
|
+
assert_equal(@grammar.follow_set(:s), [:EOS])
|
95
|
+
|
96
|
+
@grammar.follow_set(:a).each do |sym|
|
97
|
+
assert([:C, :D].include?(sym))
|
98
|
+
end
|
99
|
+
|
100
|
+
@grammar.follow_set(:b).each do |sym|
|
101
|
+
assert([:C, :D].include?(sym))
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_is_nonterminal
|
106
|
+
assert_equal(RLTK::CFG::is_nonterminal?(:lowercase), true)
|
107
|
+
assert_equal(RLTK::CFG::is_nonterminal?(:UPERCASE), false)
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_is_terminal
|
111
|
+
assert_equal(RLTK::CFG::is_terminal?(:lowercase), false)
|
112
|
+
assert_equal(RLTK::CFG::is_terminal?(:UPERCASE), true)
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_item
|
116
|
+
i0 = RLTK::CFG::Item.new(0, 0, :a, [:b, :C, :D, :e])
|
117
|
+
i1 = i0.copy
|
118
|
+
|
119
|
+
assert_equal(i0, i1)
|
120
|
+
assert_equal(i0.at_end?, false)
|
121
|
+
assert_equal(i0.next_symbol, :b)
|
122
|
+
|
123
|
+
i0.advance
|
124
|
+
|
125
|
+
assert_not_equal(i0, i1)
|
126
|
+
assert_equal(i0.at_end?, false)
|
127
|
+
assert_equal(i0.next_symbol, :C)
|
128
|
+
|
129
|
+
i0.advance
|
130
|
+
assert_equal(i0.at_end?, false)
|
131
|
+
assert_equal(i0.next_symbol, :D)
|
132
|
+
|
133
|
+
i0.advance
|
134
|
+
assert_equal(i0.at_end?, false)
|
135
|
+
assert_equal(i0.next_symbol, :e)
|
136
|
+
|
137
|
+
i0.advance
|
138
|
+
assert_equal(i0.at_end?, true)
|
139
|
+
assert_nil(i0.next_symbol)
|
140
|
+
end
|
141
|
+
|
142
|
+
def test_production
|
143
|
+
p0 = RLTK::CFG::Production.new(0, :a, [:b, :C, :D, :e])
|
144
|
+
p1 = p0.copy
|
145
|
+
|
146
|
+
assert_equal(p0, p1)
|
147
|
+
assert_equal(p0.last_terminal, :D)
|
148
|
+
end
|
149
|
+
end
|
data/test/tc_lexer.rb
ADDED
@@ -0,0 +1,217 @@
|
|
1
|
+
# Author: Chris Wailes <chris.wailes@gmail.com>
|
2
|
+
# Project: Ruby Language Toolkit
|
3
|
+
# Date: 2011/04/06
|
4
|
+
# Description: This file contains unit tests for the RLTK::Lexer class.
|
5
|
+
|
6
|
+
############
|
7
|
+
# Requires #
|
8
|
+
############
|
9
|
+
|
10
|
+
# Standard Library
|
11
|
+
require 'test/unit'
|
12
|
+
|
13
|
+
# Ruby Language Toolkit
|
14
|
+
require 'rltk/token'
|
15
|
+
require 'rltk/lexer'
|
16
|
+
require 'rltk/lexers/calculator'
|
17
|
+
require 'rltk/lexers/ebnf'
|
18
|
+
|
19
|
+
#######################
|
20
|
+
# Classes and Modules #
|
21
|
+
#######################
|
22
|
+
|
23
|
+
class ABLongest < RLTK::Lexer
|
24
|
+
rule(/a+/) { :APLUS }
|
25
|
+
rule(/b+/) { :BPLUS }
|
26
|
+
|
27
|
+
rule(/a+b+/) { :APLUSBPLUS }
|
28
|
+
end
|
29
|
+
|
30
|
+
class ABFirst < RLTK::Lexer
|
31
|
+
match_first
|
32
|
+
|
33
|
+
rule(/a+/) { :APLUS }
|
34
|
+
rule(/b+/) { :BPLUS }
|
35
|
+
|
36
|
+
rule(/a+b+/) { :APLUSBPLUS }
|
37
|
+
end
|
38
|
+
|
39
|
+
class ENVLexer < RLTK::Lexer
|
40
|
+
rule(/a/) { [:A, next_value] }
|
41
|
+
|
42
|
+
class Environment < Environment
|
43
|
+
def initialize(*args)
|
44
|
+
super(*args)
|
45
|
+
@value = -1
|
46
|
+
end
|
47
|
+
|
48
|
+
def next_value
|
49
|
+
@value += 1
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class FlagLexer < RLTK::Lexer
|
55
|
+
rule(/a/) { set_flag(:a); :A }
|
56
|
+
rule(/\s/)
|
57
|
+
|
58
|
+
rule(/b/, :default, [:a]) { set_flag(:b); :B }
|
59
|
+
rule(/c/, :default, [:a, :b]) { :C }
|
60
|
+
end
|
61
|
+
|
62
|
+
class StateLexer < RLTK::Lexer
|
63
|
+
rule(/a/) { :A }
|
64
|
+
rule(/\s/)
|
65
|
+
|
66
|
+
rule(/\(\*/) { push_state(:comment) }
|
67
|
+
|
68
|
+
rule(/\(\*/, :comment) { push_state(:comment) }
|
69
|
+
rule(/\*\)/, :comment) { pop_state }
|
70
|
+
rule(/./, :comment)
|
71
|
+
end
|
72
|
+
|
73
|
+
class LexerTester < Test::Unit::TestCase
|
74
|
+
def test_calc
|
75
|
+
expected =
|
76
|
+
[
|
77
|
+
RLTK::Token.new(:NUM, 1),
|
78
|
+
|
79
|
+
RLTK::Token.new(:PLS),
|
80
|
+
RLTK::Token.new(:SUB),
|
81
|
+
RLTK::Token.new(:MUL),
|
82
|
+
RLTK::Token.new(:DIV),
|
83
|
+
|
84
|
+
RLTK::Token.new(:LPAREN),
|
85
|
+
RLTK::Token.new(:RPAREN),
|
86
|
+
RLTK::Token.new(:EOS)
|
87
|
+
]
|
88
|
+
|
89
|
+
actual = RLTK::Lexers::Calculator.lex('1 + - * / ( )')
|
90
|
+
|
91
|
+
assert_equal(expected, actual)
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_ebnf
|
95
|
+
expected =
|
96
|
+
[
|
97
|
+
RLTK::Token.new(:NONTERM, :aaa),
|
98
|
+
RLTK::Token.new(:TERM, :BBB),
|
99
|
+
|
100
|
+
RLTK::Token.new(:*),
|
101
|
+
RLTK::Token.new(:+),
|
102
|
+
RLTK::Token.new(:'?'),
|
103
|
+
RLTK::Token.new(:EOS)
|
104
|
+
]
|
105
|
+
|
106
|
+
actual = RLTK::Lexers::EBNF.lex('aaa BBB * + ?')
|
107
|
+
|
108
|
+
assert_equal(expected, actual)
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_environment
|
112
|
+
expected =
|
113
|
+
[
|
114
|
+
RLTK::Token.new(:A, 0),
|
115
|
+
RLTK::Token.new(:A, 1),
|
116
|
+
RLTK::Token.new(:A, 2),
|
117
|
+
RLTK::Token.new(:EOS)
|
118
|
+
]
|
119
|
+
|
120
|
+
actual = ENVLexer.lex('aaa')
|
121
|
+
|
122
|
+
assert_equal(expected, actual)
|
123
|
+
|
124
|
+
lexer = ENVLexer.new
|
125
|
+
|
126
|
+
assert_equal(expected, lexer.lex('aaa'))
|
127
|
+
|
128
|
+
expected =
|
129
|
+
[
|
130
|
+
RLTK::Token.new(:A, 3),
|
131
|
+
RLTK::Token.new(:A, 4),
|
132
|
+
RLTK::Token.new(:A, 5),
|
133
|
+
RLTK::Token.new(:EOS)
|
134
|
+
]
|
135
|
+
|
136
|
+
assert_equal(expected, lexer.lex('aaa'))
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_first_match
|
140
|
+
expected =
|
141
|
+
[
|
142
|
+
RLTK::Token.new(:APLUS),
|
143
|
+
RLTK::Token.new(:BPLUS),
|
144
|
+
RLTK::Token.new(:EOS)
|
145
|
+
]
|
146
|
+
|
147
|
+
actual = ABFirst.lex('aaabbb')
|
148
|
+
|
149
|
+
assert_equal(expected, actual)
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_flags
|
153
|
+
|
154
|
+
assert_raise(RLTK::LexingError) { FlagLexer.lex('b') }
|
155
|
+
assert_raise(RLTK::LexingError) { FlagLexer.lex('ac') }
|
156
|
+
|
157
|
+
expected =
|
158
|
+
[
|
159
|
+
RLTK::Token.new(:A),
|
160
|
+
RLTK::Token.new(:B),
|
161
|
+
RLTK::Token.new(:C),
|
162
|
+
RLTK::Token.new(:EOS)
|
163
|
+
]
|
164
|
+
|
165
|
+
actual = FlagLexer.lex('abc')
|
166
|
+
assert_equal(expected, actual)
|
167
|
+
|
168
|
+
expected =
|
169
|
+
[
|
170
|
+
RLTK::Token.new(:A),
|
171
|
+
RLTK::Token.new(:B),
|
172
|
+
RLTK::Token.new(:C),
|
173
|
+
RLTK::Token.new(:A),
|
174
|
+
RLTK::Token.new(:B),
|
175
|
+
RLTK::Token.new(:C),
|
176
|
+
RLTK::Token.new(:EOS)
|
177
|
+
]
|
178
|
+
|
179
|
+
actual = FlagLexer.lex('abcabc')
|
180
|
+
assert_equal(expected, actual)
|
181
|
+
end
|
182
|
+
|
183
|
+
def test_lex
|
184
|
+
assert_raise(RLTK::LexingError) { ABFirst.lex('aaabbbCCC') }
|
185
|
+
assert_raise(RLTK::LexingError) { ABLongest.lex('aaabbbCCC') }
|
186
|
+
|
187
|
+
assert_nothing_raised(RLTK::LexingError) { ABFirst.lex('aaabbb') }
|
188
|
+
assert_nothing_raised(RLTK::LexingError) { ABLongest.lex('aaabbb') }
|
189
|
+
end
|
190
|
+
|
191
|
+
def test_longest_match
|
192
|
+
expected =
|
193
|
+
[
|
194
|
+
RLTK::Token.new(:APLUSBPLUS),
|
195
|
+
RLTK::Token.new(:EOS)
|
196
|
+
]
|
197
|
+
|
198
|
+
actual = ABLongest.lex('aaabbb')
|
199
|
+
|
200
|
+
assert_equal(expected, actual)
|
201
|
+
end
|
202
|
+
|
203
|
+
def test_state
|
204
|
+
expected =
|
205
|
+
[
|
206
|
+
RLTK::Token.new(:A),
|
207
|
+
RLTK::Token.new(:A),
|
208
|
+
RLTK::Token.new(:EOS)
|
209
|
+
]
|
210
|
+
|
211
|
+
actual = StateLexer.lex('a (* bbb *) a')
|
212
|
+
assert_equal(expected, actual)
|
213
|
+
|
214
|
+
actual = StateLexer.lex('a (* b (* ccc *) b *) a')
|
215
|
+
assert_equal(expected, actual)
|
216
|
+
end
|
217
|
+
end
|