Saturday, July 7, 2007

"a(a, b)" and "a (a, b)"

For Lipl, I can parse a(b c, d, e) and a (b c, d, e) differently. First is a function call while the second one is 2 tokens: Atom and List.

a = 1 .
b = 2 .
f(a, b) = [a + b] .
print f(a, b) .

If I have that, first appearance of f(a, b) should be distinguished from the second appearance after print. I can mark the declaration like: @f(a, b). But, even if I don't mark it as declaration, LiplMachine can look at the namespace for function f. If f doesn't exist it can be considered as a declaration. Or, I can always evaluate when a token is popped from the stack, not when it is pushed to. = f(a, b) [a + b] . is fine too because when f(a, b) is popped from the queue, not the stack, = is actually popping it. So, LipleMachine will know that f(a, b) is a declaration, not function call.

import pyparsing as pp
import sys

pp.ParseExpression.setDefaultWhitespaceChars("")

WS = pp.Suppress(pp.White())
OptWS = pp.Suppress(pp.Optional(WS))
LParen = pp.Suppress('(' + OptWS)
RParen = pp.Suppress(OptWS + ')')
Comma = pp.Suppress(OptWS + ',' + OptWS)

Atom = pp.Word(pp.alphas + '_', pp.alphanums + '_')\
        .setResultsName('Atom').setName('Atom')
Token = pp.Forward().setResultsName('Token')
Tokens = pp.Group(Token + pp.ZeroOrMore(WS + Token))\
        .setResultsName('Tokens').setName('Tokens')
CommaTokens = (Tokens + pp.ZeroOrMore(Comma + Tokens))\
        .setResultsName('CommaTokens').setName('CommaTokens')
List = pp.Group(LParen + CommaTokens + RParen)\
        .setResultsName('List').setName('List')
Funcall = pp.Group(Atom + List)\
        .setResultsName('Funcall').setName('Funcall')

Token << (List | Funcall | Atom)

S = (Tokens + pp.StringEnd())\
        .setResultsName('S').setName('S').leaveWhitespace()#.setDebug()

def print_tree(results, tab=2, level=0):
    "prints ParseResults"
    if type(results) != pp.ParseResults: #terminal
        print  (' '*level) + '> ' + str(results)
        return

    print (' '*level) + '- ' + results.getName() + ':'

    for x in results:
        print_tree(x, tab, level+tab)

def process(x):
    "parses and prints result"
    try:
        print x
        result = S.parseString(x)
        print ">>>", result
        print_tree(result)
        #result.dump()
        print ">>> [PASS]"
    except pp.ParseException, err:
        print x
        print (" " * (err.col - 1)) + "^"
        print err
        print ">>> [FAIL]"

def test(li):
    for x in li:
        process(x)

def main(argv=None):
    if argv is None:
        argv = sys.argv

    test(["a b (_a0, fun(arg1, arg2), a b (f,g),i)"])

    while True:
        line = raw_input("* ")
        if line == "q":
            print "Bye."
            sys.exit(0)
        process(line)

if __name__ == "__main__":
    main()

No comments:

Post a Comment