27 March 2000 Release 2.22 Notes for New Users of PCCTS Version 1.33MR22
21
#106. #tokclass can replace a rule consisting only of alternatives with terminals (no actions)
One can replace:
addOp : "\+" | "\-" ;
with:
#tokclass AddOp { "\+" "\-" }
This replaces a modest subroutine with a simple bit test. A #tokclass identifier may be used in a rule wherever a
simple #token identifier may be used.
The other work-around is much more complicated:
expr1! : left:expr2 <<#0=#l;>>
(op:addOp right:expr2 <<#0=#(#op,#left,#right);>> )* ;
addOp : "\+" | "\-" ;
The "!" for rule "expr1" disables automatic constructions of ASTs in the rule. This allows one to manipulate #0
manually. If the expression had no addition operator then the sub-rule "(addOp expr)*" would not be executed and
#0 will be assigned the AST constructed by #left. However if there
is
an addOp present then each time the sub-rule
is rescanned due to the "
(...)*
" the current tree in #0 is placed as the first of two siblings underneath a new tree.
This new tree has the AST returned by addOp as the root. It is a left-leaning tree.
#107. Rather than comment out a rule during testing, add a nonsense token which never matches - See Item #110.
Init-Actions
#108. Don't confuse init-actions with leading-actions (actions which precede a rule)
If the first element following the start of a rule or sub-rule is an action it is always interpreted as an init-action. An
init-action occurs in a scope which includes the entire rule or sub-rule. An action which is
not
an init-action is
enclosed in "{" and "}" during generation of code for the rule and has essentially zero scope - the action itself.
The difference between an init-action and an action which precedes a rule can be especially confusing when an
action appears at the start of an alternative. These
appear
to be almost identical, but they aren't:
b : <<int i=0;>> b1 > [i] /* b1 <<...>> is an init-action */
| <<int j=0;>> b2 > [j] /* b2 <<...>> is part of the rule */
; /* and will cause a compilation error */
On line "b1" the
<<...>>
appears immediately after the beginning of the rule making it an init-action. On line
"b2" the
<<...>>
does
not
appear at the start of a rule or sub-rule, thus it is interpreted as a leading action which
happens to precede the rule.
This can be especially dangerous if you are in the habit of rearranging the order of alternatives in a rule.
For instance, changing this:
b : <<int i=0,j=0;>> <<i++;>> b1 > [i] /* c1 */
| <<j++;>> b1 > [i] /* c2 */
;
to this:
b : /* empty production */ /* d1 */
| <<int i=0,j=0;>> <<i++;>> b1 > [i] /* d2 */
| <<j++;>> b1 > [i]
;
or to this:
b
: <<j++;>> b1 > [i] /* e1 */
| <<int i=0,j=0;>> <<i++;>> b1 > [i] /* e2 */
;
changes an init-action into a non-init action, and vice-versa.