Mercurial > lbo > hg > pcombinators
changeset 6:e4b519f95d2d draft
Implement comparatively simple parser of arithmetic expressions written as combinators.
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Sun, 19 May 2019 14:15:45 +0200 |
parents | ac04bb5bb0c5 |
children | b4844d42ed0f |
files | arith_test.py |
diffstat | 1 files changed, 98 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arith_test.py Sun May 19 14:15:45 2019 +0200 @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Let's test the combinators in a real world application! + +@author: lbo +""" + +from combinators import * + +class Parens(Parser): + def parse(self, st): + initial = st.index() + p1, st = Operator('(').parse(st) + print('pr', p1, st) + if p1 is None: + st.reset(initial) + return None, st + term, st = Term().parse(st) + print('pr', term, st) + if term is None: + st.reset(initial) + return None, st + p2, st = Operator(')').parse(st) + print('pr', p2, st) + if p2 is None: + print('No closing paren!') + st.reset(initial) + return None, st + return term, st + +def Atom(): + """An atom is a variable or a float.""" + return (Float() | Parens() | Regex('\w+')) + +def Operator(set): + return Last(Skip(Whitespace()) + CharSet(set)) + +class Product(Parser): + + def parse(self, st): + initial = st.index() + + left, st = Atom().parse(st) + print('p', left, st) + if left is None: + st.reset(initial) + return None, st + + op, st = Operator('*/').parse(st) + print('p', op, st) + if op is None: + return left, st + + right, st = Product().parse(st) + print('p', right, st) + if right is None: + st.reset(initial) + return None, st + return ((left, op, right), st) + +class Term(Parser): + + def parse(self, st): + initial = st.index() + + left, st = Product().parse(st) + print('t', left, st) + if left is None: + st.reset(initial) + return None, st + + op, st = Operator('+-').parse(st) + print('t', op, st) + if op is None: + return left, st + + right, st = Term().parse(st) + print(right, st) + if right is None: + st.reset(initial) + return None, st + + return (left, op, right), st + +def pretty_print(tpl): + # tpl is a (left, op, right) tuple or a scalar. + if not isinstance(tpl, tuple): + return str(tpl) + assert len(tpl) == 3 + return '({} {} {})'.format(pretty_print(tpl[0]), tpl[1], pretty_print(tpl[2])) + +def parse_and_print(expr): + parsed, st = Term().parse(ps(expr)) + if parsed is None: + print('Parse error :(', st) + return + print(pretty_print(parsed)) \ No newline at end of file