Beispiel #1
0
/*
 * Called from control when a #define is scanned.  This module
 * parses formal parameters and the replacement string.  When
 * the formal parameter name is encountered in the replacement
 * string, it is replaced by a character in the range 128 to
 * 128+NPARAM (this allows up to 32 parameters within the
 * Dec Multinational range).
 *
 * There is some special case code to distinguish
 *      #define foo     bar
 * from #define foo()   bar
 *
 * Also, we make sure that
 *      #define foo     foo
 * expands to "foo" but doesn't put cpp into an infinite loop.
 *
 * A warning message is printed if you redefine a symbol to a
 * different text.  I.e,
 *      #define foo     123
 *      #define foo     123
 * is ok, but
 *      #define foo     123
 *      #define foo     +123
 * is not.
 *
 * The following subroutines are called from define():
 * checkparm    called when a token is scanned.  It checks through the
 *              array of formal parameters.  If a match is found, the
 *              token is replaced by a control byte which will be used
 *              to locate the parameter when the macro is expanded.
 * textput      puts a string in the macro work area (parm[]), updating
 *              parmp to point to the first free byte in parm[].
 *              textput() tests for work buffer overflow.
 * charput      puts a single character in the macro work area (parm[])
 *              in a manner analogous to textput().
 */
void dodefine()
{
    int c;
    DEFBUF* dp;            /* -> new definition    */
    int isredefine;        /* TRUE if redefined    */
    char* old = NULL;         /* Remember redefined   */

    if (type[(c = skipws())] != LET)
        goto bad_define;
    isredefine = FALSE;                     /* Set if redefining    */
    if ((dp = lookid(c)) == NULL)           /* If not known now     */
        dp = defendel(token, FALSE);        /* Save the name        */
    else                                    /* It's known:          */
    {
        isredefine = TRUE;                  /* Remember this fact   */
        old = dp->repl;                     /* Remember replacement */
        dp->repl = NULL;                    /* No replacement now   */
    }
    parlist[0] = parmp = parm;              /* Setup parm buffer    */
    if ((c = get()) == '(')                 /* With arguments?      */
    {
        nargs = 0;                          /* Init formals counter */
        do                                  /* Collect formal parms */
        {
            if (nargs >= LASTPARM)
                cfatal("Too many arguments for macro", NULLST);
            else if ((c = skipws()) == ')')
                break;                      /* Got them all         */
            else if (type[c] != LET)        /* Bad formal syntax    */
                goto bad_define;
            scanid(c);                      /* Get the formal param */
            parlist[nargs++] = parmp;       /* Save its start       */
            textput(token);                 /* Save text in parm[]  */
        }
        while ((c = skipws()) == ',');      /* Get another argument */
        if (c != ')')                       /* Must end at )        */
            goto bad_define;
        c = ' ';                            /* Will skip to body    */
    }
    else
    {
        /*
         * DEF_NOARGS is needed to distinguish between
         * "#define foo" and "#define foo()".
         */
        nargs = DEF_NOARGS;                 /* No () parameters     */
    }
    if (type[c] == SPA)                     /* At whitespace?       */
        c = skipws();                       /* Not any more.        */
    workp = work;                           /* Replacement put here */
    inmacro = TRUE;                         /* Keep \<newline> now  */
    while (c != EOF_CHAR && c != '\n')      /* Compile macro body   */
    {
        if (c == '#')                       /* Token concatenation? */
        {
            while (workp > work && type[(int)workp[-1]] == SPA)
                --workp;                    /* Erase leading spaces */
            save(TOK_SEP);                  /* Stuff a delimiter    */
            c = skipws();                   /* Eat whitespace       */
            if (type[c] == LET)             /* Another token here?  */
                ;                           /* Stuff it normally    */
            else if (type[c] == DIG)        /* Digit string after?  */
            {
                while (type[c] == DIG)      /* Stuff the digits     */
                {
                    save(c);
                    c = get();
                }
                save(TOK_SEP);              /* Delimit 2nd token    */
            }
            else
            {
                ciwarn("Strange character after # (%d.)", c);
            }
            continue;
        }
        switch (type[c])
        {
        case LET:
            checkparm(c, dp);               /* Might be a formal    */
            break;

        case DIG:                           /* Number in mac. body  */
        case DOT:                           /* Maybe a float number */
            scannumber(c, save);            /* Scan it off          */
            break;

        case QUO:                           /* String in mac. body  */
            stparmscan(c);
            break;

        case BSH:                           /* Backslash            */
            save('\\');
            if ((c = get()) == '\n')
                wrongline = TRUE;
            save(c);
            break;

        case SPA:                           /* Absorb whitespace    */
            /*
             * Note: the "end of comment" marker is passed on
             * to allow comments to separate tokens.
             */
            if (workp[-1] == ' ')           /* Absorb multiple      */
                break;                      /* spaces               */
            else if (c == '\t')
                c = ' ';                    /* Normalize tabs       */
            /* Fall through to store character                      */
        default:                            /* Other character      */
            save(c);
            break;
        }
        c = get();
    }
    inmacro = FALSE;                        /* Stop newline hack    */
    unget();                                /* For control check    */
    if (workp > work && workp[-1] == ' ')   /* Drop trailing blank  */
        workp--;
    *workp = EOS;                           /* Terminate work       */
    dp->repl = savestring(work);            /* Save the string      */
    dp->nargs = nargs;                      /* Save arg count       */
#if OSL_DEBUG_LEVEL > 1
    if (debug)
        dumpadef("macro definition", dp);
    else if (bDumpDefs)
        dumpadef(NULL, dp);
#endif
    if (isredefine)                         /* Error if redefined   */
    {
        if ((old != NULL && dp->repl != NULL && !streq(old, dp->repl)) ||
            (old == NULL && dp->repl != NULL) ||
            (old != NULL && dp->repl == NULL))
        {
#ifdef STRICT_UNDEF
            cerror("Redefining defined variable \"%s\"", dp->name);
#else
            cwarn("Redefining defined variable \"%s\"", dp->name);
#endif
        }
        if (old != NULL)                    /* We don't need the    */
            free(old);                      /* old definition now.  */
    }
    return;

  bad_define:
    cerror("#define syntax error", NULLST);
    inmacro = FALSE;                        /* Stop <newline> hack  */
}
Beispiel #2
0
ReturnCode dodefine(struct Global *global)
{
  /*
   * Called from control when a #define is scanned.  This module
   * parses formal parameters and the replacement string.  When
   * the formal parameter name is encountered in the replacement
   * string, it is replaced by a character in the range 128 to
   * 128+NPARAM (this allows up to 32 parameters within the
   * Dec Multinational range).  If cpp is ported to an EBCDIC
   * machine, you will have to make other arrangements.
   *
   * There is some special case code to distinguish
   *	#define foo	bar
   * from #define foo()   bar
   *
   * Also, we make sure that
   *	#define foo	foo
   * expands to "foo" but doesn't put cpp into an infinite loop.
   *
   * A warning message is printed if you redefine a symbol to a
   * different text.  I.e,
   *	#define foo	123
   *	#define foo	123
   * is ok, but
   *	#define foo	123
   *	#define foo	+123
   * is not.
   *
   * The following subroutines are called from define():
   * checkparm	called when a token is scanned.  It checks through the
   *		array of formal parameters.  If a match is found, the
   *		token is replaced by a control byte which will be used
   *		to locate the parameter when the macro is expanded.
   * textput	puts a string in the macro work area (parm[]), updating
   *		parmp to point to the first free byte in parm[].
   *		textput() tests for work buffer overflow.
   * charput	puts a single character in the macro work area (parm[])
   *		in a manner analogous to textput().
   */
  int c;
  DEFBUF *dp;	/* -> new definition	*/
  int isredefine;	/* TRUE if redefined	*/
  char *old = NULL;		/* Remember redefined	*/
  ReturnCode ret;
#if OK_CONCAT
  int quoting;	/* Remember we saw a #	*/
#endif
  
  if (type[(c = skipws(global))] != LET) {
    cerror(global, ERROR_DEFINE_SYNTAX);
    global->inmacro = FALSE;		/* Stop <newline> hack	*/
    return(FPP_OK);
  }
  isredefine = FALSE;			/* Set if redefining	*/
  if ((dp = lookid(global, c)) == NULL) { /* If not known now     */
    dp = defendel(global, global->tokenbuf, FALSE); /* Save the name  */
    if(!dp)
      return(FPP_OUT_OF_MEMORY);
  } else {				/* It's known:          */
    isredefine = TRUE;			/* Remember this fact	*/
    old = dp->repl;			/* Remember replacement */
    dp->repl = NULL;			/* No replacement now	*/
  }
  global->parlist[0] = global->parmp = global->parm; /* Setup parm buffer */
  if ((c = get(global)) == '(') {       /* With arguments?      */
    global->nargs = 0;			/* Init formals counter */
    do {				/* Collect formal parms */
      if (global->nargs >= LASTPARM) {
	cfatal(global, FATAL_TOO_MANY_ARGUMENTS_MACRO);
	return(FPP_TOO_MANY_ARGUMENTS);
      } else if ((c = skipws(global)) == ')')
	break;			/* Got them all 	*/
      else if (type[c] != LET) {         /* Bad formal syntax    */
	cerror(global, ERROR_DEFINE_SYNTAX);
	global->inmacro = FALSE;		/* Stop <newline> hack	*/
	return(FPP_OK);
      }
      scanid(global, c);                        /* Get the formal param */
      global->parlist[global->nargs++] = global->parmp; /* Save its start */
      ret=textput(global, global->tokenbuf); /* Save text in parm[]  */
      if(ret)
	return(ret);
    } while ((c = skipws(global)) == ',');    /* Get another argument */
    if (c != ')') {                     /* Must end at )        */
      cerror(global, ERROR_DEFINE_SYNTAX);
      global->inmacro = FALSE;		/* Stop <newline> hack	*/
      return(FPP_OK);
    }
    c = ' ';                            /* Will skip to body    */
  }
  else {
    /*
     * DEF_NOARGS is needed to distinguish between
     * "#define foo" and "#define foo()".
     */
    global->nargs = DEF_NOARGS;		/* No () parameters     */
  }
  if (type[c] == SPA)                   /* At whitespace?       */
    c = skipws(global);                 /* Not any more.        */
  global->workp = global->work;		/* Replacement put here */
  global->inmacro = TRUE;		/* Keep \<newline> now	*/
  quoting = 0;				/* No # seen yet.	*/
  while (c != EOF_CHAR && c != '\n') {  /* Compile macro body   */
#if OK_CONCAT
    if (c == '#') {                     /* Token concatenation? */
      if ((c = get(global)) != '#') {   /* No, not really       */
	quoting = 1;		        /* Maybe quoting op.	*/
	continue;
      }
      while (global->workp > global->work && type[(unsigned)*(global->workp - 1)] == SPA)
	--global->workp;		/* Erase leading spaces */
      if((ret=save(global, TOK_SEP)))     /* Stuff a delimiter    */
	return(ret);
      c = skipws(global);               /* Eat whitespace       */
      continue;
    }
#endif
    switch (type[c]) {
    case LET:
#if OK_CONCAT
      ret=checkparm(global, c, dp, quoting);      /* Might be a formal    */
#else
      ret=checkparm(c, dp);               /* Might be a formal    */
#endif
      if(ret)
	return(ret);
      break;
	
    case DIG:				/* Number in mac. body	*/
    case DOT:				/* Maybe a float number */
      ret=scannumber(global, c, save);  /* Scan it off          */
      if(ret)
	return(ret);
      break;
	
    case QUO:				/* String in mac. body	*/
      ret=stparmscan(global, c);
      if(ret)
	return(ret);
      break;
	
    case BSH:				/* Backslash		*/
      ret=save(global, '\\');
      if(ret)
	return(ret);
      if ((c = get(global)) == '\n')
	global->wrongline = TRUE;
      ret=save(global, c);
      if(ret)
	return(ret);
      break;
      
    case SPA:				/* Absorb whitespace	*/
      /*
       * Note: the "end of comment" marker is passed on
       * to allow comments to separate tokens.
       */
      if (global->workp[-1] == ' ')   /* Absorb multiple      */
	break;			/* spaces		*/
      else if (c == '\t')
	c = ' ';                      /* Normalize tabs       */
      /* Fall through to store character			*/
    default:				/* Other character	*/
      ret=save(global, c);
      if(ret)
	return(ret);
      break;
    }
    c = get(global);
    quoting = 0;			/* Only when immediately*/
    /* preceding a formal	*/
  }
  global->inmacro = FALSE;		/* Stop newline hack	*/
  unget(global);                            /* For control check    */
  if (global->workp > global->work && global->workp[-1] == ' ') /* Drop trailing blank  */
    global->workp--;
  *global->workp = EOS;		/* Terminate work	*/
  dp->repl = savestring(global, global->work); /* Save the string      */
  dp->nargs = global->nargs;			/* Save arg count	*/
  if (isredefine) {                   /* Error if redefined   */
    if ((old != NULL && dp->repl != NULL && !streq(old, dp->repl))
	|| (old == NULL && dp->repl != NULL)
	|| (old != NULL && dp->repl == NULL)) {
      cerror(global, ERROR_REDEFINE, dp->name);
    }
    if (old != NULL)                  /* We don't need the    */
      free(old);                      /* old definition now.  */
  }
  return(FPP_OK);
}
Beispiel #3
0
/*
 * Main process for cpp -- copies tokens from the current input
 * stream (main file, include file, or a macro) to the output
 * file.
 */
void cppmain()
{
    int c;              /* Current character    */
    int counter;        /* newlines and spaces  */

    /*
     * Explicitly output a #line at the start of cpp output so
     * that lint (etc.) knows the name of the original source
     * file.  If we don't do this explicitly, we may get
     * the name of the first #include file instead.
     * We also seem to need a blank line following that first #line.
     */
#ifdef EVALDEFS
    if ( !bIsInEval )
#endif
    {
        sharp();
        PUTCHAR('\n');
    }
    /*
     * This loop is started "from the top" at the beginning of each line
     * wrongline is set TRUE in many places if it is necessary to write
     * a #line record.  (But we don't write them when expanding macros.)
     *
     * The counter variable has two different uses:  at
     * the start of a line, it counts the number of blank lines that
     * have been skipped over.  These are then either output via
     * #line records or by outputting explicit blank lines.
     * When expanding tokens within a line, the counter remembers
     * whether a blank/tab has been output.  These are dropped
     * at the end of the line, and replaced by a single blank
     * within lines.
     */
    for (;;)
    {
        counter = 0;                        /* Count empty lines    */
        for (;;)
        {                                   /* For each line, ...   */
            while (type[(c = get())] == SPA) /* Skip leading blanks */
                ;                           /* in this line.        */
            if (c == '\n')                  /* If line's all blank, */
                ++counter;                  /* Do nothing now       */
            else if (c == '#')
            {            /* Is 1st non-space '#' */
                keepcomments = FALSE;       /* Don't pass comments  */
                counter = control(counter); /* Yes, do a #command   */
                keepcomments = (cflag && compiling);
            }
            else if (c == EOF_CHAR)         /* At end of file?      */
            {
                break;
            }
            else if (!compiling)
            {                               /* #ifdef false?        */
                skipnl();                   /* Skip to newline      */
                counter++;                  /* Count it, too.       */
            }
            else
            {
                break;                      /* Actual token         */
            }
        }
        if (c == EOF_CHAR)                  /* Exit process at      */
            break;                          /* End of file          */
        /*
         * If the loop didn't terminate because of end of file, we
         * know there is a token to compile.  First, clean up after
         * absorbing newlines.  counter has the number we skipped.
         */
        if ((wrongline && infile->fp != NULL) || counter > 4)
            sharp();                        /* Output # line number */
        else
        {                                   /* If just a few, stuff */
            while (--counter >= 0)          /* them out ourselves   */
                PUTCHAR('\n');
        }
        /*
         * Process each token on this line.
         */
        unget();                            /* Reread the char.     */
        for (;;)
        {                                   /* For the whole line,  */
            do
            {                            /* Token concat. loop   */
                for (counter = 0; type[(c = get())] == SPA;)
                {
#if COMMENT_INVISIBLE
                    if (c != COM_SEP)
#endif
                    counter++;              /* Skip over blanks     */

                }
                if (c == EOF_CHAR || c == '\n')
                    goto end_line;          /* Exit line loop       */
                else if (counter > 0)       /* If we got any spaces */
                    PUTCHAR(' ');           /* Output one space     */
                c = macroid(c);             /* Grab the token       */
            }
            while (type[c] == LET && catenate());

            if (c == EOF_CHAR || c == '\n') /* From macro exp error */
                goto end_line;              /* Exit line loop       */

            switch (type[c])
            {
            case LET:
                fputs(token, pCppOut);       /* Quite ordinary token */
#ifdef EVALDEFS
                {
                    int len;
                    if ( bIsInEval
                         && nEvalOff + (len=strlen(token)) < NEVALBUF )
                    {
                        strcpy( &EvalBuf[nEvalOff], token );
                        nEvalOff += len;
                    }
                }
#endif
                break;


            case DIG:                       /* Output a number      */
            case DOT:                       /* Dot may begin floats */
#ifdef EVALDEFS
                if ( bIsInEval )
                    scannumber(c, outputEval);
                else
                    scannumber(c, output);
#else
                scannumber(c, output);
#endif
                break;

            case QUO:                       /* char or string const */
                scanstring(c, output);      /* Copy it to output    */
                break;

            default:                        /* Some other character */
                cput(c);                    /* Just output it       */
#ifdef EVALDEFS
                if ( bIsInEval && nEvalOff < NEVALBUF )
                    EvalBuf[nEvalOff++] = c;
#endif
                break;
            }                               /* Switch ends          */
        }                                   /* Line for loop        */
      end_line:
        if (c == '\n')
        {                                   /* Compiling at EOL?    */
            PUTCHAR('\n');                  /* Output newline, if   */
            if (infile->fp == NULL)         /* Expanding a macro,   */
                wrongline = TRUE;           /* Output # line later  */
        }
    }                                       /* Continue until EOF   */
#ifdef EVALDEFS
    if ( bIsInEval )
        EvalBuf[nEvalOff++] = '\0';
#endif
}
Beispiel #4
0
INLINE FILE_LOCAL
ReturnCode cppmain(struct Global *global)
{
  /*
   * Main process for cpp -- copies tokens from the current input
   * stream (main file, include file, or a macro) to the output
   * file.
   */

  int c;        /* Current character    */
  int counter;  /* newlines and spaces  */
  ReturnCode ret; /* return code variable type */

  long bracelevel = 0;
  long parenlevel = 0;
  long bracketlevel = 0;
  int fake = 0;

#define MAX_FUNC_LENGTH 50

  char tempfunc[MAX_FUNC_LENGTH + 1];
  char tempfunc2[MAX_FUNC_LENGTH + 1];
  char define = 0; /* probability of a function define phase in the program */
  char prev = 0; /* previous type */
  char go = 0;
  char include = 0;
  char initfunc = 0;

  /* Initialize for reading tokens */
  global->tokenbsize = 50;
  global->tokenbuf = malloc(global->tokenbsize + 1);
  if(!global->tokenbuf)
    return(FPP_OUT_OF_MEMORY);

  global->functionname = malloc(global->tokenbsize + 1);
  if(!global->functionname)
    return(FPP_OUT_OF_MEMORY);
  global->functionname[0] = '\0';

  if(global->showspace) {
    global->spacebuf = (char *)malloc(MAX_SPACE_SIZE);
    if(!global->spacebuf)
      return(FPP_OUT_OF_MEMORY);
  }

  if(global->showversion)
      Error(global, VERSION_TEXT);

  /*
   * Explicitly output a #line at the start of cpp output so
   * that lint (etc.) knows the name of the original source
   * file.  If we don't do this explicitly, we may get
   * the name of the first #include file instead.
   */
  if(global->linelines) /* if #line lines are wanted! */
    sharp(global);
  /*
   * This loop is started "from the top" at the beginning of each line
   * wrongline is set TRUE in many places if it is necessary to write
   * a #line record.  (But we don't write them when expanding macros.)
   *
   * The counter variable has two different uses:  at
   * the start of a line, it counts the number of blank lines that
   * have been skipped over. These are then either output via
   * #line records or by outputting explicit blank lines.
   * When expanding tokens within a line, the counter remembers
   * whether a blank/tab has been output.  These are dropped
   * at the end of the line, and replaced by a single blank
   * within lines.
   */

  include = global->included;

  while(include--) {
    openinclude(global, global->include[include], TRUE);
  }
  
  for (;;) {
    counter = 0;                        /* Count empty lines    */
    for (;;) {                          /* For each line, ...   */
      global->comment = FALSE;          /* No comment yet!      */
      global->chpos = 0;                /* Count whitespaces    */
      while (type[(c = get(global))] == SPA)  /* Skip leading blanks */
	if(global->showspace) {
	  if(global->chpos<MAX_SPACE_SIZE-1)
	    /* we still have buffer to store this! */
	    global->spacebuf[global->chpos++]=(char)c;
	}
      if (c == '\n') {                  /* If line's all blank, */
	if(global->comment) {
	  /* A comment was output! */
	  Putchar(global, '\n');
	}
	else
	  ++counter;                    /* Do nothing now       */
      }
      else if (c == '#') {              /* Is 1st non-space '#' */
	global->keepcomments = FALSE;   /* Don't pass comments  */
	ret = control(global, &counter); /* Yes, do a #command   */
	if(ret)
	  return(ret);
	global->keepcomments = (global->cflag && compiling);
      }
      else if (c == EOF_CHAR)           /* At end of file?      */
	break;
      else if (!compiling) {            /* #ifdef false?        */
	skipnl(global);                 /* Skip to newline      */
	counter++;                      /* Count it, too.       */
      } else {
	break;                          /* Actual token         */
      }
    }
    if (c == EOF_CHAR)                  /* Exit process at      */
      break;                            /* End of file          */
    /*
     * If the loop didn't terminate because of end of file, we
     * know there is a token to compile.  First, clean up after
     * absorbing newlines.  counter has the number we skipped.
     */
    if(global->linelines) { /* if #line lines are wanted! */
      if ((global->wrongline && global->infile->fp != NULL) || counter > 4)
        sharp(global);                    /* Output # line number */
      else {                              /* If just a few, stuff */
        while (--counter >= 0)            /* them out ourselves   */
	  Putchar(global, (int)'\n');
      }
    }
    if(global->showspace) {
      /* Show all whitespaces! */
      global->spacebuf[global->chpos] = '\0';
      Putstring(global, global->spacebuf);
    }
    
    /*
     * Process each token on this line.
     */
    unget(global);                      /* Reread the char.     */
    for (;;) {                          /* For the whole line,  */
      do {                              /* Token concat. loop   */
	for (global->chpos = counter = 0; (type[(c = get(global))] == SPA);) {
#if COMMENT_INVISIBLE
	  if (c != COM_SEP)
	    counter++;
#else
	  if(global->showspace && global->chpos < MAX_SPACE_SIZE-1) {
	    global->spacebuf[global->chpos++]=(char)c;
	  }
	  counter++;            /* Skip over blanks     */
#endif
	}
	if (c == EOF_CHAR || c == '\n')
	  break;                      /* Exit line loop       */
	else if (counter > 0) {       /* If we got any spaces */
	  if(!global->showspace)      /* We don't output all spaces */
	    Putchar(global, (int)' ');/* Output one space     */
	  else {
	    global->spacebuf[global->chpos] = '\0';
	    Putstring(global, global->spacebuf); /* Output all whitespaces */
	  }
	}
	if(ret=macroid(global, &c))   /* Grab the token       */
	  return(ret);
      } while (type[c] == LET && catenate(global, &ret) && !ret);
      if(ret)
	/* If the loop was broken because of a fatal error! */
	return(ret);
      if (c == EOF_CHAR || c == '\n') /* From macro exp error */
	break;                        /* Exit line loop       */
      go++;
      switch (type[c]) {
      case LET:
	go =0;
	/* Quite ordinary token */
	Putstring(global, global->tokenbuf);
	
	if(!define) {
	  /* Copy the name */
	  strncpy(tempfunc, global->tokenbuf, MAX_FUNC_LENGTH);
          tempfunc[MAX_FUNC_LENGTH]=0;
	}
	/* fputs(global->tokenbuf, stdout); */
	break;
      case DIG:                 /* Output a number      */
      case DOT:                 /* Dot may begin floats */
	go = 0;
	ret=scannumber(global, c, (ReturnCode(*)(struct Global *, int))output);
	if(ret)
	  return(ret);
	break;
      case QUO:                 /* char or string const */
	go = 0;
	/* Copy it to output */
        if(!global->webmode) {
          ret=scanstring(global, c,
                         (ReturnCode(*)(struct Global *, int))output);
          if(ret)
            return(ret);
          break;
        }
        /* FALLTHROUGH */
      default:                  /* Some other character */
	
	define++;
	switch(c) {
	case '{':
	  if(! bracelevel++ && define > 2) {
	    /*
	     * This is a starting brace. If there is a probability of a
	     * function defining, we copy the `tempfunc' function name to
	     * `global->functionname'.
	     */
	    strcpy(global->functionname, tempfunc2);
	    global->funcline = global->line;

		if(global->outputfunctions) {
			/*
			 * Output the discovered function name to stderr!
			 */
			Error(global, "#> Function defined at line %d: %s <#\n",
				  global->line,
				  global->functionname);
		}

	    if(global->initialfunc) {
		int a;
		for(a=0; a<global->excluded; a++) {
		    /* check for excluded functions */
		    if(!strcmp(global->functionname,
			       global->excludedinit[a]))
			break;
		}
		if(a==global->excluded) {
		    expstuff(global, "__brace__", "{");
		    expstuff(global, "__init_func__", global->initialfunc);
		    initfunc = TRUE;
		}
	    }

	  }
	  break;
	case '}':
	  go = 0;
	  if( (--bracelevel == initfunc) &&
	     strcmp(global->infile->filename, "__init_func__") ) {
	    /* we just stepped out of the function! */
	    global->functionname[0] = '\0';
	    global->funcline = 0;
	    define = 1;

	    if(initfunc) {
	      Putchar(global, '}');
	      bracelevel--;
	      initfunc=0;
	    }
	  }
	  fake = 0;
	  break;
	  
	case ';':
	case ',':
	  if(go == 2) {
	    define = 1;
	    fake = 0;
	    go--;
	    break;
	  }
	  break;
	case '(':
	  if(! parenlevel++ && !bracelevel) {
	    if(go == 2) {
	      /* foobar(text) -> "(" is found. This can't be a
		 function */
	      go--;
	      define = 1;
	      break;
	    }
	    if( define < 2 && prev == LET) {
	      /* This is the first parenthesis on the ground brace
		 level, and we did previously not have a probable
		 function name */
	      strncpy(tempfunc2, global->tokenbuf, MAX_FUNC_LENGTH);
              tempfunc2[MAX_FUNC_LENGTH]=0;
	      define++;
	    }
	    else {
	      /* we have a fake start */
	      fake++;
	    }
	  }
	  break;
	case ')':
	  if(! --parenlevel && !bracelevel && define>1 && !fake) {
	    /*
	     * The starting parentheses level and
	     * the starting brace level.
	     * This might be the start of a function defining coming
	     * up!
	     */
	    define++; /* increase probability */
	    fake = 0;
	    go = 1;
	  }
	  break;
	case '[':
	  bracketlevel++;
	  break;
	case ']':
	  bracketlevel--;
	  break;
	}
	define--; /* decrease function probability */
	
	Putchar(global, c);     /* Just output it       */
	break;
      }                         /* Switch ends          */
      prev = type[c];
    }                           /* Line for loop        */
    
    if (c == '\n') {  /* Compiling at EOL?    */
      Putchar(global, '\n');              /* Output newline, if   */
      if (global->infile->fp == NULL)     /* Expanding a macro,   */
	global->wrongline = TRUE; /* Output # line later        */
    }
  }                             /* Continue until EOF   */

  if(global->showbalance) {
    if(bracketlevel) {
      cwarn(global, WARN_BRACKET_DEPTH, bracketlevel);
    }
    if(parenlevel) {
      cwarn(global, WARN_PAREN_DEPTH, parenlevel);
    }
    if(bracelevel) {
      cwarn(global, WARN_BRACE_DEPTH, bracelevel);
    }
  }
  if (global->wflag) {
    global->out = TRUE;         /* enable output */
    outdefines(global);         /* Write out #defines   */
  }
  return(FPP_OK);
}