Pretty Scheme, ??? Python
Paul McGuire
ptmcg at austin.rr.com
Tue Jul 3 09:38:29 EDT 2007
Neil -
>> The above shadows 'id'; I suppose 'ident' would be better.
Doh! I found the id() shadowing later, changed my var to id_ so as
not to stray from your BNF too much.
>> How can I make it barf for testcases like '(+ 2 3))'? It doesn't
>> seem to expect an Eof.
To force parsing to the end of string, add a StringEnd instance
where you expect there to be the end of the input string. Change:
waeTree = wae.parseString(t)
to:
waeTree = (wae + StringEnd()).parseString(t)
>> The muss is that,
>> since all the __init__ functions now expect a token list instead
>> of named arguments, they are now cryptic, and creating AST's
>> manually became annoying. The fuss is that I do have to create
>> one in With's calc function. It should be unnecessary for the
>> AST objects to be so dependent upon the grammar to work
>> correctly.
I agree 1000%. The pyparsing method for this is to use
setResultsName. Here is the grammar, with results names defined
to match those in your original. And you are absolutely correct,
using named fields like this makes your code MUCH more robust, and
less dependent on the grammar.
num = Combine( Optional("-") + Word(nums) ).setResultsName("n")
id_ = oneOf( list(alphas) ).setResultsName("v")
addwae = Group( LPAR + "+" + wae.setResultsName("lhs") +
wae.setResultsName("rhs") + RPAR )
subwae = Group( LPAR + "-" + wae.setResultsName("lhs") +
wae.setResultsName("rhs") + RPAR )
withwae = Group( LPAR + "with" + LPAR +
id_.setResultsName("bound_id") +
wae.setResultsName("named_expr") + RPAR +
wae.setResultsName("bound_body") + RPAR )
Now your calc methods can refer to them using:
self.tokens.lhs
self.tokens.bound_id
etc.
Here is my alternative solution (not using results names). I used
the base WAE class to accept the tokens as the initialization var,
then unpack the list into variables in each respective calc()
method. I did not see the need for a subst() method. There is a
complete s-exp parser at the pyparsing wiki examples page:
http://pyparsing.wikispaces.com/space/showimage/sexpParser.py
-- Paul
class WAE(object):
ids = {}
def __init__(self,tokens):
# need to deref element 0 because of Groups
self.tokens = tokens[0]
class NumWAE(WAE):
def calc(self):
return int(self.tokens)
class IdWAE(WAE):
def getId(self):
return self.tokens
def calc(self):
return WAE.ids[self.getId()][-1]
class BinOpWAE(WAE):
def calc(self):
op,a,b = self.tokens
return self.opfn(a.calc(), b.calc())
class AddWAE(BinOpWAE):
opfn = staticmethod(lambda a,b:a+b)
class SubWAE(BinOpWAE):
opfn = staticmethod(lambda a,b:a-b)
class WithWAE(WAE):
def calc(self):
op,varid,varexpr,withexpr = self.tokens
varname = varid.getId()
if varname not in WAE.ids:
WAE.ids[varname] = []
WAE.ids[varname].append( varexpr.calc() )
ret = withexpr.calc()
WAE.ids[varname].pop()
return ret
for expr,cls in zip((num,id_,addwae,subwae,withwae),
(NumWAE,IdWAE,AddWAE,SubWAE,WithWAE)):
expr.setParseAction(cls)
for t in tests:
print t
waeTree = wae.parseString(t)[0]
print waeTree.calc()
print
More information about the Python-list
mailing list