tp_plus 0.0.73 → 0.0.74

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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +74 -65
  3. data/Rakefile +35 -21
  4. data/bin/tpp +73 -73
  5. data/lib/tp_plus/interpreter.rb +152 -129
  6. data/lib/tp_plus/namespace.rb +66 -66
  7. data/lib/tp_plus/nodes/abort_node.rb +9 -9
  8. data/lib/tp_plus/nodes/address_node.rb +22 -0
  9. data/lib/tp_plus/nodes/argument_node.rb +20 -19
  10. data/lib/tp_plus/nodes/assignment_node.rb +45 -45
  11. data/lib/tp_plus/nodes/call_node.rb +34 -34
  12. data/lib/tp_plus/nodes/case_condition_node.rb +26 -26
  13. data/lib/tp_plus/nodes/case_node.rb +33 -33
  14. data/lib/tp_plus/nodes/comment_node.rb +22 -22
  15. data/lib/tp_plus/nodes/conditional_node.rb +60 -54
  16. data/lib/tp_plus/nodes/definition_node.rb +22 -22
  17. data/lib/tp_plus/nodes/digit_node.rb +22 -21
  18. data/lib/tp_plus/nodes/empty_stmt_node.rb +9 -0
  19. data/lib/tp_plus/nodes/eval_node.rb +13 -13
  20. data/lib/tp_plus/nodes/expression_node.rb +68 -65
  21. data/lib/tp_plus/nodes/for_node.rb +20 -20
  22. data/lib/tp_plus/nodes/header_node.rb +27 -27
  23. data/lib/tp_plus/nodes/indirect_node.rb +51 -49
  24. data/lib/tp_plus/nodes/inline_conditional_node.rb +40 -40
  25. data/lib/tp_plus/nodes/io_method_node.rb +55 -55
  26. data/lib/tp_plus/nodes/io_node.rb +31 -30
  27. data/lib/tp_plus/nodes/jump_node.rb +23 -23
  28. data/lib/tp_plus/nodes/label_definition_node.rb +21 -21
  29. data/lib/tp_plus/nodes/motion_node.rb +62 -62
  30. data/lib/tp_plus/nodes/namespace_node.rb +16 -16
  31. data/lib/tp_plus/nodes/namespaced_var_node.rb +38 -38
  32. data/lib/tp_plus/nodes/numreg_node.rb +26 -25
  33. data/lib/tp_plus/nodes/offset_node.rb +27 -27
  34. data/lib/tp_plus/nodes/operator_node.rb +78 -72
  35. data/lib/tp_plus/nodes/paren_expression_node.rb +17 -0
  36. data/lib/tp_plus/nodes/pause_node.rb +9 -9
  37. data/lib/tp_plus/nodes/position_data_node.rb +64 -50
  38. data/lib/tp_plus/nodes/position_node.rb +26 -25
  39. data/lib/tp_plus/nodes/posreg_node.rb +64 -48
  40. data/lib/tp_plus/nodes/raise_node.rb +13 -13
  41. data/lib/tp_plus/nodes/real_node.rb +27 -27
  42. data/lib/tp_plus/nodes/set_skip_node.rb +14 -0
  43. data/lib/tp_plus/nodes/skip_node.rb +22 -22
  44. data/lib/tp_plus/nodes/speed_node.rb +29 -29
  45. data/lib/tp_plus/nodes/string_node.rb +13 -13
  46. data/lib/tp_plus/nodes/string_register_node.rb +26 -25
  47. data/lib/tp_plus/nodes/termination_node.rb +23 -18
  48. data/lib/tp_plus/nodes/terminator_node.rb +16 -16
  49. data/lib/tp_plus/nodes/time_node.rb +24 -24
  50. data/lib/tp_plus/nodes/timer_method_node.rb +37 -37
  51. data/lib/tp_plus/nodes/timer_node.rb +16 -21
  52. data/lib/tp_plus/nodes/units_node.rb +20 -20
  53. data/lib/tp_plus/nodes/use_node.rb +21 -21
  54. data/lib/tp_plus/nodes/user_alarm_node.rb +16 -15
  55. data/lib/tp_plus/nodes/var_method_node.rb +23 -23
  56. data/lib/tp_plus/nodes/var_node.rb +39 -39
  57. data/lib/tp_plus/nodes/vision_register_node.rb +22 -21
  58. data/lib/tp_plus/nodes/wait_for_node.rb +54 -54
  59. data/lib/tp_plus/nodes/wait_until_node.rb +65 -65
  60. data/lib/tp_plus/nodes/while_node.rb +42 -36
  61. data/lib/tp_plus/parser.rb +1682 -1592
  62. data/lib/tp_plus/scanner.rb +283 -383
  63. data/lib/tp_plus/token.rb +97 -0
  64. data/lib/tp_plus/version.rb +3 -3
  65. data/lib/tp_plus.rb +66 -62
  66. data/test/test_helper.rb +5 -5
  67. data/test/tp_plus/test_interpreter.rb +1309 -1168
  68. data/test/tp_plus/test_parser.rb +496 -489
  69. data/test/tp_plus/test_scanner.rb +577 -522
  70. data/tp_plus.gemspec +31 -28
  71. metadata +61 -14
  72. data/lib/tp_plus/nodes/set_node.rb +0 -22
@@ -1,383 +1,283 @@
1
- #--
2
- # DO NOT MODIFY!!!!
3
- # This file is automatically generated by rex 1.0.5
4
- # from lexical definition file "generators/scanner.rex".
5
- #++
6
-
7
- require 'racc/parser'
8
- class TPPlus::Scanner < Racc::Parser
9
- require 'strscan'
10
-
11
- class ScanError < StandardError ; end
12
-
13
- attr_reader :lineno
14
- attr_reader :filename
15
- attr_accessor :state
16
-
17
- def scan_setup(str)
18
- @ss = StringScanner.new(str)
19
- @lineno = 1
20
- @state = nil
21
- end
22
-
23
- def action
24
- yield
25
- end
26
-
27
- def scan_str(str)
28
- scan_setup(str)
29
- do_parse
30
- end
31
- alias :scan :scan_str
32
-
33
- def load_file( filename )
34
- @filename = filename
35
- open(filename, "r") do |f|
36
- scan_setup(f.read)
37
- end
38
- end
39
-
40
- def scan_file( filename )
41
- load_file(filename)
42
- do_parse
43
- end
44
-
45
-
46
- def next_token
47
- return if @ss.eos?
48
-
49
- # skips empty actions
50
- until token = _next_token or @ss.eos?; end
51
- token
52
- end
53
-
54
- def _next_token
55
- text = @ss.peek(1)
56
- @lineno += 1 if text == "\n"
57
- token = case @state
58
- when nil
59
- case
60
- when (text = @ss.scan(/\#.*(?=\n?$)/i))
61
- action { [:COMMENT, text] }
62
-
63
- when (text = @ss.scan(/\b(true|false)\b/i))
64
- action { [:TRUE_FALSE, text.downcase == "true"] }
65
-
66
- when (text = @ss.scan(/R(?=\[)/i))
67
- action { [:NUMREG, text] }
68
-
69
- when (text = @ss.scan(/P(?=\[)/i))
70
- action { [:POSITION, text] }
71
-
72
- when (text = @ss.scan(/PR(?=\[)/i))
73
- action { [:POSREG, text] }
74
-
75
- when (text = @ss.scan(/VR(?=\[)/i))
76
- action { [:VREG, text] }
77
-
78
- when (text = @ss.scan(/SR(?=\[)/i))
79
- action { [:SREG, text] }
80
-
81
- when (text = @ss.scan(/AR(?=\[)/i))
82
- action { [:ARG, text] }
83
-
84
- when (text = @ss.scan(/TIMER(?=\[)/i))
85
- action { [:TIMER, text] }
86
-
87
- when (text = @ss.scan(/UALM(?=\[)/i))
88
- action { [:UALM, text] }
89
-
90
- when (text = @ss.scan(/F(?=\[)/i))
91
- action { [:OUTPUT, text] }
92
-
93
- when (text = @ss.scan(/DO(?=\[)/i))
94
- action { [:OUTPUT, text] }
95
-
96
- when (text = @ss.scan(/RO(?=\[)/i))
97
- action { [:OUTPUT, text] }
98
-
99
- when (text = @ss.scan(/UO(?=\[)/i))
100
- action { [:OUTPUT, text] }
101
-
102
- when (text = @ss.scan(/SO(?=\[)/i))
103
- action { [:OUTPUT, text] }
104
-
105
- when (text = @ss.scan(/DI(?=\[)/i))
106
- action { [:INPUT, text] }
107
-
108
- when (text = @ss.scan(/RI(?=\[)/i))
109
- action { [:INPUT, text] }
110
-
111
- when (text = @ss.scan(/UI(?=\[)/i))
112
- action { [:INPUT, text] }
113
-
114
- when (text = @ss.scan(/SI(?=\[)/i))
115
- action { [:INPUT, text] }
116
-
117
- when (text = @ss.scan(/\=\=/i))
118
- action { [:EEQUAL, text] }
119
-
120
- when (text = @ss.scan(/\=/i))
121
- action { [:EQUAL, text] }
122
-
123
- when (text = @ss.scan(/\:\=/i))
124
- action { [:ASSIGN, text] }
125
-
126
- when (text = @ss.scan(/\<\>|\!\=/i))
127
- action { [:NOTEQUAL, text] }
128
-
129
- when (text = @ss.scan(/\>\=/i))
130
- action { [:GTE, text] }
131
-
132
- when (text = @ss.scan(/\<\=/i))
133
- action { [:LTE, text] }
134
-
135
- when (text = @ss.scan(/\</i))
136
- action { [:LT, text] }
137
-
138
- when (text = @ss.scan(/\>/i))
139
- action { [:GT, text] }
140
-
141
- when (text = @ss.scan(/\+/i))
142
- action { [:PLUS, text] }
143
-
144
- when (text = @ss.scan(/\-/i))
145
- action { [:MINUS, text] }
146
-
147
- when (text = @ss.scan(/\*/i))
148
- action { [:STAR, text] }
149
-
150
- when (text = @ss.scan(/\//i))
151
- action { [:SLASH, text] }
152
-
153
- when (text = @ss.scan(/DIV/i))
154
- action { [:DIV, text] }
155
-
156
- when (text = @ss.scan(/&&/i))
157
- action { [:AND, text] }
158
-
159
- when (text = @ss.scan(/\|\|/i))
160
- action { [:OR, text] }
161
-
162
- when (text = @ss.scan(/\%/i))
163
- action { [:MOD, text] }
164
-
165
- when (text = @ss.scan(/\@/i))
166
- action { @state = :LABEL; [:AT_SYM, text] }
167
-
168
- when (text = @ss.scan(/\bTP_IGNORE_PAUSE\b/i))
169
- action { [:TP_HEADER, text] }
170
-
171
- when (text = @ss.scan(/\bTP_COMMENT\b/i))
172
- action { [:TP_HEADER, text] }
173
-
174
- when (text = @ss.scan(/\bTP_GROUPMASK\b/i))
175
- action { [:TP_HEADER, text] }
176
-
177
- when (text = @ss.scan(/\bTP_SUBTYPE\b/i))
178
- action { [:TP_HEADER, text] }
179
-
180
- when (text = @ss.scan(/\bset_uframe\b/i))
181
- action { [:FANUC_SET, text] }
182
-
183
- when (text = @ss.scan(/\bset_skip_condition\b/i))
184
- action { [:FANUC_SET, text] }
185
-
186
- when (text = @ss.scan(/\buse_payload\b/i))
187
- action { [:FANUC_USE, text] }
188
-
189
- when (text = @ss.scan(/\buse_uframe\b/i))
190
- action { [:FANUC_USE, text] }
191
-
192
- when (text = @ss.scan(/\buse_utool\b/i))
193
- action { [:FANUC_USE, text] }
194
-
195
- when (text = @ss.scan(/\babort\b/i))
196
- action { [:ABORT, text] }
197
-
198
- when (text = @ss.scan(/\bafter\b/i))
199
- action { [:AFTER, text] }
200
-
201
- when (text = @ss.scan(/\bat\b/i))
202
- action { [:AT, text] }
203
-
204
- when (text = @ss.scan(/\bcase\b/i))
205
- action { [:CASE, text] }
206
-
207
- when (text = @ss.scan(/\bcircular_move\b/i))
208
- action { [:MOVE, text] }
209
-
210
- when (text = @ss.scan(/\belse\b/i))
211
- action { [:ELSE, text] }
212
-
213
- when (text = @ss.scan(/\bend\b/i))
214
- action { [:END, text] }
215
-
216
- when (text = @ss.scan(/\beval\b/i))
217
- action { [:EVAL, text] }
218
-
219
- when (text = @ss.scan(/\bfor\b/i))
220
- action { [:FOR, text] }
221
-
222
- when (text = @ss.scan(/\bif\b/i))
223
- action { [:IF, text] }
224
-
225
- when (text = @ss.scan(/\bindirect\b/i))
226
- action { [:INDIRECT, text] }
227
-
228
- when (text = @ss.scan(/\bin\b/i))
229
- action { [:IN, text] }
230
-
231
- when (text = @ss.scan(/\bjoint_move\b/i))
232
- action { [:MOVE, text] }
233
-
234
- when (text = @ss.scan(/\bjump_to\b/i))
235
- action { [:JUMP, text] }
236
-
237
- when (text = @ss.scan(/\blinear_move\b/i))
238
- action { [:MOVE, text] }
239
-
240
- when (text = @ss.scan(/\bnamespace\b/i))
241
- action { [:NAMESPACE, text] }
242
-
243
- when (text = @ss.scan(/\boffset\b/i))
244
- action { [:OFFSET, text] }
245
-
246
- when (text = @ss.scan(/\bpause\b/i))
247
- action { [:PAUSE, text] }
248
-
249
- when (text = @ss.scan(/\bposition_data\b/i))
250
- action { [:POSITION_DATA, text] }
251
-
252
- when (text = @ss.scan(/\bpulse\b/i))
253
- action { [:IO_METHOD, text] }
254
-
255
- when (text = @ss.scan(/\braise\b/i))
256
- action { [:RAISE, text] }
257
-
258
- when (text = @ss.scan(/\breset\b/i))
259
- action { [:TIMER_METHOD, :reset] }
260
-
261
- when (text = @ss.scan(/\brestart\b/i))
262
- action { [:TIMER_METHOD, :restart] }
263
-
264
- when (text = @ss.scan(/\brun\b/i))
265
- action { [:RUN, text] }
266
-
267
- when (text = @ss.scan(/\bskip_to\b/i))
268
- action { [:SKIP, text] }
269
-
270
- when (text = @ss.scan(/\bstart\b/i))
271
- action { [:TIMER_METHOD, :start] }
272
-
273
- when (text = @ss.scan(/\bstop\b/i))
274
- action { [:TIMER_METHOD, :stop] }
275
-
276
- when (text = @ss.scan(/\bterm\b/i))
277
- action { [:TERM, text] }
278
-
279
- when (text = @ss.scan(/\btime_after\b/i))
280
- action { [:TIME_SEGMENT, text] }
281
-
282
- when (text = @ss.scan(/\btime_before\b/i))
283
- action { [:TIME_SEGMENT, text] }
284
-
285
- when (text = @ss.scan(/\btimeout_to\b/i))
286
- action { [:TIMEOUT, text] }
287
-
288
- when (text = @ss.scan(/\btoggle\b/i))
289
- action { [:IO_METHOD, text] }
290
-
291
- when (text = @ss.scan(/\btool_offset\b/i))
292
- action { [:OFFSET, text] }
293
-
294
- when (text = @ss.scan(/\bturn_on|turn_off\b/i))
295
- action { [:IO_METHOD, text] }
296
-
297
- when (text = @ss.scan(/\bto\b/i))
298
- action { [:TO, text] }
299
-
300
- when (text = @ss.scan(/\bunless\b/i))
301
- action { [:UNLESS, text] }
302
-
303
- when (text = @ss.scan(/\bvision_offset\b/i))
304
- action { [:OFFSET, text] }
305
-
306
- when (text = @ss.scan(/\bwait_for\b/i))
307
- action { [:WAIT_FOR, text] }
308
-
309
- when (text = @ss.scan(/\bwait_until\b/i))
310
- action { [:WAIT_UNTIL, text] }
311
-
312
- when (text = @ss.scan(/\bwhen\b/i))
313
- action { [:WHEN, text] }
314
-
315
- when (text = @ss.scan(/\bwhile\b/i))
316
- action { [:WHILE, text] }
317
-
318
- when (text = @ss.scan(/\r?\n/i))
319
- action { [:NEWLINE, text] }
320
-
321
- when (text = @ss.scan(/;/i))
322
- action { [:SEMICOLON, text] }
323
-
324
- when (text = @ss.scan(/\d+\.\d+|\.\d+/i))
325
- action { [:REAL, text.to_f] }
326
-
327
- when (text = @ss.scan(/\./i))
328
- action { [:DOT, text] }
329
-
330
- when (text = @ss.scan(/\d+/i))
331
- action { [:DIGIT, text.to_i] }
332
-
333
- when (text = @ss.scan(/\!/i))
334
- action { [:BANG, text] }
335
-
336
- when (text = @ss.scan(/\s+/i))
337
- ;
338
-
339
- when (text = @ss.scan(/[\w\?\!_]+/i))
340
- action { [:WORD, text] }
341
-
342
- when (text = @ss.scan(/"([^\n\r\f"]|\n|\r\n|\r|\f|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])*"|'([^\n\r\f']|\n|\r\n|\r|\f|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])*'/i))
343
- action { [:STRING, text[1,text.length-2]] }
344
-
345
- when (text = @ss.scan(/./i))
346
- action { [text, text] }
347
-
348
- else
349
- text = @ss.string[@ss.pos .. -1]
350
- raise ScanError, "can not match: '" + text + "'"
351
- end # if
352
-
353
- when :LABEL
354
- case
355
- when (text = @ss.scan(/[\w_0-9]+\b/i))
356
- action { @state = nil; [:WORD, text] }
357
-
358
- else
359
- text = @ss.string[@ss.pos .. -1]
360
- raise ScanError, "can not match: '" + text + "'"
361
- end # if
362
-
363
- else
364
- raise ScanError, "undefined state: '" + state.to_s + "'"
365
- end # case state
366
- token
367
- end # def _next_token
368
-
369
- end # class
370
-
371
- if __FILE__ == $0
372
- exit if ARGV.size != 1
373
- filename = ARGV.shift
374
- rex = TPPlus::Scanner.new
375
- begin
376
- rex.load_file filename
377
- while token = rex.next_token
378
- p token
379
- end
380
- rescue
381
- $stderr.printf "%s:%d:%s\n", rex.filename, rex.lineno, $!.message
382
- end
383
- end
1
+ module TPPlus
2
+ class Scanner
3
+ def initialize
4
+ end
5
+
6
+ def scan_setup(src)
7
+ @src = src
8
+ @lineno = 1
9
+ @ch = " "
10
+ @offset = 0
11
+ @rdOffset = 0
12
+ @prevDot = false # for groups
13
+ self.next
14
+ end
15
+
16
+ def next
17
+ if @rdOffset < @src.length
18
+ @offset = @rdOffset
19
+ @ch = @src[@rdOffset]
20
+ if @ch == "\n"
21
+ @lineno += 1
22
+ end
23
+ @rdOffset += 1
24
+ else
25
+ @offset = @src.length
26
+ @ch = -1
27
+ end
28
+ end
29
+
30
+ def isDigit?(ch)
31
+ return false if ch == -1
32
+
33
+ case ch
34
+ when '0','1','2','3','4','5','6','7','8','9'
35
+ return true
36
+ else
37
+ return false
38
+ end
39
+ end
40
+
41
+ def isLetter?(ch)
42
+ return false if ch == -1
43
+
44
+ case ch
45
+ when 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
46
+ 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
47
+ '_'
48
+ return true
49
+ else
50
+ return false
51
+ end
52
+ end
53
+
54
+ def skipWhitespace
55
+ while @ch == ' ' || @ch == "\t" || @ch == "\r"
56
+ self.next
57
+ end
58
+ end
59
+
60
+ def scanIdentifier
61
+ offs = @offset
62
+ while isLetter?(@ch) || isDigit?(@ch)
63
+ self.next
64
+ end
65
+
66
+ # allow one ? or ! at end
67
+ if @ch == '?' || @ch == '!'
68
+ self.next
69
+ end
70
+
71
+ return @src[offs,(@offset-offs)]
72
+ end
73
+
74
+ def scanReal
75
+ offs = @offset-1
76
+ while self.isDigit?(@ch)
77
+ self.next
78
+ end
79
+
80
+ return [:REAL, @src[offs,(@offset-offs)].to_f]
81
+ end
82
+
83
+ def scanNumber
84
+ offs = @offset
85
+ while self.isDigit?(@ch)
86
+ self.next
87
+ end
88
+ if @ch == '.'
89
+ self.next
90
+ while self.isDigit?(@ch)
91
+ self.next
92
+ end
93
+
94
+ return [:REAL, @src[offs,(@offset-offs)].to_f]
95
+ else
96
+ return [:DIGIT, @src[offs,(@offset-offs)].to_i]
97
+ end
98
+ end
99
+
100
+ def scanComment
101
+ offs = @offset-1 # opening # already consumed
102
+ while @ch != "\n" && @ch != -1
103
+ self.next
104
+ end
105
+
106
+ return @src[offs,(@offset-offs)]
107
+ end
108
+
109
+ def scanString(type)
110
+ offs = @offset
111
+ while @ch != type && @ch != -1
112
+ self.next
113
+ end
114
+
115
+ # consume close
116
+ self.next
117
+
118
+ return @src[offs, (@offset-offs-1)] # -1 to remove trailing " or '
119
+ end
120
+
121
+ def scanLabel
122
+ offs = @offset
123
+ while self.isLetter?(@ch)
124
+ self.next
125
+ end
126
+
127
+ return @src[offs, (@offset-offs)]
128
+ end
129
+
130
+ # return token
131
+ def next_token
132
+ self.skipWhitespace
133
+
134
+ tok = nil
135
+ lit = ""
136
+ ch = @ch
137
+
138
+ if isLetter?(ch)
139
+ lit = self.scanIdentifier
140
+ if @ch == '['
141
+ tok = TPPlus::Token.lookup_data(lit)
142
+ elsif lit == "DIV"
143
+ tok = :DIV
144
+ else
145
+ # keywords are longer than 1 char, avoid lookup otherwise
146
+ if lit.length > 1
147
+ if @prevDot
148
+ case lit
149
+ when "gp1","gp2","gp3","gp4","gp5"
150
+ tok = :GROUP
151
+ else
152
+ tok = TPPlus::Token.lookup(lit)
153
+ end
154
+ else
155
+ tok = TPPlus::Token.lookup(lit)
156
+ end
157
+ else
158
+ tok = :WORD
159
+ end
160
+ end
161
+ elsif isDigit?(ch)
162
+ tok, lit = self.scanNumber
163
+ else
164
+ self.next # always make progress
165
+ case ch
166
+ when -1
167
+ return nil
168
+ when '='
169
+ if @ch == '='
170
+ tok = :EEQUAL
171
+ self.next
172
+ else
173
+ tok = :EQUAL
174
+ end
175
+ when ':'
176
+ if @ch == "="
177
+ tok = :ASSIGN
178
+ self.next
179
+ else
180
+ tok = :COLON
181
+ end
182
+ when "<"
183
+ if @ch == "="
184
+ tok = :LTE
185
+ self.next
186
+ elsif @ch == ">"
187
+ tok = :NOTEQUAL
188
+ self.next
189
+ else
190
+ tok = :LT
191
+ end
192
+ when ">"
193
+ if @ch == "="
194
+ tok = :GTE
195
+ self.next
196
+ else
197
+ tok = :GT
198
+ end
199
+ when "+"
200
+ tok = :PLUS
201
+ when "-"
202
+ tok = :MINUS
203
+ when "*"
204
+ tok = :STAR
205
+ when "/"
206
+ tok = :SLASH
207
+ when "&"
208
+ if @ch == "&"
209
+ tok = :AND
210
+ self.next
211
+ elsif isLetter?(@ch)
212
+ tok = :ADDRESS
213
+ lit = self.scanIdentifier
214
+ else
215
+ tok = :ILLEGAL
216
+ end
217
+ when "|"
218
+ if @ch == "|"
219
+ tok = :OR
220
+ self.next
221
+ else
222
+ tok = :ILLEGAL
223
+ end
224
+ when "%"
225
+ tok = :MOD
226
+ when ";"
227
+ tok = :SEMICOLON
228
+ when "."
229
+ if self.isDigit?(@ch)
230
+ tok, lit = self.scanReal
231
+ else
232
+ tok = :DOT
233
+ end
234
+ when "!"
235
+ if @ch == "="
236
+ tok = :NOTEQUAL
237
+ self.next
238
+ else
239
+ tok = :BANG
240
+ end
241
+ when "\"", "'"
242
+ tok = :STRING
243
+ lit = self.scanString(ch)
244
+ when "#"
245
+ tok = :COMMENT
246
+ lit = self.scanComment
247
+ when "@"
248
+ tok = :LABEL
249
+ lit = self.scanLabel
250
+ when '('
251
+ tok = :LPAREN
252
+ when ')'
253
+ tok = :RPAREN
254
+ when ','
255
+ tok = :COMMA
256
+ when '['
257
+ tok = :LBRACK
258
+ when ']'
259
+ tok = :RBRACK
260
+ when '{'
261
+ tok = :LBRACE
262
+ when '}'
263
+ tok = :RBRACE
264
+ when "\n"
265
+ tok = :NEWLINE
266
+ else
267
+ tok = :ILLEGAL
268
+ lit = ch
269
+ end
270
+ end
271
+
272
+ if tok == :DOT
273
+ @prevDot = true
274
+ else
275
+ @prevDot = false
276
+ end
277
+
278
+ return [tok, lit]
279
+ end
280
+ end
281
+
282
+ class ScanError < StandardError ; end
283
+ end