|
- """This module builds a LALR(1) transition-table for lalr_parser.py
-
- For now, shift/reduce conflicts are automatically resolved as shifts.
- """
-
- # Author: Erez Shinan (2017)
- # Email : erezshin@gmail.com
-
- import logging
- from collections import defaultdict
-
- from ..utils import classify, classify_bool, bfs, fzset
- from ..common import GrammarError, is_terminal
-
- from .grammar_analysis import GrammarAnalyzer
-
- ACTION_SHIFT = 0
-
- class LALR_Analyzer(GrammarAnalyzer):
-
- def compute_lookahead(self):
-
- self.states = {}
- def step(state):
- lookahead = defaultdict(list)
- sat, unsat = classify_bool(state, lambda rp: rp.is_satisfied)
- for rp in sat:
- for term in self.FOLLOW.get(rp.rule.origin, ()):
- lookahead[term].append(('reduce', rp.rule))
-
- d = classify(unsat, lambda rp: rp.next)
- for sym, rps in d.items():
- rps = {rp.advance(sym) for rp in rps}
-
- for rp in set(rps):
- if not rp.is_satisfied and not is_terminal(rp.next):
- rps |= self.expand_rule(rp.next)
-
- lookahead[sym].append(('shift', fzset(rps)))
- yield fzset(rps)
-
- for k, v in lookahead.items():
- if len(v) > 1:
- if self.debug:
- logging.warn("Shift/reduce conflict for %s: %s. Resolving as shift.", k, v)
- for x in v:
- # XXX resolving shift/reduce into shift, like PLY
- # Give a proper warning
- if x[0] == 'shift':
- lookahead[k] = [x]
-
- for k, v in lookahead.items():
- if not len(v) == 1:
- raise GrammarError("Collision in %s: %s" %(k, v))
-
- self.states[state] = {k:v[0] for k, v in lookahead.items()}
-
- for _ in bfs([self.init_state], step):
- pass
-
- # --
- self.enum = list(self.states)
- self.enum_rev = {s:i for i,s in enumerate(self.enum)}
- self.states_idx = {}
-
- for s, la in self.states.items():
- la = {k:(ACTION_SHIFT, self.enum_rev[v[1]]) if v[0]=='shift'
- else (v[0], (v[1], len(v[1].expansion))) # Reduce
- for k,v in la.items()}
- self.states_idx[ self.enum_rev[s] ] = la
-
-
- self.init_state_idx = self.enum_rev[self.init_state]
|