/*
 ************************************************************************
 * 	An illustration how such a theoretical (abstract) thing as
 * 	  FSM can be actually used for mundane programming tasks
 *
 * The problem:
 *	write a filter converting an input stream into an output
 *	stream
 *
 * Input stream:
 *   made up of words separated by whitespaces: not-a-white-space+
 *   whitespace: {' ','\n','\t','\r','\f'}
 *   comments: \/* ... *\/, cannot be nested
 *	(the backspace here and below is used as an esc-character)
 *
 * Output stream
 *   throw away all the comments
 *   one word per line (no leading/trailing whitespaces)
 *
 * For example, the following input stream
 *
 * aaa bbb c,
 *      d     \n
 *
 * : e*\/**\// /* aaa
 * /*   ****a/ //// *
 * /   *\/  *\/
 * t1 /***\/ t2
 * k     :+*+/+
 *
 * should be converted as
 * aaa
 * bbb
 * c,
 * d
 * :
 * e*\/
 * *\/
 * t1
 * t2
 * k
 * :+*+/+
 *
 *
 * The following elementary auutomaton implements the whole thing
 *
 * State	Expecting char	Action		New State
 * 0		white-space	putc('\n')	1
 * 0		'/'		-		2
 * 0		any		putc(c)		0
 *
 * 1		white-space	-		1
 * 1		any		putpack(c)	0
 *
 * 2		'*'		-		3
 * 2		any	   putc('/'),putback(c)	0
 *
 * 3		'*'		-		4
 * 3		any		-		3
 *
 * 4		'/'		-		1
 * 4		any	      putback(c)	3
 *
 * Note, a transition to a 'New State' entails reading a new character
 * from the input stream and putting it into a variable 'c'
 *
 * $Id: sample_fsm.c,v 1.2 2002/10/25 23:12:19 oleg Exp oleg $
 *
 ************************************************************************
 */


#include <stdio.h>
#include <ctype.h>

			/* The automaton: takes the current char 'c' */
			/* and processes it depending on its current */
			/* state of mind			     */
			/* Returns the result of processing a char   */
static enum FSM_RESULT { FSM_ate, FSM_regurgitated }
automaton(const int c)
{
  static enum {Q_regular, Q_whitespace, Q_beg_comment, Q_comment,
	       Q_end_comment} state = Q_whitespace; /* Starting state */

  switch(state)
  {
   case Q_regular:
        if( isspace(c) )
	  putchar('\n'), state = Q_whitespace;
        else if( c == '/' )
	  state = Q_beg_comment;
	else
	  putchar(c);
	return FSM_ate;

   case Q_whitespace:
	return isspace(c) ? FSM_ate : (state = Q_regular, FSM_regurgitated);

   case Q_beg_comment:
	return c == '*' ? (state = Q_comment, FSM_ate) :
	                  (putchar('/'), state = Q_regular, FSM_regurgitated);

   case Q_comment:
	if( c == '*' )
	  state = Q_end_comment;
	return FSM_ate;

   case Q_end_comment:
     if( c=='/' ) 
       return state = Q_whitespace, FSM_ate;
       return state = Q_comment, FSM_regurgitated;
  }
}

static volatile void help(void)
{
  fprintf(stderr,"A filter that lists all the words from the input\n");
  fprintf(stderr,"stream one per line, ignoring C-style comments\n\n");
  exit(4);
}

int main(const int argc, const char * argv[])
{
  register int c;

  if( argc > 1 )
   help();			/* No arguments are expected	*/

  while( (c=getchar()) != EOF )
   if( automaton(c) == FSM_regurgitated )
    ungetc(c,stdin);
  automaton(' ');		/* Treat the EOF as a whitespace	*/
  return 0;
}

