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.

93 lines
2.9 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 .lalr_analysis import LALR_Analyzer, Shift
  8. class Parser:
  9. def __init__(self, parser_conf):
  10. assert all(r.options is None or r.options.priority is None
  11. for r in parser_conf.rules), "LALR doesn't yet support prioritization"
  12. analysis = LALR_Analyzer(parser_conf)
  13. analysis.compute_lookahead()
  14. callbacks = {rule: getattr(parser_conf.callback, rule.alias or rule.origin, None)
  15. for rule in parser_conf.rules}
  16. self._parse_table = analysis.parse_table
  17. self.parser_conf = parser_conf
  18. self.parser = _Parser(analysis.parse_table, callbacks)
  19. self.parse = self.parser.parse
  20. ###{standalone
  21. class _Parser:
  22. def __init__(self, parse_table, callbacks):
  23. self.states = parse_table.states
  24. self.start_state = parse_table.start_state
  25. self.end_state = parse_table.end_state
  26. self.callbacks = callbacks
  27. def parse(self, seq, set_state=None):
  28. i = 0
  29. token = None
  30. stream = iter(seq)
  31. states = self.states
  32. state_stack = [self.start_state]
  33. value_stack = []
  34. if set_state: set_state(self.start_state)
  35. def get_action(key):
  36. state = state_stack[-1]
  37. try:
  38. return states[state][key]
  39. except KeyError:
  40. expected = [s for s in states[state].keys() if s.isupper()]
  41. raise UnexpectedToken(token, expected, state=state) # TODO filter out rules from expected
  42. def reduce(rule):
  43. size = len(rule.expansion)
  44. if size:
  45. s = value_stack[-size:]
  46. del state_stack[-size:]
  47. del value_stack[-size:]
  48. else:
  49. s = []
  50. value = self.callbacks[rule](s)
  51. _action, new_state = get_action(rule.origin.name)
  52. assert _action is Shift
  53. state_stack.append(new_state)
  54. value_stack.append(value)
  55. # Main LALR-parser loop
  56. for i, token in enumerate(stream):
  57. while True:
  58. action, arg = get_action(token.type)
  59. assert arg != self.end_state
  60. if action is Shift:
  61. state_stack.append(arg)
  62. value_stack.append(token)
  63. if set_state: set_state(arg)
  64. break # next token
  65. else:
  66. reduce(arg)
  67. token = Token.new_borrow_pos('<EOF>', token, token) if token else Token('<EOF>', '', 0, 1, 1)
  68. while True:
  69. _action, arg = get_action('$END')
  70. if _action is Shift:
  71. assert arg == self.end_state
  72. val ,= value_stack
  73. return val
  74. else:
  75. reduce(arg)
  76. ###}