antlr3 1.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/ANTLR-LICENSE.txt +26 -0
- data/History.txt +66 -0
- data/README.txt +139 -0
- data/bin/antlr4ruby +33 -0
- data/java/RubyTarget.java +524 -0
- data/java/antlr-full-3.2.1.jar +0 -0
- data/lib/antlr3.rb +176 -0
- data/lib/antlr3/constants.rb +88 -0
- data/lib/antlr3/debug.rb +701 -0
- data/lib/antlr3/debug/event-hub.rb +210 -0
- data/lib/antlr3/debug/record-event-listener.rb +25 -0
- data/lib/antlr3/debug/rule-tracer.rb +55 -0
- data/lib/antlr3/debug/socket.rb +360 -0
- data/lib/antlr3/debug/trace-event-listener.rb +92 -0
- data/lib/antlr3/dfa.rb +247 -0
- data/lib/antlr3/dot.rb +174 -0
- data/lib/antlr3/error.rb +657 -0
- data/lib/antlr3/main.rb +561 -0
- data/lib/antlr3/modes/ast-builder.rb +41 -0
- data/lib/antlr3/modes/filter.rb +56 -0
- data/lib/antlr3/profile.rb +322 -0
- data/lib/antlr3/recognizers.rb +1280 -0
- data/lib/antlr3/streams.rb +985 -0
- data/lib/antlr3/streams/interactive.rb +91 -0
- data/lib/antlr3/streams/rewrite.rb +412 -0
- data/lib/antlr3/test/call-stack.rb +57 -0
- data/lib/antlr3/test/config.rb +23 -0
- data/lib/antlr3/test/core-extensions.rb +269 -0
- data/lib/antlr3/test/diff.rb +165 -0
- data/lib/antlr3/test/functional.rb +207 -0
- data/lib/antlr3/test/grammar.rb +371 -0
- data/lib/antlr3/token.rb +592 -0
- data/lib/antlr3/tree.rb +1415 -0
- data/lib/antlr3/tree/debug.rb +163 -0
- data/lib/antlr3/tree/visitor.rb +84 -0
- data/lib/antlr3/tree/wizard.rb +481 -0
- data/lib/antlr3/util.rb +149 -0
- data/lib/antlr3/version.rb +27 -0
- data/samples/ANTLRv3Grammar.g +621 -0
- data/samples/Cpp.g +749 -0
- data/templates/AST.stg +335 -0
- data/templates/ASTDbg.stg +40 -0
- data/templates/ASTParser.stg +153 -0
- data/templates/ASTTreeParser.stg +272 -0
- data/templates/Dbg.stg +192 -0
- data/templates/Ruby.stg +1514 -0
- data/test/functional/ast-output/auto-ast.rb +797 -0
- data/test/functional/ast-output/construction.rb +555 -0
- data/test/functional/ast-output/hetero-nodes.rb +753 -0
- data/test/functional/ast-output/rewrites.rb +1327 -0
- data/test/functional/ast-output/tree-rewrite.rb +1662 -0
- data/test/functional/debugging/debug-mode.rb +689 -0
- data/test/functional/debugging/profile-mode.rb +165 -0
- data/test/functional/debugging/rule-tracing.rb +74 -0
- data/test/functional/delegation/import.rb +379 -0
- data/test/functional/lexer/basic.rb +559 -0
- data/test/functional/lexer/filter-mode.rb +245 -0
- data/test/functional/lexer/nuances.rb +47 -0
- data/test/functional/lexer/properties.rb +104 -0
- data/test/functional/lexer/syn-pred.rb +32 -0
- data/test/functional/lexer/xml.rb +206 -0
- data/test/functional/main/main-scripts.rb +245 -0
- data/test/functional/parser/actions.rb +224 -0
- data/test/functional/parser/backtracking.rb +244 -0
- data/test/functional/parser/basic.rb +282 -0
- data/test/functional/parser/calc.rb +98 -0
- data/test/functional/parser/ll-star.rb +143 -0
- data/test/functional/parser/nuances.rb +165 -0
- data/test/functional/parser/predicates.rb +103 -0
- data/test/functional/parser/properties.rb +242 -0
- data/test/functional/parser/rule-methods.rb +132 -0
- data/test/functional/parser/scopes.rb +274 -0
- data/test/functional/token-rewrite/basic.rb +318 -0
- data/test/functional/token-rewrite/via-parser.rb +100 -0
- data/test/functional/tree-parser/basic.rb +750 -0
- data/test/unit/sample-input/file-stream-1 +2 -0
- data/test/unit/sample-input/teststreams.input2 +2 -0
- data/test/unit/test-dfa.rb +52 -0
- data/test/unit/test-exceptions.rb +44 -0
- data/test/unit/test-recognizers.rb +55 -0
- data/test/unit/test-scheme.rb +62 -0
- data/test/unit/test-streams.rb +459 -0
- data/test/unit/test-tree-wizard.rb +535 -0
- data/test/unit/test-trees.rb +854 -0
- metadata +205 -0
@@ -0,0 +1,244 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require 'antlr3/test/functional'
|
5
|
+
|
6
|
+
class TestBacktracking < ANTLR3::Test::Functional
|
7
|
+
|
8
|
+
inline_grammar(<<-'END')
|
9
|
+
grammar Backtrack;
|
10
|
+
options {
|
11
|
+
language = Ruby;
|
12
|
+
backtrack=true;
|
13
|
+
memoize=true;
|
14
|
+
k=2;
|
15
|
+
}
|
16
|
+
|
17
|
+
scope Symbols {
|
18
|
+
types;
|
19
|
+
}
|
20
|
+
|
21
|
+
@members {
|
22
|
+
def is_type_name?(name)
|
23
|
+
@Symbols_stack.reverse_each do |scope|
|
24
|
+
scope.types.include?(name) and return true
|
25
|
+
end
|
26
|
+
return false
|
27
|
+
end
|
28
|
+
|
29
|
+
def report_error(e)
|
30
|
+
# do nothing
|
31
|
+
end
|
32
|
+
|
33
|
+
}
|
34
|
+
|
35
|
+
translation_unit
|
36
|
+
scope Symbols; // entire file is a scope
|
37
|
+
@init {
|
38
|
+
$Symbols::types = Set.new
|
39
|
+
}
|
40
|
+
: external_declaration+
|
41
|
+
;
|
42
|
+
|
43
|
+
/** Either a function definition or any other kind of C decl/def.
|
44
|
+
* The LL(*) analysis algorithm fails to deal with this due to
|
45
|
+
* recursion in the declarator rules. I'm putting in a
|
46
|
+
* manual predicate here so that we don't backtrack over
|
47
|
+
* the entire function. Further, you get a better error
|
48
|
+
* as errors within the function itself don't make it fail
|
49
|
+
* to predict that it's a function. Weird errors previously.
|
50
|
+
* Remember: the goal is to avoid backtrack like the plague
|
51
|
+
* because it makes debugging, actions, and errors harder.
|
52
|
+
*
|
53
|
+
* Note that k=1 results in a much smaller predictor for the
|
54
|
+
* fixed look; k=2 made a few extra thousand lines. ;)
|
55
|
+
* I'll have to optimize that in the future.
|
56
|
+
*/
|
57
|
+
external_declaration
|
58
|
+
options {k=1;}
|
59
|
+
: ( declaration_specifiers? declarator declaration* '{' )=> function_definition
|
60
|
+
| declaration
|
61
|
+
;
|
62
|
+
|
63
|
+
function_definition
|
64
|
+
scope Symbols; // put parameters and locals into same scope for now
|
65
|
+
@init {
|
66
|
+
$Symbols::types = set()
|
67
|
+
}
|
68
|
+
: declaration_specifiers? declarator
|
69
|
+
;
|
70
|
+
|
71
|
+
declaration
|
72
|
+
scope {
|
73
|
+
is_type_def;
|
74
|
+
}
|
75
|
+
@init {
|
76
|
+
$declaration::is_type_def = false
|
77
|
+
}
|
78
|
+
: 'typedef' declaration_specifiers? {$declaration::is_type_def = true}
|
79
|
+
init_declarator_list ';' // special case, looking for typedef
|
80
|
+
| declaration_specifiers init_declarator_list? ';'
|
81
|
+
;
|
82
|
+
|
83
|
+
declaration_specifiers
|
84
|
+
: ( storage_class_specifier
|
85
|
+
| type_specifier
|
86
|
+
| type_qualifier
|
87
|
+
)+
|
88
|
+
;
|
89
|
+
|
90
|
+
init_declarator_list
|
91
|
+
: init_declarator (',' init_declarator)*
|
92
|
+
;
|
93
|
+
|
94
|
+
init_declarator
|
95
|
+
: declarator //('=' initializer)?
|
96
|
+
;
|
97
|
+
|
98
|
+
storage_class_specifier
|
99
|
+
: 'extern'
|
100
|
+
| 'static'
|
101
|
+
| 'auto'
|
102
|
+
| 'register'
|
103
|
+
;
|
104
|
+
|
105
|
+
type_specifier
|
106
|
+
: 'void'
|
107
|
+
| 'char'
|
108
|
+
| 'short'
|
109
|
+
| 'int'
|
110
|
+
| 'long'
|
111
|
+
| 'float'
|
112
|
+
| 'double'
|
113
|
+
| 'signed'
|
114
|
+
| 'unsigned'
|
115
|
+
| type_id
|
116
|
+
;
|
117
|
+
|
118
|
+
type_id
|
119
|
+
: { is_type_name?(@input.look(1).text)}? IDENTIFIER
|
120
|
+
;
|
121
|
+
|
122
|
+
type_qualifier
|
123
|
+
: 'const'
|
124
|
+
| 'volatile'
|
125
|
+
;
|
126
|
+
|
127
|
+
declarator
|
128
|
+
: pointer? direct_declarator
|
129
|
+
| pointer
|
130
|
+
;
|
131
|
+
|
132
|
+
direct_declarator
|
133
|
+
: ( IDENTIFIER
|
134
|
+
{
|
135
|
+
if $declaration.length > 0 && $declaration::is_type_def
|
136
|
+
$Symbols::types.add($IDENTIFIER.text)
|
137
|
+
end
|
138
|
+
}
|
139
|
+
| '(' declarator ')'
|
140
|
+
)
|
141
|
+
declarator_suffix*
|
142
|
+
;
|
143
|
+
|
144
|
+
declarator_suffix
|
145
|
+
: /*'[' constant_expression ']'
|
146
|
+
|*/ '[' ']'
|
147
|
+
| '(' ')'
|
148
|
+
;
|
149
|
+
|
150
|
+
pointer
|
151
|
+
: '*' type_qualifier+ pointer?
|
152
|
+
| '*' pointer
|
153
|
+
| '*'
|
154
|
+
;
|
155
|
+
|
156
|
+
IDENTIFIER
|
157
|
+
: LETTER (LETTER|'0'..'9')*
|
158
|
+
;
|
159
|
+
|
160
|
+
fragment
|
161
|
+
LETTER
|
162
|
+
: '$'
|
163
|
+
| 'A'..'Z'
|
164
|
+
| 'a'..'z'
|
165
|
+
| '_'
|
166
|
+
;
|
167
|
+
|
168
|
+
CHARACTER_LITERAL
|
169
|
+
: '\'' ( EscapeSequence | ~('\''|'\\') ) '\''
|
170
|
+
;
|
171
|
+
|
172
|
+
STRING_LITERAL
|
173
|
+
: '"' ( EscapeSequence | ~('\\'|'"') )* '"'
|
174
|
+
;
|
175
|
+
|
176
|
+
HEX_LITERAL : '0' ('x'|'X') HexDigit+ IntegerTypeSuffix? ;
|
177
|
+
|
178
|
+
DECIMAL_LITERAL : ('0' | '1'..'9' '0'..'9'*) IntegerTypeSuffix? ;
|
179
|
+
|
180
|
+
OCTAL_LITERAL : '0' ('0'..'7')+ IntegerTypeSuffix? ;
|
181
|
+
|
182
|
+
fragment
|
183
|
+
HexDigit : ('0'..'9'|'a'..'f'|'A'..'F') ;
|
184
|
+
|
185
|
+
fragment
|
186
|
+
IntegerTypeSuffix
|
187
|
+
: ('u'|'U')? ('l'|'L')
|
188
|
+
| ('u'|'U') ('l'|'L')?
|
189
|
+
;
|
190
|
+
|
191
|
+
FLOATING_POINT_LITERAL
|
192
|
+
: ('0'..'9')+ '.' ('0'..'9')* Exponent? FloatTypeSuffix?
|
193
|
+
| '.' ('0'..'9')+ Exponent? FloatTypeSuffix?
|
194
|
+
| ('0'..'9')+ Exponent FloatTypeSuffix?
|
195
|
+
| ('0'..'9')+ Exponent? FloatTypeSuffix
|
196
|
+
;
|
197
|
+
|
198
|
+
fragment
|
199
|
+
Exponent : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;
|
200
|
+
|
201
|
+
fragment
|
202
|
+
FloatTypeSuffix : ('f'|'F'|'d'|'D') ;
|
203
|
+
|
204
|
+
fragment
|
205
|
+
EscapeSequence
|
206
|
+
: '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
|
207
|
+
| OctalEscape
|
208
|
+
;
|
209
|
+
|
210
|
+
fragment
|
211
|
+
OctalEscape
|
212
|
+
: '\\' ('0'..'3') ('0'..'7') ('0'..'7')
|
213
|
+
| '\\' ('0'..'7') ('0'..'7')
|
214
|
+
| '\\' ('0'..'7')
|
215
|
+
;
|
216
|
+
|
217
|
+
fragment
|
218
|
+
UnicodeEscape
|
219
|
+
: '\\' 'u' HexDigit HexDigit HexDigit HexDigit
|
220
|
+
;
|
221
|
+
|
222
|
+
WS : (' '|'\r'|'\t'|'\u000C'|'\n') {$channel=HIDDEN;}
|
223
|
+
;
|
224
|
+
|
225
|
+
COMMENT
|
226
|
+
: '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}
|
227
|
+
;
|
228
|
+
|
229
|
+
LINE_COMMENT
|
230
|
+
: '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
|
231
|
+
;
|
232
|
+
LINE_COMMAND
|
233
|
+
: '#' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
|
234
|
+
;
|
235
|
+
END
|
236
|
+
|
237
|
+
example "grammar with backtracking and memoization" do
|
238
|
+
lexer = Backtrack::Lexer.new( 'int a;' )
|
239
|
+
parser = Backtrack::Parser.new lexer
|
240
|
+
events = parser.translation_unit
|
241
|
+
end
|
242
|
+
|
243
|
+
end
|
244
|
+
|
@@ -0,0 +1,282 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require 'antlr3/test/functional'
|
5
|
+
|
6
|
+
class TestParser001 < ANTLR3::Test::Functional
|
7
|
+
inline_grammar(<<-'END')
|
8
|
+
grammar Identifiers;
|
9
|
+
options { language = Ruby; }
|
10
|
+
|
11
|
+
@parser::init {
|
12
|
+
@identifiers = []
|
13
|
+
@reported_errors = []
|
14
|
+
}
|
15
|
+
|
16
|
+
@parser::members {
|
17
|
+
attr_reader :reported_errors, :identifiers
|
18
|
+
|
19
|
+
def found_identifier(name)
|
20
|
+
@identifiers << name
|
21
|
+
end
|
22
|
+
|
23
|
+
def emit_error_message(msg)
|
24
|
+
@reported_errors << msg
|
25
|
+
end
|
26
|
+
}
|
27
|
+
|
28
|
+
document:
|
29
|
+
t=IDENTIFIER {found_identifier($t.text)}
|
30
|
+
;
|
31
|
+
|
32
|
+
IDENTIFIER: ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*;
|
33
|
+
END
|
34
|
+
|
35
|
+
example "parsing 'blah_de_blah'" do
|
36
|
+
# to build a parser, this is the standard chain of calls to prepare the input
|
37
|
+
input = ANTLR3::StringStream.new( 'blah_de_blah', :file => 'blah.txt' )
|
38
|
+
lexer = Identifiers::Lexer.new( input )
|
39
|
+
tokens = ANTLR3::CommonTokenStream.new( lexer )
|
40
|
+
parser = Identifiers::Parser.new( tokens )
|
41
|
+
|
42
|
+
parser.document
|
43
|
+
|
44
|
+
parser.reported_errors.should be_empty
|
45
|
+
parser.identifiers.should == %w(blah_de_blah)
|
46
|
+
end
|
47
|
+
|
48
|
+
example "error from empty input" do
|
49
|
+
# if you don't need to use a customized stream, lexers and parsers will
|
50
|
+
# automatically wrap input in the standard stream classes
|
51
|
+
lexer = Identifiers::Lexer.new( '' )
|
52
|
+
parser = Identifiers::Parser.new( lexer )
|
53
|
+
parser.document
|
54
|
+
|
55
|
+
parser.reported_errors.should have(1).thing
|
56
|
+
end
|
57
|
+
|
58
|
+
example 'automatic input wrapping' do
|
59
|
+
# if the parser is able to figure out what lexer class
|
60
|
+
# to use (typically when it comes from a combined grammar),
|
61
|
+
# and you don't need to do any special token processing
|
62
|
+
# before making a parser, this is an extra shortcut for
|
63
|
+
# parser construction
|
64
|
+
parser = Identifiers::Parser.new( 'blah_de_blah', :file => 'blah.txt' )
|
65
|
+
|
66
|
+
parser.document
|
67
|
+
|
68
|
+
parser.reported_errors.should be_empty
|
69
|
+
parser.identifiers.should == %w(blah_de_blah)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class TestParser002 < ANTLR3::Test::Functional
|
74
|
+
inline_grammar(<<-'END')
|
75
|
+
grammar SimpleLanguage;
|
76
|
+
options {
|
77
|
+
language = Ruby;
|
78
|
+
}
|
79
|
+
|
80
|
+
@parser::init {
|
81
|
+
@events = []
|
82
|
+
@reported_errors = []
|
83
|
+
}
|
84
|
+
|
85
|
+
@parser::members {
|
86
|
+
attr_reader :reported_errors, :events
|
87
|
+
|
88
|
+
def emit_error_message(msg)
|
89
|
+
@reported_errors << msg
|
90
|
+
end
|
91
|
+
}
|
92
|
+
|
93
|
+
document:
|
94
|
+
( declaration
|
95
|
+
| call
|
96
|
+
)*
|
97
|
+
EOF
|
98
|
+
;
|
99
|
+
|
100
|
+
declaration:
|
101
|
+
'var' t=IDENTIFIER ';'
|
102
|
+
{@events << ['decl', $t.text]}
|
103
|
+
;
|
104
|
+
|
105
|
+
call:
|
106
|
+
t=IDENTIFIER '(' ')' ';'
|
107
|
+
{@events << ['call', $t.text]}
|
108
|
+
;
|
109
|
+
|
110
|
+
IDENTIFIER: ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*;
|
111
|
+
WS: (' '|'\r'|'\t'|'\n') {$channel=HIDDEN;};
|
112
|
+
END
|
113
|
+
|
114
|
+
|
115
|
+
example "parsing decls and calls" do
|
116
|
+
lexer = SimpleLanguage::Lexer.new( "var foobar; gnarz(); var blupp; flupp ( ) ;" )
|
117
|
+
parser = SimpleLanguage::Parser.new( lexer )
|
118
|
+
|
119
|
+
parser.document
|
120
|
+
|
121
|
+
parser.reported_errors.should be_empty
|
122
|
+
parser.events.should == [
|
123
|
+
%w(decl foobar),
|
124
|
+
%w(call gnarz),
|
125
|
+
%w(decl blupp),
|
126
|
+
%w(call flupp)
|
127
|
+
]
|
128
|
+
end
|
129
|
+
|
130
|
+
example "bad declaration" do
|
131
|
+
lexer = SimpleLanguage::Lexer.new( 'var; foo()' )
|
132
|
+
parser = SimpleLanguage::Parser.new( lexer )
|
133
|
+
|
134
|
+
parser.document
|
135
|
+
|
136
|
+
parser.reported_errors.should have(1).thing
|
137
|
+
parser.events.should be_empty
|
138
|
+
end
|
139
|
+
|
140
|
+
example "error recovery via token insertion" do
|
141
|
+
lexer = SimpleLanguage::Lexer.new( 'gnarz(; flupp();' )
|
142
|
+
parser = SimpleLanguage::Parser.new( lexer )
|
143
|
+
|
144
|
+
parser.document
|
145
|
+
|
146
|
+
parser.reported_errors.should have(1).thing
|
147
|
+
parser.events.should == [
|
148
|
+
%w(call gnarz),
|
149
|
+
%w(call flupp)
|
150
|
+
]
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
class TestParser003 < ANTLR3::Test::Functional
|
156
|
+
inline_grammar(<<-'END')
|
157
|
+
grammar MoreComplicated;
|
158
|
+
|
159
|
+
options { language = Ruby; }
|
160
|
+
|
161
|
+
@init {
|
162
|
+
@reported_errors = []
|
163
|
+
}
|
164
|
+
|
165
|
+
@members {
|
166
|
+
attr_reader :reported_errors
|
167
|
+
|
168
|
+
def emit_error_message(msg)
|
169
|
+
@reported_errors << msg
|
170
|
+
end
|
171
|
+
}
|
172
|
+
|
173
|
+
program
|
174
|
+
: declaration+
|
175
|
+
;
|
176
|
+
|
177
|
+
declaration
|
178
|
+
: variable
|
179
|
+
| functionHeader ';'
|
180
|
+
| functionHeader block
|
181
|
+
;
|
182
|
+
|
183
|
+
variable
|
184
|
+
: type declarator ';'
|
185
|
+
;
|
186
|
+
|
187
|
+
declarator
|
188
|
+
: ID
|
189
|
+
;
|
190
|
+
|
191
|
+
functionHeader
|
192
|
+
: type ID '(' ( formalParameter ( ',' formalParameter )* )? ')'
|
193
|
+
;
|
194
|
+
|
195
|
+
formalParameter
|
196
|
+
: type declarator
|
197
|
+
;
|
198
|
+
|
199
|
+
type
|
200
|
+
: 'int'
|
201
|
+
| 'char'
|
202
|
+
| 'void'
|
203
|
+
| ID
|
204
|
+
;
|
205
|
+
|
206
|
+
block
|
207
|
+
: '{'
|
208
|
+
variable*
|
209
|
+
stat*
|
210
|
+
'}'
|
211
|
+
;
|
212
|
+
|
213
|
+
stat: forStat
|
214
|
+
| expr ';'
|
215
|
+
| block
|
216
|
+
| assignStat ';'
|
217
|
+
| ';'
|
218
|
+
;
|
219
|
+
|
220
|
+
forStat
|
221
|
+
: 'for' '(' assignStat ';' expr ';' assignStat ')' block
|
222
|
+
;
|
223
|
+
|
224
|
+
assignStat
|
225
|
+
: ID '=' expr
|
226
|
+
;
|
227
|
+
|
228
|
+
expr: condExpr
|
229
|
+
;
|
230
|
+
|
231
|
+
condExpr
|
232
|
+
: aexpr ( ('==' | '<') aexpr )?
|
233
|
+
;
|
234
|
+
|
235
|
+
aexpr
|
236
|
+
: atom ( '+' atom )*
|
237
|
+
;
|
238
|
+
|
239
|
+
atom
|
240
|
+
: ID
|
241
|
+
| INT
|
242
|
+
| '(' expr ')'
|
243
|
+
;
|
244
|
+
|
245
|
+
ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
|
246
|
+
;
|
247
|
+
|
248
|
+
INT : ('0'..'9')+
|
249
|
+
;
|
250
|
+
|
251
|
+
WS : ( ' '
|
252
|
+
| '\t'
|
253
|
+
| '\r'
|
254
|
+
| '\n'
|
255
|
+
)+
|
256
|
+
{$channel=HIDDEN}
|
257
|
+
;
|
258
|
+
END
|
259
|
+
|
260
|
+
example "parsing 'int foo;'" do
|
261
|
+
lexer = MoreComplicated::Lexer.new "int foo;"
|
262
|
+
parser = MoreComplicated::Parser.new lexer
|
263
|
+
parser.program
|
264
|
+
parser.reported_errors.should be_empty
|
265
|
+
end
|
266
|
+
|
267
|
+
|
268
|
+
example "catching badly formed input" do
|
269
|
+
lexer = MoreComplicated::Lexer.new "int foo() { 1+2 }"
|
270
|
+
parser = MoreComplicated::Parser.new lexer
|
271
|
+
parser.program
|
272
|
+
parser.reported_errors.should have(1).thing
|
273
|
+
end
|
274
|
+
|
275
|
+
example "two instances of badly formed input" do
|
276
|
+
lexer = MoreComplicated::Lexer.new "int foo() { 1+; 1+2 }"
|
277
|
+
parser = MoreComplicated::Parser.new lexer
|
278
|
+
parser.program
|
279
|
+
parser.reported_errors.should have(2).things
|
280
|
+
end
|
281
|
+
|
282
|
+
end
|