Both sides previous revision
Previous revision
|
|
contextual_predicates [2021/02/08 18:09] revusky ↷ Page name changed from lookbehind to contextual_predicates |
contextual_predicates [2021/02/08 18:14] (current) revusky |
====== Lookbehind Predicates ====== | ====== Contextual Predicates ====== |
| |
A //lookbehind predicate// allows you to add conditions at [[choice points]] based on scanning back in the call/lookahead stack. Note that this is a completely new feature in JavaCC 21 that does not exist in the legacy JavaCC tool. | A //contextual predicate// allows you to add conditions at [[choice points]] based on scanning back in the call/lookahead stack. Note that this is a completely new feature in JavaCC 21 that does not exist in the legacy JavaCC tool. |
| |
The easiest way to describe this is with some actual examples. | The easiest way to describe this is with some actual examples. |
==== Specifying that a production is non-reentrant ==== | ==== Specifying that a production is non-reentrant ==== |
| |
Probably the most typical usage will be to guarantee that a production is not //re-entrant//, i.e. that it is not allowed to nest recursively. This can now be expressed very cleanly with a //lookbehind predicate// as follows: | Probably the most typical usage will be to guarantee that a production is not //re-entrant//, i.e. that it is not allowed to nest recursively. This can now be expressed very cleanly with a //contextual predicate// as follows: |
| |
<code> | <code> |
==== Scanning Forward vs. Backward, Ellipsis and Wild-card ==== | ==== Scanning Forward vs. Backward, Ellipsis and Wild-card ==== |
| |
Note that the elements in a //lookbehind predicate// are separated either with a backslash "\" or a forward slash "/". The previous example used a backslash and that means that we scan backwards from the current production up towards the root; a forward slash means that we are scanning forward from the root. | Note that the elements in a //contextual predicate// are separated either with a backslash "\" or a forward slash "/". The previous example used a backslash and that means that we scan backwards from the current production up towards the root; a forward slash means that we are scanning forward from the root. |
| |
In the above example, the ellipsis "..." that follows the backslash means that there can be an arbitrary number of intervening productions in the call stack. The //wild-card// or simply //dot// means that we match the occurrence (exactly one!) of any production. If, for example, we wrote: | In the above example, the ellipsis "..." that follows the backslash means that there can be an arbitrary number of intervening productions in the call stack. The //wild-card// or simply //dot// means that we match the occurrence (exactly one!) of any production. If, for example, we wrote: |
==== Summary ==== | ==== Summary ==== |
| |
A //lookbehind predicate// starts optionally with a tilde "~" to indicate negation. The first character after the tilde (or simply the first character if there is no tilde) must be either a backslash or a forward slash. The backslash indicates that we are scanning backwards from the current production and the forward slash means that we are scanning forward from the current production. | A //contextual predicate// starts optionally with a tilde "~" to indicate negation. The first character after the tilde (or simply the first character if there is no tilde) must be either a backslash or a forward slash. The backslash indicates that we are scanning backwards from the current production and the forward slash means that we are scanning forward from the current production. |
| |
An ellipsis "..." means that we can have an arbitrary number (including zero) of intervening productions. A dot "." means that we have exactly one production of any type. | An ellipsis "..." means that we can have an arbitrary number (including zero) of intervening productions. A dot "." means that we have exactly one production of any type. |
NB. If you have a ''SCAN'' statement that does not specify either numerical or syntactic lookahead, then the generated code will scan ahead an //unlimited// number of tokens. (Unless the expansion to be parsed is constrained by an [[up to here]] marker.) This is a key characteristic of the newer [[scan statement]]. | NB. If you have a ''SCAN'' statement that does not specify either numerical or syntactic lookahead, then the generated code will scan ahead an //unlimited// number of tokens. (Unless the expansion to be parsed is constrained by an [[up to here]] marker.) This is a key characteristic of the newer [[scan statement]]. |
| |
Note also that //lookbehind predicates//, like syntactic lookahead in JavaCC 21, can be nested arbitrarily and work in an arbitrarily nested scanahead routine. | Note also that //contextual predicates//, like syntactic lookahead in JavaCC 21, can be nested arbitrarily and work in an arbitrarily nested scanahead routine. |
| |
| |