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.

98 lines
3.0 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 FinalReduce:
  8. def __init__(self, value):
  9. self.value = value
  10. class Parser:
  11. def __init__(self, parser_conf):
  12. 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"
  13. self.analysis = analysis = LALR_Analyzer(parser_conf.rules, parser_conf.start)
  14. analysis.compute_lookahead()
  15. callbacks = {rule: getattr(parser_conf.callback, rule.alias or rule.origin, None)
  16. for rule in analysis.rules}
  17. self.parser = _Parser(analysis.states_idx, analysis.init_state_idx, analysis.start_symbol, callbacks)
  18. self.parse = self.parser.parse
  19. class _Parser:
  20. def __init__(self, states, init_state, start_symbol, callbacks):
  21. self.states = states
  22. self.init_state = init_state
  23. self.start_symbol = start_symbol
  24. self.callbacks = callbacks
  25. def parse(self, seq, set_state=None):
  26. i = 0
  27. token = None
  28. stream = iter(seq)
  29. states = self.states
  30. state_stack = [self.init_state]
  31. value_stack = []
  32. if set_state: set_state(self.init_state)
  33. def get_action(key):
  34. state = state_stack[-1]
  35. try:
  36. return states[state][key]
  37. except KeyError:
  38. expected = states[state].keys()
  39. raise UnexpectedToken(token, expected, seq, i)
  40. def reduce(rule, size, end=False):
  41. if size:
  42. s = value_stack[-size:]
  43. del state_stack[-size:]
  44. del value_stack[-size:]
  45. else:
  46. s = []
  47. res = self.callbacks[rule](s)
  48. if end and len(state_stack) == 1 and rule.origin == self.start_symbol:
  49. return FinalReduce(res)
  50. _action, new_state = get_action(rule.origin)
  51. assert _action == ACTION_SHIFT
  52. state_stack.append(new_state)
  53. value_stack.append(res)
  54. # Main LALR-parser loop
  55. try:
  56. token = next(stream)
  57. i += 1
  58. while True:
  59. action, arg = get_action(token.type)
  60. if action == ACTION_SHIFT:
  61. state_stack.append(arg)
  62. value_stack.append(token)
  63. if set_state: set_state(arg)
  64. token = next(stream)
  65. i += 1
  66. else:
  67. reduce(*arg)
  68. except StopIteration:
  69. pass
  70. while True:
  71. _action, rule = get_action('$end')
  72. assert _action == 'reduce'
  73. res = reduce(*rule, end=True)
  74. if isinstance(res, FinalReduce):
  75. assert state_stack == [self.init_state] and not value_stack, len(state_stack)
  76. return res.value