Make syntax error call yyerror() rather than raising a Python exception
[piyacc.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.piyacc import element
30
31 # this can be redefined in SECTION1
32 def YY_AT_BOL():
33   return yy_buffer_stack[-1].at_bol
34
35 def yy_set_bol(at_bol):
36   yy_buffer_stack[-1].at_bol = at_bol
37
38 def YY_USER_ACTION():
39   pass
40
41 def YY_RULE_START():
42   # note that this should also be done after yyless() and REJECT(),
43   # and state should be saved in case they result in a null string,
44   # however, it doesn't seem to be in flex, maintain compatibility:
45   if len(yytext):
46     yy_set_bol(yytext[-1] == '\n')
47   YY_USER_ACTION()
48
49 # GENERATE SECTION1
50
51 # GENERATE STARTCONDDECL
52
53 class YYReject(Exception):
54   pass
55
56 class YYContinue(Exception):
57   pass
58
59 class YYTerminate(Exception):
60   pass
61
62 class YYBufferList:
63   def __init__(self, next = None):
64     self.next = next
65
66 class YYBufferBlock(YYBufferList):
67   def __init__(self, next = None, pos = 0, text = ''):
68     YYBufferList.__init__(self, next)
69     self.pos = pos
70     self.text = text
71
72 class YYBufferState(YYBufferList):
73   def __init__(self, next = None, file_in = None, at_bol = True):
74     YYBufferList.__init__(self, next)
75     self.file_in = file_in
76     self.at_bol = at_bol
77
78 yyin = sys.stdin
79 yyout = sys.stdout
80 yy_buffer_stack = [YYBufferState()]
81
82 yystart = INITIAL
83 yystart_stack = []
84 yy_threads0 = [None]
85 yy_threads1 = [None]
86 yy_prefix_slop = 1
87
88 yy_group_text = None
89 yy_group_stack = None
90 yy_groups = None
91 yy_groups_by_name = None
92 yy_action = None
93 yytext = ''
94 yytext_len = 0
95
96 yy_element_stack = None
97 yy_element_token = None
98 yy_element_space = None
99
100 YY_NULL = 0
101
102 def REJECT():
103   raise YYReject()
104
105 def yyterminate():
106   raise YYTerminate()
107
108 def yyless(i):
109   global yytext, yytext_len
110   assert yytext_len >= i
111   yytext = yytext[:i]
112   yytext_len = i
113
114 def unput(text):
115   global yyin, yytext_len
116   while yytext_len:
117     block = yy_buffer_stack[-1].next
118     while block is None or block.pos >= len(block.text):
119       if block is None:
120         yy_buffer_stack.pop()
121         block = yy_buffer_stack[-1].next
122         yyin = yy_buffer_stack[-1].file_in
123       else:
124         block = block.next
125         yy_buffer_stack[-1].next = block
126     i = min(yytext_len, len(block.text) - block.pos)
127     block.pos += i
128     yytext_len -= i
129   yy_buffer_stack[-1].next = YYBufferBlock(yy_buffer_stack[-1].next, 0, text)
130
131 def ECHO():
132   yyout.write(yytext)
133
134 def yy_rule_start():
135   global yytext, yytext_len, yy_element_stack
136   yytext = yy_group_text[:yy_group_stack[-1]]
137   yytext_len = yy_group_stack[-1]
138   del yy_group_stack[-2:]
139   YY_RULE_START()
140   yy_element_stack.append([])
141
142 def yy_group_end():
143   pass
144
145 def yy_group_end_element():
146   yy_element_stack.append([])
147
148 def yy_group_element(pos0, pos1, stack, _class, *args, **kwargs):
149   _element = _class(*args, **kwargs)
150   del _element.text[:]
151   for pos2, pos3, i in reversed(stack):
152     _element.text.append(yy_group_text[pos0:pos2])
153     _element.children.append(i)
154     pos0 = pos3
155   _element.text.append(yy_group_text[pos0:pos1])
156   return _element
157
158 def BEGIN(start):
159   global yystart
160   yystart = start
161
162 def YY_START():
163   return yystart
164
165 def yy_push_state(start):
166   global yystart
167   yystart_stack.append(yystart)
168   yystart = start
169
170 def yy_pop_state():
171   global yystart
172   yystart = yystart_stack.pop()
173
174 # GENERATE SECTION2
175
176 def yylex(_class = element.Element, *args, **kwargs):
177   global \
178     yyin, \
179     yy_threads0, \
180     yy_threads1, \
181     yy_prefix_slop, \
182     yy_group_text, \
183     yy_group_stack, \
184     yy_action, \
185     yytext, \
186     yytext_len, \
187     yy_element_stack, \
188     yy_element_token, \
189     yy_element_space
190
191   # GENERATE SECTION2INITIAL
192
193   yy_element_space = _class(*args, **kwargs)
194   yy_element_token = _class(*args, **kwargs)
195   while True:
196     while yytext_len:
197       block = yy_buffer_stack[-1].next
198       while block is None or block.pos >= len(block.text):
199         if block is None:
200           yy_buffer_stack.pop()
201           block = yy_buffer_stack[-1].next
202           yyin = yy_buffer_stack[-1].file_in
203         else:
204           block = block.next
205           yy_buffer_stack[-1].next = block
206       i = min(yytext_len, len(block.text) - block.pos)
207       block.pos += i
208       yytext_len -= i
209
210     match = ''
211     match_len = 0
212
213     del yy_threads0[yy_prefix_slop:]
214     yy_threads0.append(None)
215
216     buffer_ptr = len(yy_buffer_stack) - 1
217     block_prev = yy_buffer_stack[buffer_ptr]
218     block = block_prev.next
219     if block is not None:
220       block_pos = block.pos
221
222     action = yy_dfa_start_action[
223       yystart * 2 + int(yy_buffer_stack[-1].at_bol)
224     ]
225     while action != -1:
226       state, transition = yy_dfa_actions[action]
227       #print('i', i, 'action', action, 'state', state, 'transition', transition)
228
229       i = yy_prefix_slop
230       assert len(yy_threads1) == yy_prefix_slop
231       for trans in transition:
232         if trans[0] == 0: #DFA.TRANSITION_POP:
233           i += trans[1]
234         elif trans[0] == 1: #DFA.TRANSITION_DUP:
235           while i < trans[1]:
236             yy_threads0[:0] = [None] * yy_prefix_slop
237             yy_threads1[:0] = [None] * yy_prefix_slop
238             i += yy_prefix_slop
239             yy_prefix_slop *= 2
240           yy_threads0[i - trans[1]:i] = yy_threads0[i:i + trans[1]]
241           i -= trans[1]
242         elif trans[0] == 2: #DFA.TRANSITION_MARK:
243           yy_threads0[i:i + trans[1]] = [
244             (match_len, trans[2], thread)
245             for thread in yy_threads0[i:i + trans[1]]
246           ]
247         elif trans[0] == 3: #DFA.TRANSITION_MOVE:
248           yy_threads1.extend(yy_threads0[i:i + trans[1]])
249           i += trans[1]
250         #elif trans[0] == DFA.TRANSITION_DEL:
251         #  del yy_threads1[-trans[1]:]
252         else:
253           assert False
254       assert i == len(yy_threads0)
255       yy_threads0, yy_threads1 = yy_threads1, yy_threads0
256       del yy_threads1[yy_prefix_slop:]
257
258       if state == 0:
259         # there is only one match, which is complete
260         assert len(yy_threads0) == yy_prefix_slop + 1
261         assert yy_dfa_states[state][2] == [0]
262         break
263
264       yy_buffer_stack[-1].file_in = yyin
265       while block is None or block_pos >= len(block.text):
266         if block is None:
267           file_in = yy_buffer_stack[buffer_ptr].file_in
268           text = '' if file_in is None else file_in.readline()
269           if len(text):
270             block = YYBufferBlock(None, 0, text)
271             block_pos = 0
272             block_prev.next = block
273           else:
274             # do not re-attempt read once EOF is reached
275             yy_buffer_stack[buffer_ptr].file_in = None
276             yyin = yy_buffer_stack[-1].file_in
277             buffer_ptr -= 1
278             if buffer_ptr < 0:
279               break # EOF
280             block_prev = yy_buffer_stack[buffer_ptr]
281             block = block_prev.next
282             if block is not None:
283               block_pos = block.pos
284         else:
285           i = match_len - len(match)
286           if i:
287             match += block.text[block_pos - i:]
288           block_prev = block
289           block = block_prev.next
290           if block is not None:
291             block_pos = block.pos
292       else: 
293         #print('block_pos', block_pos, 'block.text', block.text)
294         action = yy_dfa_states[state][1][
295           bisect.bisect_right(
296             yy_dfa_states[state][0],
297             ord(block.text[block_pos])
298           )
299         ]
300         block_pos += 1
301         match_len += 1
302         continue
303       # EOF
304       if i == 0:
305         try:
306           return yy_eof_actions[yystart]()
307         except YYTerminate:
308           return 0
309       break
310
311     i = match_len - len(match)
312     if i:
313       assert block is not None
314       match += block.text[block_pos - i:]
315
316     for i in yy_dfa_states[state][2]:
317       yy_group_text = match
318       yy_group_stack = []
319       yy_groups = None
320       yy_groups_by_name = None
321       yy_action = None
322       yytext = None
323       yytext_len = None
324       yy_element_stack = []
325
326       thread = yy_threads0[yy_prefix_slop + i]
327       #print('thread', thread)
328       while thread is not None:
329         pos, ref_data, thread = thread
330         yy_group_stack.append(pos)
331         ref_data()
332
333       yy_element_token = yy_group_element(
334         0,
335         yytext_len,
336         yy_element_stack.pop(),
337         _class,
338         *args,
339         **kwargs
340       )
341  
342       try:
343         return yy_action()
344       except YYReject:
345         pass
346       except YYContinue:
347         break
348       except YYTerminate:
349         return 0
350     else:
351       raise Exception('scanner jammed')
352
353     # append yy_element_token contents onto yy_element_space
354     assert len(yy_element_space.text) == len(yy_element_space.children) + 1
355     assert len(yy_element_token.text) == len(yy_element_token.children) + 1
356     yy_element_space.text[-1] += yy_element_token.text[0]
357     yy_element_space.children.extend(yy_element_token.children)
358     yy_element_space.text.extend(yy_element_token.text[1:])
359  
360     # clear yy_element_token for next yytext or EOF action
361     del yy_element_token.text[1:]
362     del yy_element_token.children[:]
363
364 # GENERATE SECTION3