Error checking using regex ?

Paul McGuire ptmcg at austin.rr._bogus_.com
Tue Jun 8 16:13:49 EDT 2004


"Guy Robinson" <guy at NOSPAM.r-e-d.co.nz> wrote in message
news:ca47pc$e11$1 at lust.ihug.co.nz...
> I have the code below which parses an expression string and creates
tokens.
>
> Can anyone suggest the best of error checking for things like:
>
> Valid variable only obj.attribute -whitespace allowed
>
> test( "ff*2/dd.r..ss r")    #additional ..ss -invalid variable.
> test( "ff*$24..55/ddr")     #double .. and $ -invalid number
> test( "ff*2/dd.r.ss r")     #variable with double . -invalid variable
>
> I can't see an efficient way of doing this so any suggestions appreciated.
>
> TIA,
>
> Guy
>
<snip>

Guy -

Well, I recognize the test cases from an example that I include with
pyparsing.  Are you trying to add support for variables to that example?  If
so, here is the example, modified to support assignments to variables.

-- Paul

============================
# minimath.py (formerly fourfn.py)
#
# Demonstration of the parsing module, implementing a simple 4-function
expression parser,
# with support for scientific notation, and symbols for e and pi.
# Extended to add exponentiation and simple built-in functions.
# Extended to add variable assignment, storage, and evaluation, and
Python-like comments.
#
# Copyright 2003,2004 by Paul McGuire
#
from pyparsing import
Literal,CaselessLiteral,Word,Combine,Group,Optional,ZeroOrMore,OneOrMore,For
ward,nums,alphas,restOfLine,delimitedList
import math

variables = {}
exprStack = []

def pushFirst( str, loc, toks ):
    global exprStack
    if toks:
        exprStack.append( toks[0] )
    return toks

def assignVar( str, loc, toks ):
    global exprStack
    global variables
    variables[ toks[0] ] = evaluateStack( exprStack )
    pushFirst(str,loc,toks)


bnf = None
def BNF():
    global bnf
    if not bnf:
        point = Literal( "." )
        e     = CaselessLiteral( "E" )
        fnumber = Combine( Word( "+-"+nums, nums ) +
                           Optional( point + Optional( Word( nums ) ) ) +
                           Optional( e + Word( "+-"+nums, nums ) ) )
        ident = Word(alphas, alphas+nums+"_$")
        varident = delimitedList(ident,".",combine=True)

        plus  = Literal( "+" )
        minus = Literal( "-" )
        mult  = Literal( "*" )
        div   = Literal( "/" )
        lpar  = Literal( "(" ).suppress()
        rpar  = Literal( ")" ).suppress()
        addop  = plus | minus
        multop = mult | div
        expop = Literal( "^" )
        pi    = CaselessLiteral( "PI" )

        expr = Forward()
        atom = ( pi | e | fnumber | ident + lpar + expr + rpar |
varident ).setParseAction( pushFirst ) | ( lpar + expr.suppress() + rpar )
        factor = atom + ZeroOrMore( ( expop + expr ).setParseAction(
pushFirst ) )
        term = factor + ZeroOrMore( ( multop + factor ).setParseAction(
pushFirst ) )
        expr << term + ZeroOrMore( ( addop + term ).setParseAction(
pushFirst ) )
        assignment = (varident + "=" + expr).setParseAction( assignVar )

        bnf = Optional( assignment | expr )

        comment = "#" + restOfLine
        bnf.ignore(comment)

    return bnf

# map operator symbols to corresponding arithmetic operations
opn = { "+" : ( lambda a,b: a + b ),
        "-" : ( lambda a,b: a - b ),
        "*" : ( lambda a,b: a * b ),
        "/" : ( lambda a,b: a / b ),
        "^" : ( lambda a,b: a ** b ) }
fn  = { "sin" : math.sin,
        "cos" : math.cos,
        "tan" : math.tan,
        "abs" : abs,
        "trunc" : ( lambda a: int(a) ),
        "round" : ( lambda a: int(a+0.5) ),
        "sgn" : ( lambda a: ( (a<0 and -1) or (a>0 and 1) or 0 ) ) }
def evaluateStack( s ):
    global variables
    if not s: return 0.0
    op = s.pop()
    if op in "+-*/^":
        op2 = evaluateStack( s )
        op1 = evaluateStack( s )
        return opn[op]( op1, op2 )
    elif op == "PI":
        return 3.1415926535
    elif op == "E":
        return 2.718281828
    elif op[0].isalpha():
        if op in variables:
            return variables[op]
        fnarg = evaluateStack( s )
        return (fn[op])( fnarg )
    else:
        return float( op )

if __name__ == "__main__":

    def test( str ):
        global exprStack
        exprStack = []
        results = BNF().parseString( str )
        print str, "->", results, "=>", exprStack, "=", evaluateStack(
exprStack )

    test( "9" )
    test( "9 + 3 + 6" )
    test( "9 + 3 / 11" )
    test( "(9 + 3)" )
    test( "(9+3) / 11" )
    test( "9 - 12 - 6" )
    test( "9 - (12 - 6)" )
    test( "2*3.14159" )
    test( "3.1415926535*3.1415926535 / 10" )
    test( "PI * PI / 10" )
    test( "PI*PI/10" )
    test( "PI^2" )
    test( "6.02E23 * 8.048" )
    test( "e / 3" )
    test( "sin(PI/2)" )
    test( "trunc(E)" )
    test( "E^PI" )
    test( "2^3^2" )
    test( "2^9" )
    test( "sgn(-2)" )
    test( "sgn(0)" )
    test( "sgn(0.1)" )
    test( "5*4+300/(5-2)*(6+4)+4" )
    test( "((5*4+301)/(5-2))*(6+4)+4" )
    test( "(321/3)*10+4" )
    test( "# nothing but comments" )
    test( "a = 2^10" )
    test( "a^0.1   # same as 10th root of 1024" )
    test( "c = a" )
    test( "b=a" )
    test( "b-c" )





More information about the Python-list mailing list