What are some of the practical examples that require back-tracking (for whatever definition of "require")? The example I was once being told about was parsing assignment expressions:
Expr ::= CanBeLhsOfAssignExpr | CanBeLhsOfAssignExpr "=" Expr | CanNotBeLhsOfAssignExpr
but in practice, it's easily parsed in the following manner: def parse_Expr(self):
# parse_ExprInner parses CanBeLhsOfAssignExpr or CanNotBeLhsOfAssignExpr cases
result = self.parse_ExprInner()
if self.peekToken() == TOKEN_ASSIGN:
if result.is_CanBeLhsOfAssignExpr:
token = self.skipToken()
# assignment is right-associative
rhs = self.parse_Expr()
result = self.make_AssignExpr(token, result, rhs)
else:
self.raiseParseError("{} can't be target of assignment", result)
return result
The idea is to parse the prefix under "relaxed" rules, delaying the well-formedness check until it's actually needed.