BNFC allows one to use "internal" rules to aid in syntax directed translation. The canonical example they give is for type annotation
internal VarT . Exp ::= "(" Ident ":" Type ");
This gives us a new part of the AST,
Exp = ... | VarT Ident Type
This works great! However, what would be really nice is if it were possible to allow an arbitrary type to be put there as a placeholder for later.
internal VarT . Exp ::= "(" Ident ":" a ")";
And we would generate a parametric datatype
Exp a = ... | VarT Ident a
Then we could fill this in with a type (for a type checker), or a code segment (for code generation).