def __init__(self, text): self.scanner = Scanner(text)
class Parser(object): def __init__(self, text): self.scanner = Scanner(text) def alpaca(self): defns = [] defns.append(self.defn()) pf = None while self.scanner.consume(';'): defns.append(self.defn()) # we shan't consume() this token, lest the scanner jump # ahead assuming that the next token is normal. If the # scanner is already on this token, the rest of the scanner # text is the playfield; so we just check on() here. if self.scanner.on('begin'): pf = self.scanner.scan_playfield() else: self.scanner.expect('.') playfield = AST('Playfield', value=pf) return AST('Alpaca', [AST('Defns', defns), playfield]) def defn(self): if self.scanner.on('state'): return self.state_defn() elif self.scanner.on('class'): return self.class_defn() elif self.scanner.on('neighbourhood'): return self.nbhd_defn() else: raise SyntaxError("Expected 'state', 'class', or " "'neighbourhood', but found " "'%s'" % self.scanner.token) def state_defn(self): self.scanner.expect('state') id = self.scanner.consume_type('identifier') attrs = [] char_repr = AST('CharRepr', value=self.scanner.consume_type('string literal')) if self.scanner.consume('{'): attrs.append(self.attribute()) while self.scanner.consume(','): attrs.append(self.attribute()) self.scanner.expect('}') attrs = AST('ReprDecls', attrs) classes = [] while self.scanner.on('is'): classes.append(self.class_decl()) classes = AST('MembershipDecls', classes) rules = self.rules() return AST('StateDefn', [char_repr, attrs, classes, rules], value=id) def attribute(self): id = self.scanner.consume_type('identifier') self.scanner.expect(':') value = self.scanner.consume_type('string literal') return AST('Attribute', value=(id, value)) def class_decl(self): self.scanner.expect('is') id = self.scanner.consume_type('identifier') return AST('ClassDecl', value=id) def class_defn(self): self.scanner.expect('class') id = self.scanner.consume_type('identifier') classes = [] while self.scanner.on('is'): classes.append(self.class_decl()) classes = AST('MembershipDecls', classes) rules = self.rules() return AST('ClassDefn', [rules, classes], value=id) def nbhd_defn(self): self.scanner.expect('neighbourhood') self.scanner.check_type('identifier') id = self.scanner.consume_type('identifier') n = self.neighbourhood() return AST('NbhdDefn', [n], value=id) def rules(self): r = [] if self.scanner.on('to'): r.append(self.rule()) while self.scanner.consume(','): r.append(self.rule()) return AST('Rules', r) def rule(self): self.scanner.expect('to') s = self.state_ref() e = AST('BoolLit', value='true') if self.scanner.consume('when'): e = self.expression() return AST('Rule', [s, e]) def state_ref(self): if self.scanner.on_type('identifier'): id = self.scanner.consume_type('identifier') return AST('StateRefEq', value=id) elif self.scanner.on_type('arrow chain'): rel = self.scanner.consume_type('arrow chain') (dx, dy) = resolve_arrow_chain(rel) return AST('StateRefRel', value=(dx, dy)) self.scanner.expect('me') return AST('StateRefRel', value=(0, 0)) def neighbourhood(self): self.scanner.expect('(') refs = [] while self.scanner.on_type('arrow chain'): refs.append(self.state_ref()) self.scanner.expect(')') return AST('Neighbourhood', refs) def expression(self): e = self.term() while self.scanner.on_type('boolean operator'): op = self.scanner.consume_type('boolean operator') t = self.term() e = AST('BoolOp', [e, t], value=op) return e def term(self): if self.scanner.on_type('integer literal'): count = self.scanner.consume_type('integer literal') nb = NBHD_MOORE if self.scanner.consume('in'): if self.scanner.on_type('identifier'): nb = AST('NbhdRef', value=self.scanner.consume_type('identifier')) else: nb = self.neighbourhood() if self.scanner.on('is'): rel = self.class_decl() else: rel = self.state_ref() return AST('Adjacency', [rel, nb], value=count) elif self.scanner.consume('('): e = self.expression() self.scanner.expect(')') return e elif self.scanner.consume('not'): e = self.term() return AST('Not', [e]) elif self.scanner.on_type('boolean literal'): lit = self.scanner.consume_type('boolean literal') return AST('BoolLit', value=lit) else: sr = self.state_ref() if self.scanner.on('is'): rel = self.class_decl() else: self.scanner.consume('=') # optional rel = self.state_ref() return AST('Relational', [sr, rel])
class Parser(object): def __init__(self, text): self.scanner = Scanner(text) def alpaca(self): defns = [] defns.append(self.defn()) pf = None while self.scanner.consume(';'): defns.append(self.defn()) # we shan't consume() this token, lest the scanner jump # ahead assuming that the next token is normal. If the # scanner is already on this token, the rest of the scanner # text is the playfield; so we just check on() here. if self.scanner.on('begin'): pf = self.scanner.scan_playfield() else: self.scanner.expect('.') playfield = Playfield(value=pf) return Alpaca(defns=defns, playfield=playfield) def defn(self): if self.scanner.on('state'): return self.state_defn() elif self.scanner.on('class'): return self.class_defn() elif self.scanner.on('neighbourhood'): return self.nbhd_defn() else: raise SyntaxError("Expected 'state', 'class', or " "'neighbourhood', but found " "'%s'" % self.scanner.token) def state_defn(self): self.scanner.expect('state') id = self.scanner.consume_type('identifier') attrs = [] char_repr = CharRepr(value=self.scanner.consume_type('string literal')) classes = [] while self.scanner.on('is'): classes.append(self.class_decl()) rules = self.rules() return StateDefn(id=id, char_repr=char_repr, classes=classes, rules=rules) def class_decl(self): self.scanner.expect('is') id = self.scanner.consume_type('identifier') return ClassDecl(id=id) def class_defn(self): self.scanner.expect('class') id = self.scanner.consume_type('identifier') classes = [] while self.scanner.on('is'): classes.append(self.class_decl()) rules = self.rules() return ClassDefn(id=id, rules=rules, classes=classes) def nbhd_defn(self): self.scanner.expect('neighbourhood') self.scanner.check_type('identifier') id = self.scanner.consume_type('identifier') n = self.neighbourhood() return NbhdDefn(id=id, children=[n]) def rules(self): r = [] if self.scanner.on('to'): r.append(self.rule()) while self.scanner.consume(','): r.append(self.rule()) return r def rule(self): self.scanner.expect('to') s = self.state_ref() e = BoolLit(value='true') if self.scanner.consume('when'): e = self.expression() return Rule(state_ref=s, expr=e) def state_ref(self): if self.scanner.on_type('identifier'): id = self.scanner.consume_type('identifier') return StateRefEq(id=id) elif self.scanner.on_type('arrow chain'): rel = self.scanner.consume_type('arrow chain') (dx, dy) = resolve_arrow_chain(rel) return StateRefRel(value=(dx, dy)) self.scanner.expect('me') return StateRefRel(value=(0, 0)) def neighbourhood(self): self.scanner.expect('(') refs = [] while self.scanner.on_type('arrow chain'): refs.append(self.state_ref()) self.scanner.expect(')') return Neighbourhood(children=refs) def expression(self): e = self.term() while self.scanner.on_type('boolean operator'): op = self.scanner.consume_type('boolean operator') t = self.term() e = BoolOp(lhs=e, rhs=t, op=op) return e def term(self): if self.scanner.on_type('integer literal'): count = self.scanner.consume_type('integer literal') nbhd = NBHD_MOORE if self.scanner.consume('in'): if self.scanner.on_type('identifier'): id = self.scanner.consume_type('identifier') nbhd = NbhdRef(id=id) else: nbhd = self.neighbourhood() if self.scanner.on('is'): rel = self.class_decl() else: rel = self.state_ref() return Adjacency(rel=rel, nbhd=nbhd, count=count) elif self.scanner.consume('('): e = self.expression() self.scanner.expect(')') return e elif self.scanner.consume('not'): e = self.term() return Not(expr=e) elif self.scanner.on_type('boolean literal'): lit = self.scanner.consume_type('boolean literal') return BoolLit(value=lit) else: sr = self.state_ref() if self.scanner.on('is'): rel = self.class_decl() else: self.scanner.consume('=') # optional rel = self.state_ref() return Relational(lhs=sr, rhs=rel)