This repo contains code to mirror other repos. It also contains the code that is getting mirrored.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

119 lines
3.8 KiB

  1. """This module implements a LALR(1) Parser
  2. """
  3. # Author: Erez Shinan (2017)
  4. # Email : erezshin@gmail.com
  5. from ..exceptions import UnexpectedToken
  6. from ..lexer import Token
  7. from ..utils import Enumerator, Serialize
  8. from .lalr_analysis import LALR_Analyzer, Shift, Reduce, IntParseTable
  9. from .lalr_puppet import ParserPuppet
  10. ###{standalone
  11. class LALR_Parser(object):
  12. def __init__(self, parser_conf, debug=False):
  13. analysis = LALR_Analyzer(parser_conf, debug=debug)
  14. analysis.compute_lalr()
  15. callbacks = parser_conf.callbacks
  16. self._parse_table = analysis.parse_table
  17. self.parser_conf = parser_conf
  18. self.parser = _Parser(analysis.parse_table, callbacks, debug)
  19. @classmethod
  20. def deserialize(cls, data, memo, callbacks, debug=False):
  21. inst = cls.__new__(cls)
  22. inst._parse_table = IntParseTable.deserialize(data, memo)
  23. inst.parser = _Parser(inst._parse_table, callbacks, debug)
  24. return inst
  25. def serialize(self, memo):
  26. return self._parse_table.serialize(memo)
  27. def parse(self, *args):
  28. return self.parser.parse(*args)
  29. class _Parser:
  30. def __init__(self, parse_table, callbacks, debug=False):
  31. self.parse_table = parse_table
  32. self.callbacks = callbacks
  33. self.debug = debug
  34. def parse(self, seq, start, set_state=None, value_stack=None, state_stack=None):
  35. token = None
  36. stream = iter(seq)
  37. states = self.parse_table.states
  38. start_state = self.parse_table.start_states[start]
  39. end_state = self.parse_table.end_states[start]
  40. state_stack = state_stack or [start_state]
  41. value_stack = value_stack or []
  42. if set_state: set_state(start_state)
  43. def get_action(token):
  44. state = state_stack[-1]
  45. try:
  46. return states[state][token.type]
  47. except KeyError:
  48. expected = {s for s in states[state].keys() if s.isupper()}
  49. try:
  50. puppet = ParserPuppet(self, state_stack, value_stack, start, stream, set_state)
  51. except NameError: # For standalone parser
  52. puppet = None
  53. raise UnexpectedToken(token, expected, state=state, puppet=puppet)
  54. def reduce(rule):
  55. size = len(rule.expansion)
  56. if size:
  57. s = value_stack[-size:]
  58. del state_stack[-size:]
  59. del value_stack[-size:]
  60. else:
  61. s = []
  62. value = self.callbacks[rule](s)
  63. _action, new_state = states[state_stack[-1]][rule.origin.name]
  64. assert _action is Shift
  65. state_stack.append(new_state)
  66. value_stack.append(value)
  67. # Main LALR-parser loop
  68. try:
  69. for token in stream:
  70. while True:
  71. action, arg = get_action(token)
  72. assert arg != end_state
  73. if action is Shift:
  74. state_stack.append(arg)
  75. value_stack.append(token)
  76. if set_state: set_state(arg)
  77. break # next token
  78. else:
  79. reduce(arg)
  80. except Exception as e:
  81. if self.debug:
  82. print("")
  83. print("STATE STACK DUMP")
  84. print("----------------")
  85. for i, s in enumerate(state_stack):
  86. print('%d)' % i , s)
  87. print("")
  88. raise
  89. token = Token.new_borrow_pos('$END', '', token) if token else Token('$END', '', 0, 1, 1)
  90. while True:
  91. _action, arg = get_action(token)
  92. assert(_action is Reduce)
  93. reduce(arg)
  94. if state_stack[-1] == end_state:
  95. return value_stack[-1]
  96. ###}