Mercurial > lbo > hg > arith
view arith/parse.py @ 0:e85652916197 draft
Initial commit
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Fri, 17 May 2019 22:28:13 +0200 |
parents | |
children |
line wrap: on
line source
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Sun May 12 19:23:08 2019 @author: lbo """ """ Parse arithmetic terms. Terms are structured like this: Sum (consists of) products (consist of) factors """ from tree import Value, Symbol, Product, Term, Power class ParseState: """Encapsulates state as the parser goes through input.""" _input = '' _index = 0 def __init__(self, s): self._input = s def repr(self): return 'ParseState({} < {} > {}'.format( self._input[0:self._index], self._input[self._index], self._input[self._index:]) def next(self): current = self.peek() self._index += 1 while not self.finished() and self.peek().isspace(): self._index += 1 return current def peek(self): return self._input[self._index] def index(self): return self._index def reset(self, ix): self._index = ix def __iter__(self): return self def __next__(self): return self.next() def finished(self): return self._index == len(self._input) def parse(s): st = ParseState(s) return parse_term(st) def parse_term(st): left = parse_product(st) result = left if st.finished(): return result op = st.peek() while op in [Term.PLUS, Term.MINUS]: st.next() right = parse_product(st) result = Term(result, right) result.typ = op if st.finished(): break op = st.peek() return result def parse_product(st): left = parse_power(st) result = left if st.finished(): return result op = st.peek() while not st.finished() and op in [Product.PROD, Product.QUOT]: st.next() right = parse_product(st) result = Product(result, right) result.typ = op if st.finished(): break op = st.peek() return result def parse_power(st): left = parse_atom(st) result = left if st.finished(): return result next = st.peek() if next == '^': st.next() right = parse_atom(st) result = Power(left, right) return result def parse_atom(st): next = st.next() if next == '(': term = parse_term(st) st.next() # Consume closing paren return term full = next def is_number(s): return all([a.isnumeric() or a == '.' for a in s]) while not st.finished() and (st.peek().isalpha() or is_number(st.peek())): full += st.next() if is_number(full): return Value(float(full)) if full.isalnum(): return Symbol(full)