1 # Copyright (C) 2019 Nick Downing <nick@ndcode.org>
2 # SPDX-License-Identifier: GPL-2.0-with-bison-exception
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.
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
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
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
29 from ndcode.pilex import element
33 # GENERATE STARTCONDDECL
35 class YYReject(Exception):
38 class YYContinue(Exception):
41 class YYTerminate(Exception):
45 def __init__(self, next = None):
48 class YYBufferBlock(YYBufferList):
49 def __init__(self, next = None, pos = 0, text = ''):
50 YYBufferList.__init__(self, next)
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
62 yy_buffer_stack = [YYBufferState()]
73 yy_groups_by_name = None
78 yy_element_stack = None
79 yy_element_token = None
80 yy_element_space = None
91 global yytext, yytext_len
92 assert yytext_len >= i
97 global yyin, yytext_len
99 block = yy_buffer_stack[-1].next
100 while block is None or block.pos >= len(block.text):
102 yy_buffer_stack.pop()
103 block = yy_buffer_stack[-1].next
104 yyin = yy_buffer_stack[-1].file_in
107 yy_buffer_stack[-1].next = block
108 i = min(yytext_len, len(block.text) - block.pos)
111 yy_buffer_stack[-1].next = YYBufferBlock(yy_buffer_stack[-1].next, 0, text)
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:
125 yy_buffer_stack[-1].at_bol = yytext[-1] == '\n'
126 yy_element_stack.append([])
131 def yy_group_end_element():
132 yy_element_stack.append([])
134 def yy_group_element(pos0, pos1, stack, _class, *args, **kwargs):
135 _element = _class(*args, **kwargs)
137 for pos2, pos3, i in reversed(stack):
138 _element.text.append(yy_group_text[pos0:pos2])
139 _element.children.append(i)
141 _element.text.append(yy_group_text[pos0:pos1])
151 def yy_push_state(start):
153 yystart_stack.append(yystart)
158 yystart = yystart_stack.pop()
161 return yy_buffer_stack[-1].at_bol
163 def yy_set_bol(at_bol):
164 yy_buffer_stack[-1].at_bol = at_bol
168 def yylex(_class = element.Element, *args, **kwargs):
183 # GENERATE SECTION2INITIAL
185 yy_element_space = _class(*args, **kwargs)
186 yy_element_token = _class(*args, **kwargs)
189 block = yy_buffer_stack[-1].next
190 while block is None or block.pos >= len(block.text):
192 yy_buffer_stack.pop()
193 block = yy_buffer_stack[-1].next
194 yyin = yy_buffer_stack[-1].file_in
197 yy_buffer_stack[-1].next = block
198 i = min(yytext_len, len(block.text) - block.pos)
205 del yy_threads0[yy_prefix_slop:]
206 yy_threads0.append(None)
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
214 action = yy_dfa_start_action[
215 yystart * 2 + int(yy_buffer_stack[-1].at_bol)
218 state, transition = yy_dfa_actions[action]
219 #print('i', i, 'action', action, 'state', state, 'transition', transition)
222 assert len(yy_threads1) == yy_prefix_slop
223 for trans in transition:
224 if trans[0] == 0: #DFA.TRANSITION_POP:
226 elif trans[0] == 1: #DFA.TRANSITION_DUP:
228 yy_threads0[:0] = [None] * yy_prefix_slop
229 yy_threads1[:0] = [None] * yy_prefix_slop
232 yy_threads0[i - trans[1]:i] = yy_threads0[i: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]]
239 elif trans[0] == 3: #DFA.TRANSITION_MOVE:
240 yy_threads1.extend(yy_threads0[i:i + trans[1]])
242 #elif trans[0] == DFA.TRANSITION_DEL:
243 # del yy_threads1[-trans[1]:]
246 assert i == len(yy_threads0)
247 yy_threads0, yy_threads1 = yy_threads1, yy_threads0
248 del yy_threads1[yy_prefix_slop:]
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]
256 yy_buffer_stack[-1].file_in = yyin
257 while block is None or block_pos >= len(block.text):
259 file_in = yy_buffer_stack[buffer_ptr].file_in
260 text = '' if file_in is None else file_in.readline()
262 block = YYBufferBlock(None, 0, text)
264 block_prev.next = block
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
272 block_prev = yy_buffer_stack[buffer_ptr]
273 block = block_prev.next
274 if block is not None:
275 block_pos = block.pos
277 i = match_len - len(match)
279 match += block.text[block_pos - i:]
281 block = block_prev.next
282 if block is not None:
283 block_pos = block.pos
285 #print('block_pos', block_pos, 'block.text', block.text)
286 action = yy_dfa_states[state][1][
288 yy_dfa_states[state][0],
289 ord(block.text[block_pos])
298 return yy_eof_actions[yystart]()
303 i = match_len - len(match)
305 assert block is not None
306 match += block.text[block_pos - i:]
308 for i in yy_dfa_states[state][2]:
309 yy_group_text = match
312 yy_groups_by_name = None
316 yy_element_stack = []
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)
325 yy_element_token = yy_group_element(
328 yy_element_stack.pop(),
343 raise Exception('scanner jammed')
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:])
352 # clear yy_element_token for next yytext or EOF action
353 del yy_element_token.text[1:]
354 del yy_element_token.children[:]