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.

71 lines
2.0 KiB

  1. from .lalr_analysis import ACTION_SHIFT
  2. from ..common import ParseError, UnexpectedToken
  3. class Parser(object):
  4. def __init__(self, analysis, callback):
  5. self.analysis = analysis
  6. self.callbacks = {rule: getattr(callback, rule.alias or rule.origin, None)
  7. for rule in analysis.rules}
  8. def parse(self, seq):
  9. states_idx = self.analysis.states_idx
  10. state_stack = [self.analysis.init_state_idx]
  11. value_stack = []
  12. i = 0
  13. def get_action(key):
  14. state = state_stack[-1]
  15. try:
  16. return states_idx[state][key]
  17. except KeyError:
  18. expected = states_idx[state].keys()
  19. try:
  20. token = seq[i]
  21. except IndexError:
  22. assert key == '$end'
  23. token = seq[-1]
  24. raise UnexpectedToken(token, expected, seq, i)
  25. def reduce(rule, size):
  26. if size:
  27. s = value_stack[-size:]
  28. del state_stack[-size:]
  29. del value_stack[-size:]
  30. else:
  31. s = []
  32. res = self.callbacks[rule](s)
  33. if len(state_stack) == 1 and rule.origin == self.analysis.start_symbol:
  34. return res
  35. _action, new_state = get_action(rule.origin)
  36. assert _action == ACTION_SHIFT
  37. state_stack.append(new_state)
  38. value_stack.append(res)
  39. # Main LALR-parser loop
  40. while i < len(seq):
  41. action, arg = get_action(seq[i].type)
  42. if action == ACTION_SHIFT:
  43. state_stack.append(arg)
  44. value_stack.append(seq[i])
  45. i+= 1
  46. else:
  47. reduce(*arg)
  48. while True:
  49. _action, rule = get_action('$end')
  50. assert _action == 'reduce'
  51. res = reduce(*rule)
  52. if res:
  53. assert state_stack == [self.analysis.init_state_idx] and not value_stack, len(state_stack)
  54. return res