if it's more trouble than it's worth to bootstrap...

In retrospect, if I've understood the DSL properly, it's easy enough to use a precedence climbing parser, which, being deterministic, sidesteps the issue completely.

Please ignore my fast, cheap, and out of control sketch; see instead Martin Richard's MCPL code[0] for much cleaner, saner, small OP parsers.

-Dave

[0] http://www.cl.cam.ac.uk/~mr10/mcplman.pdf
Theorem Prover, pp 57-58
Lambda Calculator, p 63

:: :: ::

LIT, VAR, JUX, ALT, SEQ, COM, LOOP = list("LVjascl")
################

E       = lambda c,n: {
        LIT:    lambda t: t[0],
        VAR:    lambda t: lookup(c,t[0]),
        JUX:    lambda t: reduce(conj,mapE(c,t),""),
        ALT:    lambda t: reduce(disj,mapE(c,t),None),
        SEQ:    lambda t: reduce(seq, mapE(c,t),""),
        COM:    lambda t: E(c,t[0]),
        LOOP:   lambda t: loop(c,t),
        }[n[0]](n[1:])

lookup = lambda c,var: reduce(disj,[e.get(var,None) for e in kludge +c],None)
kludge  = [{'':[]}] # null context so var-less LOOPs substitute for DOCs
mapE    = lambda c,t: map(lambda n: E(c,n),t)
loop    = lambda c,(var,n): docomma(doloop(c,var,lbody(n)))
docomma = lambda (comma,xs):            comma.join(xs) if xs else None
doloop  = lambda c,var,(_,body,comma): (E(c,comma), [E([e]+c,body)
for e in (lookup(c,var) or [])])
lbody   = lambda n: n if (n[0]==COM) else (COM,n,(LIT,""))
conj    = lambda x,y: x+y if (p(x) and p(y)) else None
disj    = lambda x,y: x if p(x) else y
seq     = lambda x,y: (x or "")+(y or "")
p       = lambda x:   x is not None

################

O = { '{': (lambda t,a,b: (JUX,a,(LOOP,t[1:],b)), 6,0) # BUGGY should be unary ,None: (lambda t,a,b: (JUX,a,(VAR,t),b), 5,5) # default is varname
    , '=': (lambda t,a,b: (EQ,a,b),               4,4)
    , '|': (lambda t,a,b: (ALT,a,b),              3,3)
    , ';': (lambda t,a,b: (SEQ,a,b),              2,2)
    , ',': (lambda t,a,b: (COM,a,b),              1,1)
    , '}': (lambda t,a,b: None,                   0,None) }

parse = lambda s:      expr(0, brack(s))[0]
brack = lambda s:      sum([seg.split('<') for seg in s.split('>')],[])
expr  = lambda p,xs:   exp1(p,((LIT,xs[0]),xs[1:]))
exp1  = lambda p,ctx:  exp1(p,next(ctx)) if p < prec(ctx) else ctx
prec  = lambda (_,xs): op(xs[0])[1] if xs else -1
op    = lambda x:      O.get(x[0],O[None])
next  = lambda (a,xs): dyad(xs[0],a, rarg(op(xs[0]),xs[1:]))
rarg  = lambda (node,_,tp),tl:     (node,)+expr(tp,tl)
dyad  = lambda tok,a,(node,b,xs):  (node(tok,a,b),xs)

################

if __name__ == "__main__":
        bibt    = "In <booktitle>.<;> <month> <year>."
        bibloop = "\n\t<{author><name><,>, <}>."
        ctx = [{ "year"      : "1381"
               , "month"     : "Farvardin"
, "booktitle" : "Proc. of Tehran Acad. of Linguistics" }]
        auths = [{ "author": [{"name": "Taher Marzian"},
                              {"name": "Shahriar Afshar"}] }]
        for c in [ctx,ctx+auths]:
            for tmpl in [parse(bibt),parse(bibt+bibloop)]:
                print E(c,tmpl) or ""


--
To unsubscribe: http://lists.canonical.org/mailman/listinfo/kragen-discuss

Reply via email to