Specialized Actions

In general, semantic actions accept the first-last iterator pair. The action functions or functors receive the unprocessed data representing the matching production directly from the input. There are situations though where we might want to pass data in its processed form. A concrete example is the numeric parser. It is unwise to pass unprocessed data to a semantic action attached to a numeric parser and just throw away what has been done. Here, we might want to pass the actual parsed number.

The function and functor signature of a semantic action varies depending on the parser where it is attached. The following table lists the parsers that accept unique signatures. Parsers not included in the list by default expect the generic signature as explained before.

Numeric Actions
uint_p
int_p
ureal_p
real_p

void func(NumT val); // Signature for functions

struct ftor { // Signature for functors

typedef NumT arg_type; // Required for functors
void operator()(NumT val) const;

};

Where NumT is any primitive numeric type such as int, long, float, double, etc., or a user defined numeric type such as big_int. The parsed number is passed into the function/functor.


Character Actions
chlit, ch_p
range, range_p
anychar
alnum,
alpha
cntrl, digit
graph, lower
print, punct
space, upper
xdigit
chset

void func(CharT ch);

Where CharT is the desired character type. A functor should have a member operator() with a compatible signature as above. The matching character is passed into the function/functor.


Symbol Table Actions
symbols

void func(IteratorT first, IteratorT last, T& data);

Where first points to the current input, last points to one after the end of the input (identical to STL ranges) and data is any information associated with the matching symbol in the symbol table (see the section on Symbols above). A functor should have a member operator() with a compatible signature as above. The matching portion is passed to the function/functor.

Notice that the data associated with the matching symbol is passed by reference to allow it to be modified by the function/functor.

Extracting symbols:

The symbol table class symbols has a member functor add. Symbols may be added dynamically to the symbol table through its member functor add. The member functor add may be attached to a parser as a semantic action:

expr[sym.add]

where expr is an expression that results to a parser and sym is a symbol table. On success, the matching portion of the input is added to the symbol table. Here's an example that extracts valid C/C++ identifiers and puts that in a symbol table sym:

var_decl = lexeme[(alpha >> *(alnum | '_'))[sym.add]];

If you intend to allow source language to add to the symbol table during a parse, you must ensure that the symbol has not already been added previously:

var_decl = lexeme[((alpha >> *(alnum | '_')) - sym)[sym.add]];

This rule ensures that the symbol has not been declared previously. The expression

((alpha >> *(alnum | '_')) - sym)
matches any valid C/C++ identifier that has not yet been added to the symbol table sym.