Hi Ivan,
Thanks for replying, and sorry for being unclear. By different levels I just mean that I need a non-greedy * for a low-level rule that gets combined in different ways higher up. I'm able to write a correct parser by "flattening out" the rules, but since it's a big grammar (173 rules) that quickly gets messy.
Here's an excerpt from the real rules. Practically speaking, the problem is that by itself, "ex:abc)" is a valid PrefixedName, but in the _expression_ "(?var) { (ex:abc) }" only "ex:abc" should be parsed as a PrefixedName, and the ")" as part of the InlineDataFull.
PN_LOCAL_ESC ::= '\' ( '_' | '~' | '.' | '-' | '!' | '$' | '&' | "'" | '(' | ')' | '*' | '+' | ',' | ';' | '=' | '/' | '?' | '#' | '@' | '%' )
PLX ::= PERCENT | PN_LOCAL_ESC
PN_LOCAL ::= (PN_CHARS_U | ':' | [0-9] | PLX ) ((PN_CHARS | '.' | ':' | PLX)* (PN_CHARS | ':' | PLX) )?
PNAME_LN ::= PNAME
PrefixedName ::= PNAME_LN | PNAME_NS
iri ::= IRIREF | PrefixedName
DataBlockValue ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | 'UNDEF'
InlineDataFull ::= ( NIL | '(' Var* ')' ) '{' ( '(' DataBlockValue* ')' | NIL )* '}'
With my limited understanding of lexgen's internals, I can write a * that backtracks if it catches an error from a later success continuation, but this doesn't compose with something like opt that doesn't signal an error:
(define (bstar p)
(lambda (sk fk strm)
(let ((try
(lambda (s)
(let ((ss (sk s)))
(if (equal? ss '(error)) #f
ss)))))
(p (lambda (strm1)
(or
((bstar p) try sk strm1)
(sk strm)))
sk
strm))))
(lex (seq (bstar (lit "a")) (lit "a")) err "aaaaab")) ; => ((a a a a a) (b))
but
(lex (opt (seq (bstar (lit a)) (lit a))) err "aaaaab") ; => (() (a a a a a b))
Does this make more sense?
Nathaniel