This repo contains code to mirror other repos. It also contains the code that is getting mirrored.
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

84 lines
2.6 KiB

  1. """This module implements a LALR(1) Parser
  2. """
  3. # Author: Erez Shinan (2017)
  4. # Email : erezshin@gmail.com
  5. from ..common import ParseError, UnexpectedToken
  6. from .lalr_analysis import LALR_Analyzer, ACTION_SHIFT
  7. class Parser(object):
  8. def __init__(self, parser_conf):
  9. assert all(o is None or o.priority is None for n,x,a,o in parser_conf.rules), "LALR doesn't yet support prioritization"
  10. self.analysis = LALR_Analyzer(parser_conf.rules, parser_conf.start)
  11. self.analysis.compute_lookahead()
  12. self.callbacks = {rule: getattr(parser_conf.callback, rule.alias or rule.origin, None)
  13. for rule in self.analysis.rules}
  14. def parse(self, seq, set_state=None):
  15. i = 0
  16. token = None
  17. stream = iter(seq)
  18. states_idx = self.analysis.states_idx
  19. state_stack = [self.analysis.init_state_idx]
  20. value_stack = []
  21. if set_state: set_state(self.analysis.init_state_idx)
  22. def get_action(key):
  23. state = state_stack[-1]
  24. try:
  25. return states_idx[state][key]
  26. except KeyError:
  27. expected = states_idx[state].keys()
  28. raise UnexpectedToken(token, expected, seq, i)
  29. def reduce(rule, size, end=False):
  30. if size:
  31. s = value_stack[-size:]
  32. del state_stack[-size:]
  33. del value_stack[-size:]
  34. else:
  35. s = []
  36. res = self.callbacks[rule](s)
  37. if end and len(state_stack) == 1 and rule.origin == self.analysis.start_symbol:
  38. return res
  39. _action, new_state = get_action(rule.origin)
  40. assert _action == ACTION_SHIFT
  41. state_stack.append(new_state)
  42. value_stack.append(res)
  43. # Main LALR-parser loop
  44. try:
  45. token = next(stream)
  46. i += 1
  47. while True:
  48. action, arg = get_action(token.type)
  49. if action == ACTION_SHIFT:
  50. state_stack.append(arg)
  51. value_stack.append(token)
  52. if set_state: set_state(arg)
  53. token = next(stream)
  54. i += 1
  55. else:
  56. reduce(*arg)
  57. except StopIteration:
  58. pass
  59. while True:
  60. _action, rule = get_action('$end')
  61. assert _action == 'reduce'
  62. res = reduce(*rule, end=True)
  63. if res:
  64. assert state_stack == [self.analysis.init_state_idx] and not value_stack, len(state_stack)
  65. return res