Requires parser capable to evaluate lookup predicate, such as GLR parser. With additional complexity on declaration side it may solvable by error handling magic but I didn't solve this puzzle so far.
Example: multiple grammar variants in one definition file:
allowed_indirect_method:
INDIRECT_METHOD
| %?{ FEATURE_INDIRECT_IS_ENABLED } METHOD
Example: simplify lexer by moving predicates into grammar (using say to show idea, not a final implementation)
keyword.c:
- return (all_keywords || FEATURE_SAY_IS_ENABLED ? KEY_say : 0);
+ return KEY_say;
toke.c:
case (KEY_say): TOKEN(SAY);
perly.y:
bareword: BAREWORD
| %?{ ! FEATURE_SAY_IS_ENABLED } SAY
;
Example:
expr: expr[lhs] ANDOP expr[rhs]
{ $$ = parser->action->flow_control_and_expression (OP_AND, $lhs, $rhs); }
| expr[lhs] OROP[operator] expr[rhs]
{ $$ = parser->action->flow_control_or_expression ($operator, $lhs, $rhs); }
| listexpr %prec PREC_LOW
Usage of "virtual method table" allows to install different rule handlers (eg: PPI) as well as it will help with obsoleted feature maintenance, for example moving them into dynamically loaded plugins (when feature will be necessary) - plugin loader will just update table with proper implementations.
Example:
expr: expr[lhs] ANDOP expr[rhs]
{ $$ = parser->action->flow_control_and_expression (& (struct expr) {
.operator = OP_AND, .lhs = $lhs, .rhs = $rhs
} ); }
| expr[lhs] OROP[operator] expr[rhs]
{ $$ = parser->action->flow_control_or_expression (& (struct expr) {
.operator = $operator, .lhs = $lhs, .rhs = $rhs
} ); }
| listexpr %prec PREC_LOW
Usage of this pattern proved valuable for me in modernization of complex code (with help of variadic macros - requires C99)
%{
#define EXPR_ACTION(Type, ...) action->Type( & (struct expr) { .operator = 0, .lhs = NULL, .rhs = NULL, __ARGS__ }
#define FLOW_CONTROL_AND_EXPRESSION(First, ...) EXPR_ACTION (flow_control_and_expression, First, __ARGS__ }
#define FLOW_CONTROL_OR_EXPRESSION(First, ...) EXPR_ACTION (flow_control_or_expression, First, __ARGS__ }
}%
expr: expr[lhs] ANDOP expr[rhs]
{ $$ = parser->FLOW_CONTROL_AND_EXPRESSION(.operator = OP_AND, .lhs = $lhs, .rhs = $rhs); }
| expr[lhs] OROP[operator] expr[rhs]
{ $$ = parser->FLOW_CONTROL_OR_EXPRESSION(.operator = $operator, .lhs = $lhs, .rhs = $rhs); }
| listexpr %prec PREC_LOW
- single grammar definition for any perl version (v5, v7, vX ...)
- get rid of toke.c, keyword.c; replace them with as simple as possible (f)lex
- generate language support tools (mvp: emacs perl-mode, PPI tokenizer as parser's virtual method table)
hey, are you actively working on this? I highly support the whole plan that you have here, and would love to help in whatever way I can.
I think even just to rewrite the parser using a GLR (which sounds like it would work) could go a long way for tooling, even if it wouldn't be merged right away upstream.