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.

70 lines
2.1 KiB

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