Esempio n. 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  */
}
Esempio n. 2
0
File: cpp4.c Progetto: Akaito/bgfx
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);
}