|
@@ -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') |