This repo contains code to mirror other repos. It also contains the code that is getting mirrored.
Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.

201 righe
6.8 KiB

  1. """This module implements a LALR(1) Parser
  2. """
  3. # Author: Erez Shinan (2017)
  4. # Email : erezshin@gmail.com
  5. from copy import deepcopy, copy
  6. from ..exceptions import UnexpectedInput, UnexpectedToken
  7. from ..lexer import Token
  8. from ..utils import Serialize
  9. from .lalr_analysis import LALR_Analyzer, Shift, Reduce, IntParseTable
  10. from .lalr_interactive_parser import InteractiveParser
  11. from lark.exceptions import UnexpectedCharacters, UnexpectedInput, UnexpectedToken
  12. ###{standalone
  13. class LALR_Parser(Serialize):
  14. def __init__(self, parser_conf, debug=False):
  15. analysis = LALR_Analyzer(parser_conf, debug=debug)
  16. analysis.compute_lalr()
  17. callbacks = parser_conf.callbacks
  18. self._parse_table = analysis.parse_table
  19. self.parser_conf = parser_conf
  20. self.parser = _Parser(analysis.parse_table, callbacks, debug)
  21. @classmethod
  22. def deserialize(cls, data, memo, callbacks, debug=False):
  23. inst = cls.__new__(cls)
  24. inst._parse_table = IntParseTable.deserialize(data, memo)
  25. inst.parser = _Parser(inst._parse_table, callbacks, debug)
  26. return inst
  27. def serialize(self, memo):
  28. return self._parse_table.serialize(memo)
  29. def parse_interactive(self, lexer, start):
  30. return self.parser.parse(lexer, start, start_interactive=True)
  31. def parse(self, lexer, start, on_error=None):
  32. try:
  33. return self.parser.parse(lexer, start)
  34. except UnexpectedInput as e:
  35. if on_error is None:
  36. raise
  37. while True:
  38. if isinstance(e, UnexpectedCharacters):
  39. s = e.interactive_parser.lexer_state.state
  40. p = s.line_ctr.char_pos
  41. if not on_error(e):
  42. raise e
  43. if isinstance(e, UnexpectedCharacters):
  44. # If user didn't change the character position, then we should
  45. if p == s.line_ctr.char_pos:
  46. s.line_ctr.feed(s.text[p:p+1])
  47. try:
  48. return e.interactive_parser.resume_parse()
  49. except UnexpectedToken as e2:
  50. if (isinstance(e, UnexpectedToken)
  51. and e.token.type == e2.token.type == '$END'
  52. and e.interactive_parser == e2.interactive_parser):
  53. # Prevent infinite loop
  54. raise e2
  55. e = e2
  56. except UnexpectedCharacters as e2:
  57. e = e2
  58. class ParseConf(object):
  59. __slots__ = 'parse_table', 'callbacks', 'start', 'start_state', 'end_state', 'states'
  60. def __init__(self, parse_table, callbacks, start):
  61. self.parse_table = parse_table
  62. self.start_state = self.parse_table.start_states[start]
  63. self.end_state = self.parse_table.end_states[start]
  64. self.states = self.parse_table.states
  65. self.callbacks = callbacks
  66. self.start = start
  67. class ParserState(object):
  68. __slots__ = 'parse_conf', 'lexer', 'state_stack', 'value_stack'
  69. def __init__(self, parse_conf, lexer, state_stack=None, value_stack=None):
  70. self.parse_conf = parse_conf
  71. self.lexer = lexer
  72. self.state_stack = state_stack or [self.parse_conf.start_state]
  73. self.value_stack = value_stack or []
  74. @property
  75. def position(self):
  76. return self.state_stack[-1]
  77. # Necessary for match_examples() to work
  78. def __eq__(self, other):
  79. if not isinstance(other, ParserState):
  80. return NotImplemented
  81. return len(self.state_stack) == len(other.state_stack) and self.position == other.position
  82. def __copy__(self):
  83. return type(self)(
  84. self.parse_conf,
  85. self.lexer, # XXX copy
  86. copy(self.state_stack),
  87. deepcopy(self.value_stack),
  88. )
  89. def copy(self):
  90. return copy(self)
  91. def feed_token(self, token, is_end=False):
  92. state_stack = self.state_stack
  93. value_stack = self.value_stack
  94. states = self.parse_conf.states
  95. end_state = self.parse_conf.end_state
  96. callbacks = self.parse_conf.callbacks
  97. while True:
  98. state = state_stack[-1]
  99. try:
  100. action, arg = states[state][token.type]
  101. except KeyError:
  102. expected = {s for s in states[state].keys() if s.isupper()}
  103. raise UnexpectedToken(token, expected, state=self, interactive_parser=None)
  104. assert arg != end_state
  105. if action is Shift:
  106. # shift once and return
  107. assert not is_end
  108. state_stack.append(arg)
  109. value_stack.append(token if token.type not in callbacks else callbacks[token.type](token))
  110. return
  111. else:
  112. # reduce+shift as many times as necessary
  113. rule = arg
  114. size = len(rule.expansion)
  115. if size:
  116. s = value_stack[-size:]
  117. del state_stack[-size:]
  118. del value_stack[-size:]
  119. else:
  120. s = []
  121. value = callbacks[rule](s)
  122. _action, new_state = states[state_stack[-1]][rule.origin.name]
  123. assert _action is Shift
  124. state_stack.append(new_state)
  125. value_stack.append(value)
  126. if is_end and state_stack[-1] == end_state:
  127. return value_stack[-1]
  128. class _Parser(object):
  129. def __init__(self, parse_table, callbacks, debug=False):
  130. self.parse_table = parse_table
  131. self.callbacks = callbacks
  132. self.debug = debug
  133. def parse(self, lexer, start, value_stack=None, state_stack=None, start_interactive=False):
  134. parse_conf = ParseConf(self.parse_table, self.callbacks, start)
  135. parser_state = ParserState(parse_conf, lexer, state_stack, value_stack)
  136. if start_interactive:
  137. return InteractiveParser(self, parser_state, parser_state.lexer)
  138. return self.parse_from_state(parser_state)
  139. def parse_from_state(self, state):
  140. # Main LALR-parser loop
  141. try:
  142. token = None
  143. for token in state.lexer.lex(state):
  144. state.feed_token(token)
  145. end_token = Token.new_borrow_pos('$END', '', token) if token else Token('$END', '', 0, 1, 1)
  146. return state.feed_token(end_token, True)
  147. except UnexpectedInput as e:
  148. try:
  149. e.interactive_parser = InteractiveParser(self, state, state.lexer)
  150. except NameError:
  151. pass
  152. raise e
  153. except Exception as e:
  154. if self.debug:
  155. print("")
  156. print("STATE STACK DUMP")
  157. print("----------------")
  158. for i, s in enumerate(state.state_stack):
  159. print('%d)' % i , s)
  160. print("")
  161. raise
  162. ###}