Given an "automatic parser generator" like YACC, we need a
way to indicate what "(semantic) actions" should be associated with
each grammar rule when it is used in a parse to produce the desired
intermediate form.
A grammar can be annotated to indicate where semantic
processing should occur by naming the actions and including the
names at appropriate places in the grammar.
For example, the annotations on the production for the
else-less if statement for a one-pass compiler that generated
assembly language code might look like:
< stmt >
->
if< expr >
#gen-else-branch
then< stmt >end#gen-else-target
A semantic action will typically produce a value to be associated
with a node in the parse tree (not the syntax tree). It may need
to access the values associated with the children of the node it
is to label with a value.
Imagine semantic actions routines that generate code for
expressions:
< expr > -> < expr > + < expr >#gen-add
Each semantic action will need to know
where the value computed for each sub-tree of the expression
will be found at run time (i.e. what register or memory
locations). This information will be provided as the
labels associated with nodes in the parse tree by the
semantic action routines.
The parser should (can, must) help by keeping track of the values
produced by semantic actions as the parser proceeds.
This is simple in a bottom-up parser. When the handle is
reduced, the value produced by any action associated with the
production used is placed in the stack with the non-terminal
to which the handle was reduced.
The parser generator should (can, must) provide a way that actions
can access values associated with terminals and non-terminals in
the handle and specify the value to be associated with the non-terminal
to which the handle is reduced.