This repo contains code to mirror other repos. It also contains the code that is getting mirrored.
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 

108 řádky
3.3 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. class Action:
  12. def __str__(self):
  13. return self.__name__
  14. def __repr__(self):
  15. return str(self)
  16. class Shift(Action): pass
  17. class Reduce(Action): pass
  18. class ParseTable:
  19. def __init__(self, states, start_state, end_state):
  20. self.states = states
  21. self.start_state = start_state
  22. self.end_state = end_state
  23. class IntParseTable(ParseTable):
  24. @classmethod
  25. def from_ParseTable(cls, parse_table):
  26. enum = list(parse_table.states)
  27. state_to_idx = {s:i for i,s in enumerate(enum)}
  28. int_states = {}
  29. for s, la in parse_table.states.items():
  30. la = {k:(v[0], state_to_idx[v[1]]) if v[0] is Shift else v
  31. for k,v in la.items()}
  32. int_states[ state_to_idx[s] ] = la
  33. start_state = state_to_idx[parse_table.start_state]
  34. end_state = state_to_idx[parse_table.end_state]
  35. return cls(int_states, start_state, end_state)
  36. class LALR_Analyzer(GrammarAnalyzer):
  37. def compute_lookahead(self):
  38. self.end_states = []
  39. self.states = {}
  40. def step(state):
  41. lookahead = defaultdict(list)
  42. sat, unsat = classify_bool(state, lambda rp: rp.is_satisfied)
  43. for rp in sat:
  44. for term in self.FOLLOW.get(rp.rule.origin, ()):
  45. lookahead[term].append((Reduce, rp.rule))
  46. d = classify(unsat, lambda rp: rp.next)
  47. for sym, rps in d.items():
  48. rps = {rp.advance(sym) for rp in rps}
  49. for rp in set(rps):
  50. if not rp.is_satisfied and not is_terminal(rp.next):
  51. rps |= self.expand_rule(rp.next)
  52. new_state = fzset(rps)
  53. lookahead[sym].append((Shift, new_state))
  54. if sym == '$END':
  55. self.end_states.append( new_state )
  56. yield fzset(rps)
  57. for k, v in lookahead.items():
  58. if len(v) > 1:
  59. if self.debug:
  60. logging.warn("Shift/reduce conflict for %s: %s. Resolving as shift.", k, v)
  61. for x in v:
  62. # XXX resolving shift/reduce into shift, like PLY
  63. # Give a proper warning
  64. if x[0] is Shift:
  65. lookahead[k] = [x]
  66. for k, v in lookahead.items():
  67. if not len(v) == 1:
  68. raise GrammarError("Collision in %s: %s" %(k, v))
  69. self.states[state] = {k:v[0] for k, v in lookahead.items()}
  70. for _ in bfs([self.start_state], step):
  71. pass
  72. self.end_state ,= self.end_states
  73. self._parse_table = ParseTable(self.states, self.start_state, self.end_state)
  74. if self.debug:
  75. self.parse_table = self._parse_table
  76. else:
  77. self.parse_table = IntParseTable.from_ParseTable(self._parse_table)