"""This module implements a LALR(1) Parser """ # Author: Erez Shinan (2017) # Email : erezshin@gmail.com from ..exceptions import UnexpectedToken from ..lexer import Token from ..utils import Enumerator, Serialize from .lalr_analysis import LALR_Analyzer, Shift, Reduce, IntParseTable from .lalr_puppet import ParserPuppet ###{standalone class LALR_Parser(object): def __init__(self, parser_conf, debug=False): analysis = LALR_Analyzer(parser_conf, debug=debug) analysis.compute_lalr() callbacks = parser_conf.callbacks self._parse_table = analysis.parse_table self.parser_conf = parser_conf self.parser = _Parser(analysis.parse_table, callbacks, debug) @classmethod def deserialize(cls, data, memo, callbacks, debug=False): inst = cls.__new__(cls) inst._parse_table = IntParseTable.deserialize(data, memo) inst.parser = _Parser(inst._parse_table, callbacks, debug) return inst def serialize(self, memo): return self._parse_table.serialize(memo) def parse(self, *args): return self.parser.parse(*args) class _Parser: def __init__(self, parse_table, callbacks, debug=False): self.parse_table = parse_table self.callbacks = callbacks self.debug = debug def parse(self, seq, start, set_state=None, value_stack=None, state_stack=None): token = None stream = iter(seq) states = self.parse_table.states start_state = self.parse_table.start_states[start] end_state = self.parse_table.end_states[start] state_stack = state_stack or [start_state] value_stack = value_stack or [] if set_state: set_state(start_state) def get_action(token): state = state_stack[-1] try: return states[state][token.type] except KeyError: expected = {s for s in states[state].keys() if s.isupper()} try: puppet = ParserPuppet(self, state_stack, value_stack, start, stream, set_state) except NameError: # For standalone parser puppet = None raise UnexpectedToken(token, expected, state=state, puppet=puppet) def reduce(rule): size = len(rule.expansion) if size: s = value_stack[-size:] del state_stack[-size:] del value_stack[-size:] else: s = [] value = self.callbacks[rule](s) _action, new_state = states[state_stack[-1]][rule.origin.name] assert _action is Shift state_stack.append(new_state) value_stack.append(value) # Main LALR-parser loop try: for token in stream: while True: action, arg = get_action(token) assert arg != end_state if action is Shift: state_stack.append(arg) value_stack.append(token) if set_state: set_state(arg) break # next token else: reduce(arg) except Exception as e: if self.debug: print("") print("STATE STACK DUMP") print("----------------") for i, s in enumerate(state_stack): print('%d)' % i , s) print("") raise token = Token.new_borrow_pos('$END', '', token) if token else Token('$END', '', 0, 1, 1) while True: _action, arg = get_action(token) assert(_action is Reduce) reduce(arg) if state_stack[-1] == end_state: return value_stack[-1] ###}