Fix an error recovery routine that seems to not run often
[pilex.git] / skel_lex_yy.py
1 # Copyright (C) 2019 Nick Downing <nick@ndcode.org>
2 # SPDX-License-Identifier: GPL-2.0-with-bison-exception
3 #
4 # This program is free software; you can redistribute it and/or modify it under
5 # the terms of the GNU General Public License as published by the Free Software
6 # Foundation; version 2.
7 #
8 # This program is distributed in the hope that it will be useful, but WITHOUT
9 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11 # details.
12 #
13 # You should have received a copy of the GNU General Public License along with
14 # this program; if not, write to the Free Software Foundation, Inc., 51
15 # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
16 #
17 # As a special exception, you may create a larger work that contains part or
18 # all of the pilex lexical scanner skeleton and distribute that work under
19 # terms of your choice, so long as that work isn't itself a lexical scanner
20 # generator using the skeleton or a modified version thereof as a lexical
21 # scanner skeleton. Alternatively, if you modify or redistribute the lexical
22 # scanner skeleton itself, you may (at your option) remove this special
23 # exception, which will cause the skeleton and the resulting pilex output
24 # files to be licensed under the GNU General Public License without this
25 # special exception.
26
27 import bisect
28 import sys
29 from ndcode.pilex import element
30
31 # GENERATE SECTION1
32
33 # GENERATE STARTCONDDECL
34
35 class YYReject(Exception):
36   pass
37
38 class YYContinue(Exception):
39   pass
40
41 class YYTerminate(Exception):
42   pass
43
44 class YYBufferList:
45   def __init__(self, next = None):
46     self.next = next
47
48 class YYBufferBlock(YYBufferList):
49   def __init__(self, next = None, pos = 0, text = ''):
50     YYBufferList.__init__(self, next)
51     self.pos = pos
52     self.text = text
53
54 class YYBufferState(YYBufferList):
55   def __init__(self, next = None, file_in = None, at_bol = True):
56     YYBufferList.__init__(self, next)
57     self.file_in = file_in
58     self.at_bol = at_bol
59
60 yyin = sys.stdin
61 yyout = sys.stdout
62 yy_buffer_stack = [YYBufferState()]
63
64 yystart = INITIAL
65 yystart_stack = []
66 yy_threads0 = [None]
67 yy_threads1 = [None]
68 yy_prefix_slop = 1
69
70 yy_group_text = None
71 yy_group_stack = None
72 yy_groups = None
73 yy_groups_by_name = None
74 yy_action = None
75 yytext = ''
76 yytext_len = 0
77
78 yy_element_stack = None
79 yy_element_token = None
80 yy_element_space = None
81
82 YY_NULL = 0
83
84 def REJECT():
85   raise YYReject()
86
87 def yyterminate():
88   raise YYTerminate()
89
90 def yyless(i):
91   global yytext, yytext_len
92   assert yytext_len >= i
93   yytext = yytext[:i]
94   yytext_len = i
95
96 def unput(text):
97   global yyin, yytext_len
98   while yytext_len:
99     block = yy_buffer_stack[-1].next
100     while block is None or block.pos >= len(block.text):
101       if block is None:
102         yy_buffer_stack.pop()
103         block = yy_buffer_stack[-1].next
104         yyin = yy_buffer_stack[-1].file_in
105       else:
106         block = block.next
107         yy_buffer_stack[-1].next = block
108     i = min(yytext_len, len(block.text) - block.pos)
109     block.pos += i
110     yytext_len -= i
111   yy_buffer_stack[-1].next = YYBufferBlock(yy_buffer_stack[-1].next, 0, text)
112
113 def ECHO():
114   yyout.write(yytext)
115
116 def yy_rule_start():
117   global yytext, yytext_len, yy_element_stack
118   yytext = yy_group_text[:yy_group_stack[-1]]
119   yytext_len = yy_group_stack[-1]
120   del yy_group_stack[-2:]
121   # note that this should also be done after yyless() and REJECT(),
122   # and state should be saved in case they result in a null string,
123   # however, it doesn't seem to be in flex, maintain compatibility:
124   if len(yytext):
125     yy_buffer_stack[-1].at_bol = yytext[-1] == '\n'
126   yy_element_stack.append([])
127
128 def yy_group_end():
129   pass
130
131 def yy_group_end_element():
132   yy_element_stack.append([])
133
134 def yy_group_element(pos0, pos1, stack, _class, *args, **kwargs):
135   _element = _class(*args, **kwargs)
136   del _element.text[:]
137   for pos2, pos3, i in reversed(stack):
138     _element.text.append(yy_group_text[pos0:pos2])
139     _element.children.append(i)
140     pos0 = pos3
141   _element.text.append(yy_group_text[pos0:pos1])
142   return _element
143
144 def BEGIN(start):
145   global yystart
146   yystart = start
147
148 def YY_START():
149   return yystart
150
151 def yy_push_state(start):
152   global yystart
153   yystart_stack.append(yystart)
154   yystart = start
155
156 def yy_pop_state():
157   global yystart
158   yystart = yystart_stack.pop()
159
160 def YY_AT_BOL():
161   return yy_buffer_stack[-1].at_bol
162
163 def yy_set_bol(at_bol):
164   yy_buffer_stack[-1].at_bol = at_bol
165
166 # GENERATE SECTION2
167
168 def yylex(_class = element.Element, *args, **kwargs):
169   global \
170     yyin, \
171     yy_threads0, \
172     yy_threads1, \
173     yy_prefix_slop, \
174     yy_group_text, \
175     yy_group_stack, \
176     yy_action, \
177     yytext, \
178     yytext_len, \
179     yy_element_stack, \
180     yy_element_token, \
181     yy_element_space
182
183   # GENERATE SECTION2INITIAL
184
185   yy_element_space = _class(*args, **kwargs)
186   yy_element_token = _class(*args, **kwargs)
187   while True:
188     while yytext_len:
189       block = yy_buffer_stack[-1].next
190       while block is None or block.pos >= len(block.text):
191         if block is None:
192           yy_buffer_stack.pop()
193           block = yy_buffer_stack[-1].next
194           yyin = yy_buffer_stack[-1].file_in
195         else:
196           block = block.next
197           yy_buffer_stack[-1].next = block
198       i = min(yytext_len, len(block.text) - block.pos)
199       block.pos += i
200       yytext_len -= i
201
202     match = ''
203     match_len = 0
204
205     del yy_threads0[yy_prefix_slop:]
206     yy_threads0.append(None)
207
208     buffer_ptr = len(yy_buffer_stack) - 1
209     block_prev = yy_buffer_stack[buffer_ptr]
210     block = block_prev.next
211     if block is not None:
212       block_pos = block.pos
213
214     action = yy_dfa_start_action[
215       yystart * 2 + int(yy_buffer_stack[-1].at_bol)
216     ]
217     while action != -1:
218       state, transition = yy_dfa_actions[action]
219       #print('i', i, 'action', action, 'state', state, 'transition', transition)
220
221       i = yy_prefix_slop
222       assert len(yy_threads1) == yy_prefix_slop
223       for trans in transition:
224         if trans[0] == 0: #DFA.TRANSITION_POP:
225           i += trans[1]
226         elif trans[0] == 1: #DFA.TRANSITION_DUP:
227           while i < trans[1]:
228             yy_threads0[:0] = [None] * yy_prefix_slop
229             yy_threads1[:0] = [None] * yy_prefix_slop
230             i += yy_prefix_slop
231             yy_prefix_slop *= 2
232           yy_threads0[i - trans[1]:i] = yy_threads0[i:i + trans[1]]
233           i -= trans[1]
234         elif trans[0] == 2: #DFA.TRANSITION_MARK:
235           yy_threads0[i:i + trans[1]] = [
236             (match_len, trans[2], thread)
237             for thread in yy_threads0[i:i + trans[1]]
238           ]
239         elif trans[0] == 3: #DFA.TRANSITION_MOVE:
240           yy_threads1.extend(yy_threads0[i:i + trans[1]])
241           i += trans[1]
242         #elif trans[0] == DFA.TRANSITION_DEL:
243         #  del yy_threads1[-trans[1]:]
244         else:
245           assert False
246       assert i == len(yy_threads0)
247       yy_threads0, yy_threads1 = yy_threads1, yy_threads0
248       del yy_threads1[yy_prefix_slop:]
249
250       if state == 0:
251         # there is only one match, which is complete
252         assert len(yy_threads0) == yy_prefix_slop + 1
253         assert yy_dfa_states[state][2] == [0]
254         break
255
256       yy_buffer_stack[-1].file_in = yyin
257       while block is None or block_pos >= len(block.text):
258         if block is None:
259           file_in = yy_buffer_stack[buffer_ptr].file_in
260           text = '' if file_in is None else file_in.readline()
261           if len(text):
262             block = YYBufferBlock(None, 0, text)
263             block_pos = 0
264             block_prev.next = block
265           else:
266             # do not re-attempt read once EOF is reached
267             yy_buffer_stack[buffer_ptr].file_in = None
268             yyin = yy_buffer_stack[-1].file_in
269             buffer_ptr -= 1
270             if buffer_ptr < 0:
271               break # EOF
272             block_prev = yy_buffer_stack[buffer_ptr]
273             block = block_prev.next
274             if block is not None:
275               block_pos = block.pos
276         else:
277           i = match_len - len(match)
278           if i:
279             match += block.text[block_pos - i:]
280           block_prev = block
281           block = block_prev.next
282           if block is not None:
283             block_pos = block.pos
284       else: 
285         #print('block_pos', block_pos, 'block.text', block.text)
286         action = yy_dfa_states[state][1][
287           bisect.bisect_right(
288             yy_dfa_states[state][0],
289             ord(block.text[block_pos])
290           )
291         ]
292         block_pos += 1
293         match_len += 1
294         continue
295       # EOF
296       if i == 0:
297         try:
298           return yy_eof_actions[yystart]()
299         except YYTerminate:
300           return 0
301       break
302
303     i = match_len - len(match)
304     if i:
305       assert block is not None
306       match += block.text[block_pos - i:]
307
308     for i in yy_dfa_states[state][2]:
309       yy_group_text = match
310       yy_group_stack = []
311       yy_groups = None
312       yy_groups_by_name = None
313       yy_action = None
314       yytext = None
315       yytext_len = None
316       yy_element_stack = []
317
318       thread = yy_threads0[yy_prefix_slop + i]
319       #print('thread', thread)
320       while thread is not None:
321         pos, ref_data, thread = thread
322         yy_group_stack.append(pos)
323         ref_data()
324
325       yy_element_token = yy_group_element(
326         0,
327         yytext_len,
328         yy_element_stack.pop(),
329         _class,
330         *args,
331         **kwargs
332       )
333  
334       try:
335         return yy_action()
336       except YYReject:
337         pass
338       except YYContinue:
339         break
340       except YYTerminate:
341         return 0
342     else:
343       raise Exception('scanner jammed')
344
345     # append yy_element_token contents onto yy_element_space
346     assert len(yy_element_space.text) == len(yy_element_space.children) + 1
347     assert len(yy_element_token.text) == len(yy_element_token.children) + 1
348     yy_element_space.text[-1] += yy_element_token.text[0]
349     yy_element_space.children.extend(yy_element_token.children)
350     yy_element_space.text.extend(yy_element_token.text[1:])
351  
352     # clear yy_element_token for next yytext or EOF action
353     del yy_element_token.text[1:]
354     del yy_element_token.children[:]
355
356 # GENERATE SECTION3