iparser 1.1.6 → 1.1.7
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.
- checksums.yaml +4 -4
- data/lib/iparser.rb +2 -558
- data/lib/iparser/machine.rb +490 -0
- data/lib/iparser/state.rb +76 -0
- data/lib/iparser/version.rb +1 -1
- metadata +4 -11
- data/.gitignore +0 -9
- data/CODE_OF_CONDUCT.md +0 -13
- data/Gemfile +0 -4
- data/LICENSE.txt +0 -21
- data/README.md +0 -313
- data/Rakefile +0 -1
- data/bin/console +0 -14
- data/bin/setup +0 -7
- data/iparser.gemspec +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fb8c11dda45b03574bc8ac82a8dde785a9c51e82
|
4
|
+
data.tar.gz: 0d4e4b8978f466a20ffe8f20745f546ba9b66545
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a5b5179f93ad382926822ecac1b2c78ff38cd1a6d1bf341af1913ebabfb9d182f98fe28d5e7cf66366ff4b9655403457a703ce9814b6884360e8837f0f8c888
|
7
|
+
data.tar.gz: 2a06c84d8322fe76845051ec7d0050347597027aced8f89ec9fb6d6e50f6a813d83725015654e8db6af5d1d1976a69db1e0185f6cb62019e7f1708de712e24e7
|
data/lib/iparser.rb
CHANGED
@@ -1,565 +1,9 @@
|
|
1
1
|
#--
|
2
2
|
# iparser.rb - Universal parser machine to generate your specific parsers.
|
3
3
|
#++
|
4
|
+
require 'iparser/state'
|
5
|
+
require 'iparser/machine'
|
4
6
|
require 'iparser/version'
|
5
7
|
|
6
8
|
module Iparser
|
7
|
-
# Used for describe single state
|
8
|
-
# of parser machine.
|
9
|
-
class State
|
10
|
-
|
11
|
-
attr_reader :statename
|
12
|
-
attr_accessor :branches, :entry, :leave, :ientry, :ileave, :ignore
|
13
|
-
|
14
|
-
# call-seq:
|
15
|
-
# State.new( String )
|
16
|
-
def initialize ( sname )
|
17
|
-
unless sname.instance_of? String
|
18
|
-
raise TypeError, 'Incorrectly types for <Parser-State> constructor.'
|
19
|
-
end
|
20
|
-
|
21
|
-
@statename = sname
|
22
|
-
@init = nil # method called after entry (state constructor).
|
23
|
-
@fini = nil # method called after leave (state destructor).
|
24
|
-
@handler = nil # state machine for handler current state.
|
25
|
-
@ignore = []
|
26
|
-
@ientry = 0 # use to save compred index of this state.
|
27
|
-
@ileave = 0 # use to save compred index of this state.
|
28
|
-
@entry = [] # template chars for entry state.
|
29
|
-
@leave = [] # template chars for leave state.
|
30
|
-
@branches = [] # indexes of any states to branch.
|
31
|
-
end
|
32
|
-
|
33
|
-
# call-seq:
|
34
|
-
# init( method(:some_init_method) )
|
35
|
-
#
|
36
|
-
# Set initializer method for current state.
|
37
|
-
def init ( method )
|
38
|
-
raise TypeError, error_message(method, __method__) unless method.instance_of? Method
|
39
|
-
@init = method
|
40
|
-
end
|
41
|
-
|
42
|
-
# call-seq:
|
43
|
-
# fini( method(:some_fini_method) )
|
44
|
-
#
|
45
|
-
# Set finalizer method for current state.
|
46
|
-
def fini ( method )
|
47
|
-
raise TypeError, error_message(method, __method__) unless method.instance_of? Method
|
48
|
-
@fini = method
|
49
|
-
end
|
50
|
-
|
51
|
-
def run_init( *args ) # :nodoc:
|
52
|
-
return @init.call( *args ) if @init != nil
|
53
|
-
return nil
|
54
|
-
end
|
55
|
-
|
56
|
-
def run_fini( *args ) # :nodoc:
|
57
|
-
return @fini.call( *args ) if @fini != nil
|
58
|
-
return nil
|
59
|
-
end
|
60
|
-
|
61
|
-
# call-seq:
|
62
|
-
# handler( method(:some_handler_method) )
|
63
|
-
#
|
64
|
-
# Set handler method for current state.
|
65
|
-
def handler ( method )
|
66
|
-
raise TypeError, error_message(method, __method__) unless method.instance_of? Method
|
67
|
-
@handler = method
|
68
|
-
end
|
69
|
-
|
70
|
-
def run_handler( *args ) # :nodoc:
|
71
|
-
return @handler.call( *args ) if @handler != nil
|
72
|
-
return nil
|
73
|
-
end
|
74
|
-
|
75
|
-
private
|
76
|
-
def error_message(object, method)
|
77
|
-
"#{object.class}: Incorrectly types for <#{method}> method of <Parser-State>."
|
78
|
-
end
|
79
|
-
end # class State
|
80
|
-
|
81
|
-
|
82
|
-
# Used for create parser machine.
|
83
|
-
class Machine
|
84
|
-
INITIAL_STATE = 'wait'
|
85
|
-
|
86
|
-
attr_reader :parserstate
|
87
|
-
|
88
|
-
# call-seq:
|
89
|
-
# Machine.new( )
|
90
|
-
def initialize ( )
|
91
|
-
@buffer = [] # буфер для символов входного потока
|
92
|
-
@states = [] # массив с состояниями парсера, <ParserState> объекты
|
93
|
-
@chain = [] # цепочка работающих состояний
|
94
|
-
#
|
95
|
-
# Машина состояний для метода classify.
|
96
|
-
#
|
97
|
-
@matchstate = {
|
98
|
-
:state => 0,
|
99
|
-
:index => 0
|
100
|
-
}
|
101
|
-
@parserstate = ''
|
102
|
-
end
|
103
|
-
|
104
|
-
# Сбрасывает чувствительные переменные.
|
105
|
-
def reset ( ) # :nodoc:
|
106
|
-
@buffer = []
|
107
|
-
@states.each do |s|
|
108
|
-
s.ientry = 0
|
109
|
-
s.ileave = 0
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
# Return current state name.
|
114
|
-
def current_state ( )
|
115
|
-
return @chain.last.statename if @chain.size > 0
|
116
|
-
return nil
|
117
|
-
end
|
118
|
-
|
119
|
-
# Initialize parser object,
|
120
|
-
# should be called before call other methods.
|
121
|
-
def prestart ( )
|
122
|
-
reset( )
|
123
|
-
@matchstate[:state] = 0
|
124
|
-
@chain = [ @states[0], ]
|
125
|
-
end
|
126
|
-
|
127
|
-
# Display information about of each state of parser.
|
128
|
-
def display ( )
|
129
|
-
puts 'Parser states: ' + @states.size.to_s
|
130
|
-
|
131
|
-
@states.each do |st|
|
132
|
-
puts
|
133
|
-
puts '** state: ' + st.statename
|
134
|
-
puts 'branches: '
|
135
|
-
st.branches.each do |br|
|
136
|
-
puts ' ' + @states[br].statename
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
# Обработка ввода для интерактивных режимов работы.
|
142
|
-
def interactive_input ( ) # :nodoc:
|
143
|
-
state = 0
|
144
|
-
rv = ""
|
145
|
-
str = gets
|
146
|
-
|
147
|
-
# Сразу нажата <Enter> => exit.
|
148
|
-
return rv if str[0] == '\n'
|
149
|
-
|
150
|
-
# Выполняем разбор посимвольно.
|
151
|
-
str.each_char do |c|
|
152
|
-
break if c == ?\n
|
153
|
-
case state
|
154
|
-
#
|
155
|
-
# Сборка символов и проверка на наличие
|
156
|
-
# экранирующего символа, значит это ESC-символы.
|
157
|
-
when 0
|
158
|
-
if c == '\\' then
|
159
|
-
state = 1
|
160
|
-
else
|
161
|
-
rv += c
|
162
|
-
end
|
163
|
-
#
|
164
|
-
# Анализ ESC символа.
|
165
|
-
when 1
|
166
|
-
case c
|
167
|
-
when '0'
|
168
|
-
rv += "\0"
|
169
|
-
when 'n'
|
170
|
-
rv += "\n"
|
171
|
-
when 'r'
|
172
|
-
rv += "\r"
|
173
|
-
when '\\'
|
174
|
-
rv += "\\"
|
175
|
-
when 'a'
|
176
|
-
rv += "\a"
|
177
|
-
when 'b'
|
178
|
-
rv += "\b"
|
179
|
-
when 't'
|
180
|
-
rv += "\t"
|
181
|
-
when 'v'
|
182
|
-
rv += "\v"
|
183
|
-
when 'f'
|
184
|
-
rv += "\f"
|
185
|
-
else
|
186
|
-
puts "\nERROR: unrecognized esc-symbols.\n"
|
187
|
-
exit
|
188
|
-
end
|
189
|
-
state = 0
|
190
|
-
end
|
191
|
-
end
|
192
|
-
return rv
|
193
|
-
end
|
194
|
-
|
195
|
-
# Обработка вывода для интерактивных режимов работы.
|
196
|
-
def interactive_output( istr ) # :nodoc:
|
197
|
-
str = []
|
198
|
-
istr.bytes.each do |c|
|
199
|
-
case c
|
200
|
-
when 0
|
201
|
-
str << c.to_s + ":\\0"
|
202
|
-
when 10
|
203
|
-
str << c.to_s + ":\\n"
|
204
|
-
when 13
|
205
|
-
str << c.to_s + ":\\r"
|
206
|
-
when 7
|
207
|
-
str << c.to_s + ":\\a"
|
208
|
-
when 8
|
209
|
-
str << c.to_s + ":\\b"
|
210
|
-
when 9
|
211
|
-
str << c.to_s + ":\\t"
|
212
|
-
when 11
|
213
|
-
str << c.to_s + ":\\v"
|
214
|
-
when 12
|
215
|
-
str << c.to_s + ":\\f"
|
216
|
-
else
|
217
|
-
str << c.to_s + ":" + c.chr
|
218
|
-
end
|
219
|
-
end
|
220
|
-
return str
|
221
|
-
end
|
222
|
-
|
223
|
-
# Run parser machine for check in interactive mode.
|
224
|
-
def interactive_parser ( )
|
225
|
-
puts 'Press <Enter> to exit...'
|
226
|
-
|
227
|
-
# Цикл обработки ввода.
|
228
|
-
loop do
|
229
|
-
str = interactive_input( )
|
230
|
-
break if str == ""
|
231
|
-
|
232
|
-
# Цикл посимвольной классификаци.
|
233
|
-
str.bytes.each do |c|
|
234
|
-
parse( c.chr )
|
235
|
-
puts 'parser: ' + @parserstate
|
236
|
-
puts 'symbol: ' + interactive_output( c.chr ).to_s
|
237
|
-
puts 'state: ' + @chain.last.statename
|
238
|
-
puts
|
239
|
-
end
|
240
|
-
end
|
241
|
-
end
|
242
|
-
|
243
|
-
# call-seq:
|
244
|
-
# s = Parser::State.new('idle')
|
245
|
-
# p = Parser::Machine.new
|
246
|
-
# p << s
|
247
|
-
#
|
248
|
-
# Add any parser-state to current parser.
|
249
|
-
def addstate ( ps )
|
250
|
-
raise TypeError, ps.class.to_s + ': Incorrectly types for \'<<\' method of <Parser>.' unless
|
251
|
-
ps.instance_of? State
|
252
|
-
@states << ps
|
253
|
-
end
|
254
|
-
|
255
|
-
# call-seq:
|
256
|
-
# some_state1.branches << parser.state_index(some_state2).
|
257
|
-
# Return index
|
258
|
-
def state_index ( state )
|
259
|
-
raise TypeError, ps.class.to_s + ': Incorrectly types for \'state_index\' method of <Parser>.' unless
|
260
|
-
state.instance_of? State
|
261
|
-
|
262
|
-
@states.each_with_index do |st,i|
|
263
|
-
return i if state == st
|
264
|
-
end
|
265
|
-
raise "State <#{state.statename}> is not exist in Parser."
|
266
|
-
end
|
267
|
-
|
268
|
-
# Сравнивает символы входного потока
|
269
|
-
# с символами из указанного шаблона.
|
270
|
-
# В качестве шаблона выступают поля <entry> или <leave>
|
271
|
-
# объектов типа <ParserState>.
|
272
|
-
def cmp ( tmp, idx ) # :nodoc:
|
273
|
-
|
274
|
-
# проверка на случай если шаблон не задан,
|
275
|
-
# т.е. проинициализирован в [].
|
276
|
-
if tmp.size > 0 then
|
277
|
-
if idx < tmp.size then
|
278
|
-
case tmp[idx].class.to_s
|
279
|
-
when 'Regexp'
|
280
|
-
return true if @buffer.last =~ tmp[ idx ]
|
281
|
-
when 'String'
|
282
|
-
return true if @buffer.last == tmp[ idx ]
|
283
|
-
end
|
284
|
-
end
|
285
|
-
end
|
286
|
-
return false
|
287
|
-
end
|
288
|
-
|
289
|
-
# Поиск в массиве указанного диапазона,
|
290
|
-
# указанного в параметрах символа.
|
291
|
-
#
|
292
|
-
# >=0 : индекс совпавшего элемента.
|
293
|
-
# -1 : нет совпадений.
|
294
|
-
def checkback ( tmp, len ) # :nodoc:
|
295
|
-
if len > 0 then
|
296
|
-
i = len
|
297
|
-
len.times do
|
298
|
-
i = i - 1
|
299
|
-
return i if cmp( tmp, i )
|
300
|
-
end
|
301
|
-
end
|
302
|
-
return -1
|
303
|
-
end
|
304
|
-
|
305
|
-
# Находит соответствие между символами входного потока
|
306
|
-
# и возможными переходами.
|
307
|
-
#
|
308
|
-
# При совпадени возвращает индекс состояния
|
309
|
-
# в массиве состояний, иначе:
|
310
|
-
#
|
311
|
-
# >0 : прыжок в новое состояние
|
312
|
-
# -1 : возврат в предыдущее состояние
|
313
|
-
# -2 : еще идет проверка.
|
314
|
-
# -3 : нет cовпадений (промах).
|
315
|
-
def classify ( state ) # :nodoc:
|
316
|
-
case @matchstate[:state]
|
317
|
-
|
318
|
-
# Состояние еще не определено.
|
319
|
-
# :state = 0
|
320
|
-
when 0
|
321
|
-
mcount = 0
|
322
|
-
mindex = 0
|
323
|
-
backtag = 0
|
324
|
-
#
|
325
|
-
# Проверка условия выхода из состояния.
|
326
|
-
if cmp( state.leave, state.ileave ) then
|
327
|
-
state.ileave = state.ileave.next
|
328
|
-
#
|
329
|
-
# Возврат в предыдущее состояние.
|
330
|
-
if state.ileave >= state.leave.size then
|
331
|
-
return -1
|
332
|
-
end
|
333
|
-
backtag = 1
|
334
|
-
mindex = -1
|
335
|
-
else
|
336
|
-
#
|
337
|
-
# Нет совпадения, но если уже часть сравнений
|
338
|
-
# успешна, то возможно входной символ совпадает
|
339
|
-
# с предыдущими, уже совпавшими символами,
|
340
|
-
# т.е. как откат в режиме <wait>.
|
341
|
-
#
|
342
|
-
i = checkback( state.leave, state.ileave )
|
343
|
-
|
344
|
-
if i != -1 then
|
345
|
-
state.ileave = i.next
|
346
|
-
backtag = 1
|
347
|
-
else
|
348
|
-
state.ileave = 0
|
349
|
-
backtag = 0
|
350
|
-
end
|
351
|
-
end
|
352
|
-
#
|
353
|
-
# Проверка возможных переходов для
|
354
|
-
# указанного в параметрах состояния.
|
355
|
-
state.branches.each do |b|
|
356
|
-
if cmp( @states[b].entry, @states[b].ientry ) then
|
357
|
-
mcount = mcount + 1
|
358
|
-
mindex = b
|
359
|
-
@states[b].ientry = @states[b].ientry.next
|
360
|
-
#
|
361
|
-
# состояние полностью пройдено.
|
362
|
-
if @states[ b ].ientry >= @states[ b ].entry.size then
|
363
|
-
return b
|
364
|
-
end
|
365
|
-
else
|
366
|
-
#
|
367
|
-
# Нет совпадения, но если уже часть сравнений
|
368
|
-
# успешна, то возможно входной символ совпадает
|
369
|
-
# с предыдущими, уже совпавшими символами,
|
370
|
-
# т.е. как откат в режиме <wait>.
|
371
|
-
i = checkback( @states[b].entry, @states[b].ientry )
|
372
|
-
|
373
|
-
if i != -1 then
|
374
|
-
mcount = mcount + 1
|
375
|
-
mindex = b
|
376
|
-
@states[b].ientry = i.next
|
377
|
-
else
|
378
|
-
@states[b].ientry = 0
|
379
|
-
end
|
380
|
-
end
|
381
|
-
end
|
382
|
-
#
|
383
|
-
# Анализ количества совпадений.
|
384
|
-
case (mcount + backtag)
|
385
|
-
#
|
386
|
-
# нет совпадений.
|
387
|
-
when 0
|
388
|
-
return (-3 + backtag)
|
389
|
-
#
|
390
|
-
# однозначное совпадение, но весь массив шаблонов
|
391
|
-
# еще не пройден.
|
392
|
-
when 1
|
393
|
-
if mindex == -1 then
|
394
|
-
@matchstate[:state] = 2
|
395
|
-
else
|
396
|
-
@matchstate[:state] = 1
|
397
|
-
@matchstate[:index] = mindex
|
398
|
-
end
|
399
|
-
return -2
|
400
|
-
#
|
401
|
-
# нет однозначного соответствия.
|
402
|
-
else
|
403
|
-
return -2
|
404
|
-
end
|
405
|
-
|
406
|
-
# Состояние точно определено (переход в перед).
|
407
|
-
# :state = 1
|
408
|
-
when 1
|
409
|
-
i = @matchstate[:index]
|
410
|
-
if cmp( @states[ i ].entry, @states[ i ].ientry ) then
|
411
|
-
#
|
412
|
-
# Инкремент счетчика (индекса) вхождений.
|
413
|
-
@states[ i ].ientry = @states[ i ].ientry.next
|
414
|
-
#
|
415
|
-
# Массив шаблонов совпадает полностью.
|
416
|
-
# можно считать, что 100% совпадение.
|
417
|
-
if @states[ i ].ientry >= @states[ i ].entry.size then
|
418
|
-
@matchstate[:state] = 0
|
419
|
-
return i
|
420
|
-
end
|
421
|
-
return -2
|
422
|
-
end
|
423
|
-
#
|
424
|
-
# Нет совпадения, но если уже часть сравнений
|
425
|
-
# успешна, то возможно входной символ совпадает
|
426
|
-
# с предыдущими, уже совпавшими символами,
|
427
|
-
# т.е. как откат в режиме <wait>.
|
428
|
-
idx = checkback( @states[i].entry, @states[i].ientry )
|
429
|
-
|
430
|
-
if idx != -1 then
|
431
|
-
@states[i].ientry = idx.next
|
432
|
-
return -2
|
433
|
-
end
|
434
|
-
@states[i].ientry = 0
|
435
|
-
@matchstate[:state] = 0
|
436
|
-
return -3
|
437
|
-
|
438
|
-
# Состояние точно определено (возврат назад).
|
439
|
-
# :state = 2
|
440
|
-
when 2
|
441
|
-
if cmp( state.leave, state.ileave ) then
|
442
|
-
state.ileave = state.ileave.next
|
443
|
-
#
|
444
|
-
# Возврат в предыдущее состояние.
|
445
|
-
if state.ileave >= state.leave.size then
|
446
|
-
@matchstate[:state] = 0
|
447
|
-
return -1
|
448
|
-
end
|
449
|
-
return -2
|
450
|
-
end
|
451
|
-
#
|
452
|
-
# Нет совпадения, но если уже часть сравнений
|
453
|
-
# успешна, то возможно входной символ совпадает
|
454
|
-
# с предыдущими, уже совпавшими символами,
|
455
|
-
# т.е. как откат в режиме <wait>.
|
456
|
-
#
|
457
|
-
i = checkback( state.leave, state.ileave )
|
458
|
-
|
459
|
-
if i != -1 then
|
460
|
-
state.ileave = i.next
|
461
|
-
return -2
|
462
|
-
end
|
463
|
-
state.ileave = 0
|
464
|
-
@matchstate[:state] = 0
|
465
|
-
return -3
|
466
|
-
|
467
|
-
end # case @matchstate
|
468
|
-
end
|
469
|
-
|
470
|
-
# Main method, used for parse input stream.
|
471
|
-
# Parse will be starting in unit with nil index (0).
|
472
|
-
#
|
473
|
-
# Return true if parsing process is successful, else return false.
|
474
|
-
def parse ( c )
|
475
|
-
@parserstate = INITIAL_STATE
|
476
|
-
retval = true
|
477
|
-
#
|
478
|
-
# * Фиксированное состояние (определенное): -1.
|
479
|
-
# * Не фиксированное состояние (неопределенное): -2.
|
480
|
-
# * Переход (смена состояний): >0.
|
481
|
-
#
|
482
|
-
@buffer << c
|
483
|
-
|
484
|
-
# Задан шаблон для игнорирования символов.
|
485
|
-
if @chain.last.ignore.size > 0 then
|
486
|
-
return retval if @chain.last.ignore.include?(c)
|
487
|
-
end
|
488
|
-
|
489
|
-
# Проверка переходов в другие состояния.
|
490
|
-
r = classify( @chain.last )
|
491
|
-
|
492
|
-
# Переход (прыжок) в другое состояние.
|
493
|
-
# <branch>:
|
494
|
-
if r >= 0 then
|
495
|
-
@chain << @states[r]
|
496
|
-
if @chain.last.run_init( @buffer ) == nil then
|
497
|
-
reset( )
|
498
|
-
@parserstate = 'branch'
|
499
|
-
else
|
500
|
-
@parserstate = 'error'
|
501
|
-
retval = false
|
502
|
-
end
|
503
|
-
|
504
|
-
# Возврат из текущего состояния.
|
505
|
-
# <back>:
|
506
|
-
elsif r == -1 then
|
507
|
-
if @chain.last.run_fini( @buffer ) == nil then
|
508
|
-
#
|
509
|
-
# если это состояние не первое в цепочке
|
510
|
-
# тогда откатываемся назад.
|
511
|
-
if @chain.size > 1 then
|
512
|
-
@chain.delete_at( @chain.size - 1 )
|
513
|
-
end
|
514
|
-
reset( )
|
515
|
-
@parserstate = 'back'
|
516
|
-
else
|
517
|
-
@parserstate = 'error'
|
518
|
-
retval = false
|
519
|
-
end
|
520
|
-
|
521
|
-
# Нет совпадений.
|
522
|
-
# <miss>:
|
523
|
-
elsif r == -3 then
|
524
|
-
#
|
525
|
-
# если в процессе состояния <wait>
|
526
|
-
# мы попали в <miss>, то накопленный
|
527
|
-
# буфер надо обработать.
|
528
|
-
@buffer.each do |ch|
|
529
|
-
@parserstate = 'miss'
|
530
|
-
|
531
|
-
r = @chain.last.run_handler( ch )
|
532
|
-
#
|
533
|
-
# Анализ результата обработки состояния.
|
534
|
-
case r.class.to_s
|
535
|
-
#
|
536
|
-
# Fixnum - переход на любое состояние (индекс).
|
537
|
-
when 'Fixnum'
|
538
|
-
if( (r >= 0) && (r < @states.size) ) then
|
539
|
-
@chain << @states[r]
|
540
|
-
reset( )
|
541
|
-
@parserstate = 'hardset'
|
542
|
-
else
|
543
|
-
raise TypeError, "Method <#{@chain.last.statename}> return incorrectly index."
|
544
|
-
end
|
545
|
-
#
|
546
|
-
# nil - ничего не возвращает.
|
547
|
-
when 'NilClass'
|
548
|
-
#
|
549
|
-
# else - расценивается как ошибка обработки.
|
550
|
-
# обработка ложится на плечи разработчика.
|
551
|
-
else
|
552
|
-
@parserstate = 'error'
|
553
|
-
retval = false
|
554
|
-
break
|
555
|
-
end
|
556
|
-
end
|
557
|
-
@buffer = []
|
558
|
-
end
|
559
|
-
return retval
|
560
|
-
end
|
561
|
-
|
562
|
-
private :reset, :cmp, :checkback, :interactive_input, :interactive_output
|
563
|
-
end # class Machine
|
564
|
-
|
565
9
|
end
|