| @@ -0,0 +1,107 @@ | |||||
| from ..utils import classify, classify_bool, bfs, fzset | |||||
| from ..common import GrammarError, is_terminal | |||||
| from lalr_analysis import Rule, RulePtr, GrammarAnalyzer | |||||
| class Item: | |||||
| def __init__(self, rule_ptr, start): | |||||
| self.rule_ptr = rule_ptr | |||||
| self.start = start | |||||
| @property | |||||
| def expect(self): | |||||
| return self.rule_ptr.next | |||||
| @property | |||||
| def is_complete(self): | |||||
| return self.rule_ptr.is_satisfied | |||||
| def advance(self): | |||||
| return Item(self.rule_ptr.advance(self.expect), self.start) | |||||
| def __eq__(self, other): | |||||
| return self.rule_ptr == other.rule_ptr and self.start == other.start | |||||
| def __hash__(self): | |||||
| return hash((self.rule_ptr, self.start)) | |||||
| def __repr__(self): | |||||
| return '%s (%s)' % (self.rule_ptr, self.start) | |||||
| class Parser: | |||||
| def __init__(self, rules, start): | |||||
| self.analyzer = GrammarAnalyzer(rules, start) | |||||
| self.start = start | |||||
| def parse(self, stream): | |||||
| # Define parser functions | |||||
| def predict(symbol, i): | |||||
| assert not is_terminal(symbol), symbol | |||||
| return {Item(rp, i) for rp in self.analyzer.expand_rule(symbol)} | |||||
| def scan(item, inp): | |||||
| if item.expect == inp: # TODO Do a smarter match, i.e. regexp | |||||
| return {item.advance()} | |||||
| else: | |||||
| return set() | |||||
| def complete(item, table): | |||||
| print "Complete:", item | |||||
| name = item.rule_ptr.rule.origin | |||||
| return {old_item.advance() for old_item in table[item.start] | |||||
| if old_item.expect == name} | |||||
| def process_column(i, char): | |||||
| cur_set = table[-1] | |||||
| next_set = set() | |||||
| table.append(next_set) | |||||
| to_process = cur_set | |||||
| while to_process: | |||||
| new_items = set() | |||||
| for item in to_process: | |||||
| if item.is_complete: | |||||
| new_items |= complete(item, table) | |||||
| else: | |||||
| if is_terminal(item.expect): | |||||
| next_set |= scan(item, char) | |||||
| else: | |||||
| new_items |= predict(item.expect, i) | |||||
| to_process = new_items - cur_set | |||||
| cur_set |= to_process | |||||
| # Main loop starts | |||||
| table = [predict(self.start, 0)] | |||||
| for i, char in enumerate(stream): | |||||
| process_column(i, char) | |||||
| process_column(len(stream), None) | |||||
| # rules = [ | |||||
| # ('a', ['a', 'A']), | |||||
| # ('a', ['A']), | |||||
| # ] | |||||
| # p = Parser(rules, 'a') | |||||
| # p.parse('AAA') | |||||
| rules = [ | |||||
| ('sum', ['sum', "A", 'product']), | |||||
| ('sum', ['product']), | |||||
| ('product', ['product', "M", 'factor']), | |||||
| ('product', ['factor']), | |||||
| ('factor', ['L', 'sum', 'R']), | |||||
| ('factor', ['number']), | |||||
| ('number', ['N', 'number']), | |||||
| ('number', ['N']), | |||||
| ] | |||||
| p = Parser(rules, 'sum') | |||||
| p.parse('NALNMNANR') | |||||