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.

74 lines
2.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, is_terminal
  10. from .grammar_analysis import GrammarAnalyzer
  11. ACTION_SHIFT = 0
  12. class LALR_Analyzer(GrammarAnalyzer):
  13. def compute_lookahead(self):
  14. self.states = {}
  15. def step(state):
  16. lookahead = defaultdict(list)
  17. sat, unsat = classify_bool(state, lambda rp: rp.is_satisfied)
  18. for rp in sat:
  19. for term in self.FOLLOW.get(rp.rule.origin, ()):
  20. lookahead[term].append(('reduce', rp.rule))
  21. d = classify(unsat, lambda rp: rp.next)
  22. for sym, rps in d.items():
  23. rps = {rp.advance(sym) for rp in rps}
  24. for rp in set(rps):
  25. if not rp.is_satisfied and not is_terminal(rp.next):
  26. rps |= self.expand_rule(rp.next)
  27. lookahead[sym].append(('shift', fzset(rps)))
  28. yield fzset(rps)
  29. for k, v in lookahead.items():
  30. if len(v) > 1:
  31. if self.debug:
  32. logging.warn("Shift/reduce conflict for %s: %s. Resolving as shift.", k, v)
  33. for x in v:
  34. # XXX resolving shift/reduce into shift, like PLY
  35. # Give a proper warning
  36. if x[0] == 'shift':
  37. lookahead[k] = [x]
  38. for k, v in lookahead.items():
  39. if not len(v) == 1:
  40. raise GrammarError("Collision in %s: %s" %(k, v))
  41. self.states[state] = {k:v[0] for k, v in lookahead.items()}
  42. for _ in bfs([self.init_state], step):
  43. pass
  44. # --
  45. self.enum = list(self.states)
  46. self.enum_rev = {s:i for i,s in enumerate(self.enum)}
  47. self.states_idx = {}
  48. for s, la in self.states.items():
  49. la = {k:(ACTION_SHIFT, self.enum_rev[v[1]]) if v[0]=='shift'
  50. else (v[0], (v[1], len(v[1].expansion))) # Reduce
  51. for k,v in la.items()}
  52. self.states_idx[ self.enum_rev[s] ] = la
  53. self.init_state_idx = self.enum_rev[self.init_state]