This repo contains code to mirror other repos. It also contains the code that is getting mirrored.
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

110 wiersze
3.4 KiB

  1. """This module builds a LALR(1) transition-table for lalr_parser.py
  2. For now, shift/reduce conflicts are automatically resolved as shifts.
  3. """
  4. # Author: Erez Shinan (2017)
  5. # Email : erezshin@gmail.com
  6. import logging
  7. from collections import defaultdict
  8. from ..utils import classify, classify_bool, bfs, fzset
  9. from ..common import GrammarError
  10. from .grammar_analysis import GrammarAnalyzer, Terminal
  11. class Action:
  12. def __init__(self, name):
  13. self.name = name
  14. def __str__(self):
  15. return self.name
  16. def __repr__(self):
  17. return str(self)
  18. Shift = Action('Shift')
  19. Reduce = Action('Reduce')
  20. class ParseTable:
  21. def __init__(self, states, start_state, end_state):
  22. self.states = states
  23. self.start_state = start_state
  24. self.end_state = end_state
  25. class IntParseTable(ParseTable):
  26. @classmethod
  27. def from_ParseTable(cls, parse_table):
  28. enum = list(parse_table.states)
  29. state_to_idx = {s:i for i,s in enumerate(enum)}
  30. int_states = {}
  31. for s, la in parse_table.states.items():
  32. la = {k:(v[0], state_to_idx[v[1]]) if v[0] is Shift else v
  33. for k,v in la.items()}
  34. int_states[ state_to_idx[s] ] = la
  35. start_state = state_to_idx[parse_table.start_state]
  36. end_state = state_to_idx[parse_table.end_state]
  37. return cls(int_states, start_state, end_state)
  38. class LALR_Analyzer(GrammarAnalyzer):
  39. def compute_lookahead(self):
  40. self.end_states = []
  41. self.states = {}
  42. def step(state):
  43. lookahead = defaultdict(list)
  44. sat, unsat = classify_bool(state, lambda rp: rp.is_satisfied)
  45. for rp in sat:
  46. for term in self.FOLLOW.get(rp.rule.origin, ()):
  47. lookahead[term].append((Reduce, rp.rule))
  48. d = classify(unsat, lambda rp: rp.next)
  49. for sym, rps in d.items():
  50. rps = {rp.advance(sym) for rp in rps}
  51. for rp in set(rps):
  52. if not rp.is_satisfied and not rp.next.is_term:
  53. rps |= self.expand_rule(rp.next)
  54. new_state = fzset(rps)
  55. lookahead[sym].append((Shift, new_state))
  56. if sym == Terminal('$END'):
  57. self.end_states.append( new_state )
  58. yield new_state
  59. for k, v in lookahead.items():
  60. if len(v) > 1:
  61. if self.debug:
  62. logging.warn("Shift/reduce conflict for %s: %s. Resolving as shift.", k, v)
  63. for x in v:
  64. # XXX resolving shift/reduce into shift, like PLY
  65. # Give a proper warning
  66. if x[0] is Shift:
  67. lookahead[k] = [x]
  68. for k, v in lookahead.items():
  69. if not len(v) == 1:
  70. raise GrammarError("Collision in %s: %s" %(k, ', '.join(['\n * %s: %s' % x for x in v])))
  71. self.states[state] = {k.name:v[0] for k, v in lookahead.items()}
  72. for _ in bfs([self.start_state], step):
  73. pass
  74. self.end_state ,= self.end_states
  75. self._parse_table = ParseTable(self.states, self.start_state, self.end_state)
  76. if self.debug:
  77. self.parse_table = self._parse_table
  78. else:
  79. self.parse_table = IntParseTable.from_ParseTable(self._parse_table)