class ActionBody
{
friend class ActionGen;
ActionBody * next; // The next action in the chain
public:
ActionBody(void) : next(0) {}
virtual void execute(const int curr_char) = 0;// Execute this action
void execute_all(const int curr_char); // Execute this action and
// all that follows
};
class NoAction: public ActionBody
{
public:
void execute(const int curr_char) { cerr << "NoAction" << endl; }
};
curr_char into a formatting buffer
class FormatCurrChar : public ActionBody
{
public:
void execute(const int curr_char) { My_stdout.output_char(curr_char); }
};
class CallOutputSpace : public ActionBody
{
public:
void execute(const int curr_char) { My_stdout.output_space(); }
};
class ActionGen
{
ActionBody * body;
ActionBody * last_in_chain;
protected:
ActionGen(ActionBody * born_body)
: body(born_body), last_in_chain(born_body) {}
public:
operator ActionBody * (void) const { return body; }
// Grow a chain further by a next_body
// (and whatever hangs from it)
ActionGen& operator + (const ActionGen& next_body)
{ last_in_chain->next = next_body;
last_in_chain = next_body.last_in_chain;
assert( last_in_chain->next == 0 );
return *this;
}
};
template <class T> class MA : public ActionGen
{
public:
MA(void) : ActionGen(new T) {}
};
struct Arc;
typedef Arc Node; // Node is just a bunch of arcs
struct Arc // Arc of a FSM
{
int activator; // character-activator or ANY
ActionBody * const actions; // byte-compiled actions
Node * next_node; // Node to follow
};
#define ANY 0xf00 // Matches any symbol
extern Arc N_space[];
// Read characters and fill the current paragraph
Arc N_filling [] =
{
{' ',MA<CallOutputSpace>(),N_space},
{'\t',MA<CallOutputSpace>(),N_space},
{'\n',MA<CallOutputSpace>(),N_space},
{ANY,MA<FormatCurrChar>() + MA<NoAction>() + MA<NoAction>(),N_filling}
};
// Got white spaces: ignore more than one
Arc N_space [] =
{
{' ', MA<NoAction>(),N_space}, // ignore the second wspace etc
{'\t', MA<NoAction>(),N_space},
{'\n', MA<NoAction>(),N_space},
{ANY, MA<FormatCurrChar>(),N_filling}
};
static const Node * const Start_node = N_filling;
Note how several actions can be put together with a + sign
void main(void)
{
const char * sample_string = "abc a\t \nb";
const Node * Current_node = Start_node;
/* Drive the automaton */
for(register const char * cp = sample_string; *cp != '\0'; cp++)
{
register const Arc * curr_arc;
for( curr_arc=Current_node; ; curr_arc++)
if( curr_arc->activator == ANY || curr_arc->activator == *cp )
{
curr_arc->actions->execute_all(*cp);
Current_node = curr_arc->next_node;
break;
}
}
cerr << "Done" << endl;
}