Recent Changes

Wednesday, January 3

  1. msg parseAction - action is not called message posted parseAction - action is not called from pruga.elm import ast   from pyparsing import (alphanums, a…
    parseAction - action is not called
    from pruga.elm import ast
     
    from pyparsing import (alphanums,
                            alphas,
                            ParserElement,
                            Keyword,
                            Suppress,
                            Word,
                            delimitedList)
     
    ParserElement.enablePackrat()
     
    class Node:
     
        def __init__(self, s, loc, tokens):
            print('init NODE WITH  TOKENS', tokens, f'"{s}"')
     
     
    IMPORT = Suppress(Keyword('import'))
     
    ModuleName = Word(alphas.upper(), alphanums + '_')('name')
     
    QualifiedModuleName = delimitedList(ModuleName, delim='.')
     
    # QualifiedModuleName has not defined any parseActons
    ImportStatement = IMPORT + QualifiedModuleName('module') 
     
    # I define parseAction now, but this action will not be used
    QualifiedModuleName.setParseAction(Node)
     
    source = 'import X.Y.Z'
    ast = ImportStatement.parseString(source)
    print('ImportStatement defined before QualifiedModuleName.setParseAction(Node)')
    print(ast)
     
    # identically definition ImportStatement, but is defined after QualifiedModuleName.setParseAction(Node)
    ImportStatement = IMPORT + QualifiedModuleName('module') 
     
    ast = ImportStatement.parseString(source)
    print('The same ImportStatement defined after QualifiedModuleName.setParseAction(Node)')
     
    print(ast)
     

    output

    ImportStatement defined before QualifiedModuleName.setParseAction(Node)
    ['X', 'Y', 'Z']
    init NODE WITH TOKENS ['X', 'Y', 'Z'] "import X.Y.Z"
    The same ImportStatement defined after QualifiedModuleName.setParseAction(Node)
    [<main.Node object at 0x7f136483c080>]
    1:54 am

Friday, November 17

  1. 8:42 am

Sunday, October 1

  1. 3:00 pm

Sunday, September 3

  1. msg += operator and user function for math equation message posted += operator and user function for math equation ah, i did not notice the tokens become a list if i use Group function. After removing the Group and…
    += operator and user function for math equation
    ah, i did not notice the tokens become a list if i use Group function. After removing the Group and use code like this, i got
    def assignVar(t):
        global vars_
        vars_=defaultdict(float)
        print('t0 is {}'.format(t[0]))
        vars_[t[0]]=t[-1]
    The var on lhs is updated with rhs value. If there is any better way, please let me know.
    Another question is on the funccall. I would need to map many user function to python function. In the excelExpr.py example the funcCall is actually an aggregation using MatchFirst of various functions. This seems a bit tedious as we need to a new line each time we have a new function and then append the new function name in the funcCall line. Is there easier way such as just using a dictionary?
    Sorry for all these many questions but i am glad to be able to make some progress little by little.
    6:12 am
  2. msg += operator and user function for math equation message posted += operator and user function for math equation Thanks for the clarification. Would you mind to give a simple example on how to assign the token va…
    += operator and user function for math equation
    Thanks for the clarification. Would you mind to give a simple example on how to assign the token value on rhs to variable on lhs? I tried something like this:
    assignmentExpr = Group(varname('lhs') + EQ('operator') + expr('rhs'))('assignment').addParseAction(lambda t: t[0] = t[-1])
    but i got an error
    SyntaxError: lambda cannot contain assignment

    Also, what is the difference between addParseAction and setParseAction?
    4:59 am

Saturday, September 2

  1. msg += operator and user function for math equation message posted += operator and user function for math equation The parsed data returned by pyparsing implements all the methods of a list so that it can be treate…
    += operator and user function for math equation
    The parsed data returned by pyparsing implements all the methods of a list so that it can be treated as a list (len, for i in result, result[0], etc.). If you *must* have a list (for JSON serialization, for example), you can use result.asList() and the parsed data will be converted to a nested list. Note that this will strip any defined results names, like" fname" or "argslist".

    augAssignOp won't really fit into into the infixNotation model because '+=' isn't really an operator. You can't write "x * (a += 14)". The '+=' can only occur as part of an enhanced assignment statement. So you should really implement '+=' as another form of assignment:

    EQ = Literal('=')
    PLUS_EQ = Literal('+=')
    assignmentExpr = varname('lhs') + EQ('operator') + arithExpr('rhs')
    augmentedAssignmentExpr = varname('lhs') + PLUS_EQ('operator') + arithExpr('rhs')

    and then have your overall parser match for "assignment | augmentedAssignment".

    statement_parser = assignmentExpr | augmentedAssignemtExpr

    You could attach a parse action to statement_parser that would look at the variable name in "lhs", the value in "rhs", and the assignment or augmented assignment based on whether "operator" was "=" or "+=".
    8:47 am
  2. msg += operator and user function for math equation message posted += operator and user function for math equation For my work, there is no exponential operation, and this makes things easier. But on the other hand…
    += operator and user function for math equation
    For my work, there is no exponential operation, and this makes things easier. But on the other hand, the user defined function is exactly like a python function and can take argument such as list or keyword argument (name = value). i plan to directly write those functions in python, so i just need to call those functions with parsed argument list.
    I have read more examples such as arith.py and excelExpr.py and discussion in this forum. And it seems infixNotation helps to simplify the definition of operators. But i am puzzled whether i should treat the brackets as an operator and if so how to do that.
    I have tried a bit with new style of code like below by making list a kind of parseelement instead of an operator
    from pyparsing import *
     
    compOp = oneOf("< > >= <=")
    multOp = oneOf("* /")
    addOp = oneOf("+ -")
    augassignOp = Literal('+=')
     
    EQ,LPAR,RPAR,LBRA,RBRA = map(Suppress, '=()[]')
     
    varname = Regex(r'[a-zA-Z_][a-zA-Z0-9_]*')
    fname = Regex(r'[a-zA-Z][a-zA-Z0-9_]*')
    decimalnumber = Regex(r'[+-]?\d+(\.\d*)?')
     
    expr = Forward()
    listmaker = Group(LBRA + delimitedList(expr) + RBRA)('list')
    funccall = Group(fname('fname') + LPAR + Group(delimitedList(expr))("arglist") + RPAR)
    operand = decimalnumber | listmaker | funccall | varname
    expr <<= infixNotation(operand,
        [
        (multOp, 2, opAssoc.LEFT),
        (addOp, 2, opAssoc.LEFT),
        (compOp, 2, opAssoc.LEFT),
    #    (augassignOp, 2, opAssoc.LEFT),
        ])
     
    l = ['cond(1,select(4,[2, 3]))']
     
    for item in l:
        source = item
        expr.runTests(source)

    The parsing seems to work as I got below result:
    cond(1,select(4,[2, 3]))
    [['cond', ['1', ['select', ['4', ['2', '3']]]]]]
    [0]:
      ['cond', ['1', ['select', ['4', ['2', '3']]]]]
      - arglist: ['1', ['select', ['4', ['2', '3']]]]
        [0]:
          1
        [1]:
          ['select', ['4', ['2', '3']]]
          - arglist: ['4', ['2', '3']]
            - list: ['2', '3']
          - fname: 'select'
      - fname: 'cond'

    But i am puzzled how to pass the argument back to the function as a list. Also i have not figured out how to handle the keyword argument.

    Also, i am still stuck at the augassignOp because i cannot use a lambda expression like l"ambda a, b: a = a + b" as shown in the airth.py example.

    Would appreciate any feedback. Thanks.
    6:28 am

Tuesday, August 29

  1. msg Odd .copy() behaviour message posted Odd .copy() behaviour Haven't forgotten you - I looked back through history to see what the impetus was for this change, …
    Odd .copy() behaviour
    Haven't forgotten you - I looked back through history to see what the impetus was for this change, but did not see the specific bug or case that inspired it. I did make your change and reran my unit tests, and all appears to be okay, but I still want to revisit my history dive.

    Thanks for your patience,
    -- Paul
    5:07 am

Sunday, August 27

  1. msg += operator and user function for math equation message posted += operator and user function for math equation I am new to parsing and have just come accross this tool which looks great. For my work, I need …
    += operator and user function for math equation
    I am new to parsing and have just come accross this tool which looks great.

    For my work, I need to parse multiple lines of math equations with variables and user defined functions inside. For example, with 3 lines of string:
    x = 1
    y = Max(1,2)
    x += y
    I want to be able to get x = 3 and y = 2 at the end.

    Below is my attempt on this. I am just trying to make a slight modification to the fourFn.py and SimpleCalc.py examples in the wiki page.
    import operator
    from pyparsing import Literal,Word,Combine,Optional,ZeroOrMore,Forward,nums,\
        alphas
    from collections import defaultdict
     
    def main():
        global exprStack
        exprStack = []
        global varStack
        varStack  = []
        global variables
        variables = defaultdict(float)
        l = ['x=1','y=abs(2)', 'x+=y']
        for item in l:
            source = item
            L = BNF().parseString( source )
            print(L)
            result = evaluateStack( exprStack[:] )
            print(varStack)
            print(result)
            variables[varStack.pop()]=result
            print(variables)
     
    def Scalar(x):
        return x
     
    def pushFirst( strg, loc, toks ):
        exprStack.append( toks[0] )
     
    def assignVar( strg, loc, toks ):
        varStack.append( toks[0] )
     
    bnf = None
    def BNF():
        """
        expop   :: '^'
        multop  :: '*' | '/'
        addop   :: '+' | '-'
        integer :: ['+' | '-'] '0'..'9'+
        atom    :: real | fn '(' expr ')' | '(' expr ')'
        factor  :: atom [ expop factor ]*
        term    :: factor [ multop factor ]*
        expr    :: term [ addop term ]*
        iaddop  :: '+='
        assign  :: '='
        """
        global bnf
        if not bnf:
            point = Literal( "." )
            fnumber = Combine( Word( "+-"+nums, nums ) + 
                               Optional( point + Optional( Word( nums ) ) ))
            ident = Word(alphas+"_", alphas+nums+"_")
     
            plus  = Literal( "+" )
            minus = Literal( "-" )
            mult  = Literal( "*" )
            div   = Literal( "/" )
            lpar  = Literal( "(" ).suppress()
            rpar  = Literal( ")" ).suppress()
            addop  = plus | minus
            multop = mult | div
            expop = Literal( "^" )
            assign = Literal( "=" )
            iaddop = Literal("+=")
     
            expr = Forward()
            atom = ( fnumber | ident + lpar + expr + rpar | ident ).setParseAction(pushFirst) | ( lpar + expr.suppress() + rpar )
     
            # by defining exponentiation as "atom [ ^ factor ]..." instead of "atom [ ^ atom ]...", we get right-to-left exponents, instead of left-to-righ
            # that is, 2^3^2 = 2^(3^2), not (2^3)^2.
            factor = Forward()
            factor << atom + ZeroOrMore( ( expop + factor ).setParseAction( pushFirst ) )
     
            term = factor + ZeroOrMore( ( multop + factor ).setParseAction( pushFirst ) )
            expr << term + ZeroOrMore( ( addop + term ).setParseAction( pushFirst ) )
            bnf =  ident.setParseAction(assignVar) + (assign | iaddop.setParseAction( pushFirst )) + expr
        return bnf
     
    # map operator symbols to corresponding arithmetic operations
    opn = { "+" : operator.add,
            "-" : operator.sub,
            "*" : operator.mul,
            "/" : operator.truediv,
            "^" : operator.pow,
            "+=" : operator.iadd}
    fn  = { "Max" : max,
            "Min" : min,
            "abs" : abs,
           "Scalar" : Scalar}
     
    def evaluateStack( s ):
        op = s.pop() 
        if op in "+-*/^" or op in '+=':
            op2 = evaluateStack( s )
            op1 = evaluateStack( s )
            return opn[op]( op1, op2 )
        elif op in fn:
            return fn[op]( evaluateStack( s ) )
        elif op in variables:
            return variables[op]        
        else:
            return float( op )
     
    if __name__ == '__main__':
        main()

    But I have faced two issues.
    1. The += operator is not working as expected. With input string as ['x=1','y=2', 'x+=y'], I still get x= 1 in the end. <-- defaultdict(<class 'float'>, {'x': 1.0, 'y': 2.0})
    2. My user defined funciton name will have the same name convention as the variable name convention. The only difference is that the function will have parentheses followed. I tried to modify the atom definition but it is not working as expected. With input string as ['x=1','y=abs(2)', 'x+=y'], I got a ValueError: could not convert string to float: 'y'.

    Would you help to shred some lights on how to fix the problem? Thanks.
    7:25 pm

Monday, August 21

  1. user_add ckot71 ckot71 joined pyparsing
    6:36 am

More