Exemplo n.º 1
0
Arquivo: cpp4.c Projeto: Akaito/bgfx
void doundef(struct Global *global)
  /*
   * Remove the symbol from the defined list.
   * Called from the #control processor.
   */
{
  int c;
  if (type[(c = skipws(global))] != LET)
    cerror(global, ERROR_ILLEGAL_UNDEF);
  else {
    scanid(global, c);                         /* Get name to tokenbuf */
    (void) defendel(global, global->tokenbuf, TRUE);
  }
}
Exemplo n.º 2
0
/*
 * Remove the symbol from the defined list.
 * Called from the #control processor.
 */
void doundef()
{
    int c;

    if (type[(c = skipws())] != LET)
        cerror("Illegal #undef argument", NULLST);
    else
    {
        scanid(c);                          /* Get name to token[]  */
        if (defendel(token, TRUE) == NULL)
        {
#ifdef STRICT_UNDEF
            cwarn("Symbol \"%s\" not defined in #undef", token);
#endif
        }
    }
}
Exemplo n.º 3
0
/*
 * Replace this param if it's defined.  Note that the macro name is a
 * possible replacement token.  We stuff DEF_MAGIC in front of the token
 * which is treated as a LETTER by the token scanner and eaten by
 * the output routine.  This prevents the macro expander from
 * looping if someone writes "#define foo foo".
 */
void checkparm(int c, DEFBUF* dp)
{
    int i;
    char* cp;

    scanid(c);                              /* Get parm to token[]  */
    for (i = 0; i < nargs; i++)             /* For each argument    */
    {
        if (streq(parlist[i], token))       /* If it's known        */
        {
#ifdef SOLAR
            save(DEL);
#endif
            save(i + MAC_PARM);             /* Save a magic cookie  */
            return;                         /* And exit the search  */
        }
    }
    if (streq(dp->name, token))             /* Macro name in body?  */
        save(DEF_MAGIC);                    /* Save magic marker    */
    for (cp = token; *cp != EOS;)           /* And save             */
        save(*cp++);                        /* The token itself     */
}
Exemplo n.º 4
0
Arquivo: cpp4.c Projeto: Akaito/bgfx
INLINE FILE_LOCAL
ReturnCode checkparm(struct Global *global,
		     int c,
		     DEFBUF *dp,
		     int quoting)	/* Preceded by a # ?	*/
{
  /*
   * Replace this param if it's defined.  Note that the macro name is a
   * possible replacement token. We stuff DEF_MAGIC in front of the token
   * which is treated as a LETTER by the token scanner and eaten by
   * the output routine. This prevents the macro expander from
   * looping if someone writes "#define foo foo".
   */
  
  int i;
  char *cp;
  ReturnCode ret=FPP_OK;
      
  scanid(global, c);                /* Get parm to tokenbuf */
  for (i = 0; i < global->nargs; i++) {     /* For each argument    */
    if (streq(global->parlist[i], global->tokenbuf)) {  /* If it's known */
#if OK_CONCAT
      if (quoting) {                    /* Special handling of  */
	ret=save(global, QUOTE_PARM);     /* #formal inside defn  */
	if(ret)
	  return(ret);
      }
#endif
      ret=save(global, i + MAC_PARM);     /* Save a magic cookie  */
      return(ret);		      /* And exit the search	*/
    }
  }
  if (streq(dp->name, global->tokenbuf))    /* Macro name in body?  */
    ret=save(global, DEF_MAGIC);            /* Save magic marker    */
  for (cp = global->tokenbuf; *cp != EOS;)  /* And save             */
    ret=save(global, *cp++);                /* The token itself     */
  return(ret);
}
Exemplo n.º 5
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  */
}
Exemplo n.º 6
0
Arquivo: cpp2.c Projeto: cjapes/core
int
control(int counter)
/*
 * Process #control lines.  Simple commands are processed inline,
 * while complex commands have their own subroutines.
 *
 * The counter is used to force out a newline before #line, and
 * #pragma commands.  This prevents these commands from ending up at
 * the end of the previous line if cpp is invoked with the -C option.
 */
{
        register int            c;
        register char           *tp;
        register int            hash;
        char                    *ep;

        c = skipws();
        if (c == '\n' || c == EOF_CHAR)
            return (counter + 1);
        if (!isdigit(c))
            scanid(c);                  /* Get #word to token[]         */
        else {
            unget();                    /* Hack -- allow #123 as a      */
            strcpy(token, "line");      /* synonym for #line 123        */
        }
        hash = (token[1] == EOS) ? L_nogood : (token[0] + (token[2] << 1));
        switch (hash) {
        case L_assert:  tp = "assert";          break;
        case L_define:  tp = "define";          break;
        case L_elif:    tp = "elif";            break;
        case L_else:    tp = "else";            break;
        case L_endif:   tp = "endif";           break;
        case L_if:      tp = "if";              break;
        case L_ifdef:   tp = "ifdef";           break;
        case L_ifndef:  tp = "ifndef";          break;
        case L_include: tp = "include";         break;
        case L_line:    tp = "line";            break;
        case L_pragma:  tp = "pragma";          break;
        case L_undef:   tp = "undef";           break;
        case L_error:   tp = "error";           break;
#if OSL_DEBUG_LEVEL > 1
        case L_debug:   tp = "debug";           break;
        case L_nodebug: tp = "nodebug";         break;
#endif
        default:        hash = L_nogood;
        case L_nogood:  tp = "";                break;
        }
        if (!streq(tp, token))
            hash = L_nogood;
        /*
         * hash is set to a unique value corresponding to the
         * control keyword (or L_nogood if we think it's nonsense).
         */
        if (infile->fp == NULL)
            cwarn("Control line \"%s\" within macro expansion", token);
        if (!compiling) {                       /* Not compiling now    */
            switch (hash) {
            case L_if:                          /* These can't turn     */
            case L_ifdef:                       /*  compilation on, but */
            case L_ifndef:                      /*   we must nest #if's */
                if (++ifptr >= &ifstack[BLK_NEST])
                    goto if_nest_err;
                *ifptr = 0;                     /* !WAS_COMPILING       */
            case L_line:                        /* Many                 */
            /*
             * Are pragma's always processed?
             */
            case L_pragma:                      /*  options             */
            case L_include:                     /*   are uninteresting  */
            case L_define:                      /*    if we             */
            case L_undef:                       /*     aren't           */
            case L_assert:                      /*      compiling.      */
            case L_error:                       /* BP 5.3.92, #error */
dump_line:      skipnl();                       /* Ignore rest of line  */
                return (counter + 1);
            }
        }
        /*
         * Make sure that #line and #pragma are output on a fresh line.
         */
        if (counter > 0 && (hash == L_line || hash == L_pragma)) {
            PUTCHAR('\n');
            counter--;
        }
        switch (hash) {
        case L_line:
            /*
             * Parse the line to update the line number and "progname"
             * field and line number for the next input line.
             * Set wrongline to force it out later.
             */
            c = skipws();
            workp = work;                       /* Save name in work    */
            while (c != '\n' && c != EOF_CHAR) {
                save(c);
                c = get();
            }
            unget();
            save(EOS);
            /*
             * Split #line argument into <line-number> and <name>
             * We subtract 1 as we want the number of the next line.
             */
            line = atoi(work) - 1;              /* Reset line number    */
            for (tp = work; isdigit(*tp) || type[(int)*tp] == SPA; tp++)
                ;                               /* Skip over digits     */
            if (*tp != EOS) {                   /* Got a filename, so:  */
                if (*tp == '"' && (ep = strrchr(tp + 1, '"')) != NULL) {
                    tp++;                       /* Skip over left quote */
                    *ep = EOS;                  /* And ignore right one */
                }
                if (infile->progname != NULL)   /* Give up the old name */
                    free(infile->progname);     /* if it's allocated.   */
                infile->progname = savestring(tp);
            }
            wrongline = TRUE;                   /* Force output later   */
            break;

        case L_include:
            doinclude();
            break;

        case L_define:
            dodefine();
            break;

        case L_undef:
            doundef();
            break;

        case L_else:
            if (ifptr == &ifstack[0])
                goto nest_err;
            else if ((*ifptr & ELSE_SEEN) != 0)
                goto else_seen_err;
            *ifptr |= ELSE_SEEN;
            if ((*ifptr & WAS_COMPILING) != 0) {
                if (compiling || (*ifptr & TRUE_SEEN) != 0)
                    compiling = FALSE;
                else {
                    compiling = TRUE;
                }
            }
            break;

        case L_elif:
            if (ifptr == &ifstack[0])
                goto nest_err;
            else if ((*ifptr & ELSE_SEEN) != 0) {
else_seen_err:  cerror("#%s may not follow #else", token);
                goto dump_line;
            }
            if ((*ifptr & (WAS_COMPILING | TRUE_SEEN)) != WAS_COMPILING) {
                compiling = FALSE;              /* Done compiling stuff */
                goto dump_line;                 /* Skip this clause     */
            }
            doif(L_if);
            break;

        case L_if:
        case L_ifdef:
        case L_ifndef:
            if (++ifptr >= &ifstack[BLK_NEST])
if_nest_err:    cfatal("Too many nested #%s statements", token);
            *ifptr = WAS_COMPILING;
            doif(hash);
            break;

        case L_endif:
            if (ifptr == &ifstack[0]) {
nest_err:       cerror("#%s must be in an #if", token);
                goto dump_line;
            }
            if (!compiling && (*ifptr & WAS_COMPILING) != 0)
                wrongline = TRUE;
            compiling = ((*ifptr & WAS_COMPILING) != 0);
            --ifptr;
            break;

        case L_assert:
            if (eval() == 0)
                cerror("Preprocessor assertion failure", NULLST);
            break;

        case L_pragma:
            /*
             * #pragma is provided to pass "options" to later
             * passes of the compiler.  cpp doesn't have any yet.
             */
            fprintf( pCppOut, "#pragma ");
            while ((c = get()) != '\n' && c != EOF_CHAR)
                cput(c);
            unget();
            break;

#if OSL_DEBUG_LEVEL > 1
        case L_debug:
            if (debug == 0)
                dumpdef("debug set on");
            debug++;
            break;

        case L_nodebug:
            debug--;
            break;
#endif
        case L_error:                       /* BP 5.3.92, #error */
        {
            fprintf( pCppOut, "cpp: line %u, Error directive: ", line );
            while ((c = get()) != '\n' && c != EOF_CHAR)
                cput(c);
            fprintf( pCppOut, "\n" );
            exit( 1 );
            break;
        }
        default:
            /*
             * Undefined #control keyword.
             * Note: the correct behavior may be to warn and
             * pass the line to a subsequent compiler pass.
             * This would allow #asm or similar extensions.
             */
            cerror("Illegal # command \"%s\"", token);
            break;
        }
        if (hash != L_include) {
#if OLD_PREPROCESSOR
            /*
             * Ignore the rest of the #control line so you can write
             *          #if     foo
             *          #endif  foo
             */
            goto dump_line;                     /* Take common exit     */
#else
            if (skipws() != '\n') {
                cwarn("Unexpected text in #control line ignored", NULLST);
                skipnl();
            }
#endif
        }
        return (counter + 1);
}
Exemplo n.º 7
0
Arquivo: cpp2.c Projeto: WangHoi/slc
ReturnCode control( struct Global *global,
    int *counter )  /* Pending newline counter */
{
    /*
     * Process #control lines.  Simple commands are processed inline,
     * while complex commands have their own subroutines.
     *
     * The counter is used to force out a newline before #line, and
     * #pragma commands.  This prevents these commands from ending up at
     * the end of the previous line if cpp is invoked with the -C option.
     */

    int c;
    char *tp;
    int hash;
    char *ep;
    ReturnCode ret;

    c = skipws( global );

    if( c == '\n' || c == EOF_CHAR )
        {
        (*counter)++;

        return(FPP_OK);
        }

    if( !isdigit(c) )
        scanid( global, c );                  /* Get #word to tokenbuf        */
    else
        {
        unget( global );                    /* Hack -- allow #123 as a      */

        strcpy( global->tokenbuf, "line" );   /* synonym for #line 123        */
        }

    hash = (global->tokenbuf[1] == EOS) ? L_nogood : (global->tokenbuf[0] + (global->tokenbuf[2] << 1));

    switch( hash )
        {
        case L_assert:
            tp = "assert";
            break;
        case L_define:
            tp = "define";
            break;
        case L_elif:
            tp = "elif";
            break;
        case L_else:
            tp = "else";
            break;
        case L_endif:
            tp = "endif";
            break;
        case L_error:
            tp = "error";
            break;
        case L_if:
            tp = "if";
            break;
        case L_ifdef:
            tp = "ifdef";
            break;
        case L_ifndef:
            tp = "ifndef";
            break;
        case L_include:
            tp = "include";
            break;
        case L_line:
            tp = "line";
            break;
        case L_pragma:
            tp = "pragma";
            break;
        case L_undef:
            tp = "undef";
            break;
        default:
            hash = L_nogood;
        case L_nogood:
            tp = "";
            break;
        }

    if( !streq( tp, global->tokenbuf ) )
        hash = L_nogood;

    /*
     * hash is set to a unique value corresponding to the
     * control keyword (or L_nogood if we think it's nonsense).
     */
    if( global->infile->fp == NULL )
        cwarn( global, WARN_CONTROL_LINE_IN_MACRO, global->tokenbuf );

    if( !compiling )
        {                       /* Not compiling now    */
        switch( hash )
            {
            case L_if:              /* These can't turn     */
            case L_ifdef:           /*  compilation on, but */
            case L_ifndef:          /*   we must nest #if's */
                if( ++global->ifptr >= &global->ifstack[BLK_NEST] )
                    {
                    cfatal( global, FATAL_TOO_MANY_NESTINGS, global->tokenbuf );

                    return( FPP_TOO_MANY_NESTED_STATEMENTS );
                    }

                *global->ifptr = 0;       /* !WAS_COMPILING   */

            case L_line:            /* Many         */
                /*
                 * Are pragma's always processed?
                 */
            case L_pragma:          /*  options     */
            case L_include:         /*   are uninteresting  */
            case L_define:          /*    if we     */
            case L_undef:           /*     aren't           */
            case L_assert:          /*  compiling.  */
            case L_error:
                dump_line( global, counter );       /* Ignore rest of line  */
                return(FPP_OK);
            }
        }
    /*
     * Make sure that #line and #pragma are output on a fresh line.
     */
    if( *counter > 0 && (hash == L_line || hash == L_pragma) )
        {
        Putchar( global, '\n' );

        (*counter)--;
        }

    switch( hash )
        {
        case L_line:
            /*
             * Parse the line to update the line number and "progname"
             * field and line number for the next input line.
             * Set wrongline to force it out later.
             */
            c = skipws( global );

            global->workp = global->work;       /* Save name in work    */

            while( c != '\n' && c != EOF_CHAR )
                {
                if( (ret = save( global, c )) )
                    return(ret);

                c = get( global );
                }

            unget( global );

            if( (ret = save( global, EOS )) )
                return(ret);

            /*
             * Split #line argument into <line-number> and <name>
             * We subtract 1 as we want the number of the next line.
             */
            global->line = atoi(global->work) - 1;     /* Reset line number    */

            for( tp = global->work; isdigit(*tp) || type[(unsigned)*tp] == SPA; tp++)
                ;             /* Skip over digits */

            if( *tp != EOS )
                {
                /* Got a filename, so:  */

                if( *tp == '"' && (ep = strrchr(tp + 1, '"')) != NULL )
                    {
                    tp++;           /* Skip over left quote */

                    *ep = EOS;      /* And ignore right one */
                    }

                if( global->infile->progname != NULL )
                    /* Give up the old name if it's allocated.   */
                    free( global->infile->progname );

                global->infile->progname = savestring( global, tp );
                }

            global->wrongline = TRUE;           /* Force output later   */
            break;

        case L_include:
            ret = doinclude( global );
            if( ret )
                return(ret);
            break;

        case L_define:
            ret = dodefine( global );
            if( ret )
                return(ret);
            break;

        case L_undef:
            doundef( global );
            break;

        case L_else:
            if( global->ifptr == &global->ifstack[0] )
                {
                cerror( global, ERROR_STRING_MUST_BE_IF, global->tokenbuf );

                dump_line( global, counter );

                return( FPP_OK );
                }
            else if( (*global->ifptr & ELSE_SEEN) != 0 )
                {
                cerror( global, ERROR_STRING_MAY_NOT_FOLLOW_ELSE, global->tokenbuf );

                dump_line( global, counter );

                return( FPP_OK );
                }

            *global->ifptr |= ELSE_SEEN;

            if( (*global->ifptr & WAS_COMPILING) != 0 )
                {
                if( compiling || (*global->ifptr & TRUE_SEEN) != 0 )
                    compiling = FALSE;
                else
                    {
                    compiling = TRUE;
                    }
                }
            break;

        case L_elif:
            if( global->ifptr == &global->ifstack[0] )
                {
                cerror( global, ERROR_STRING_MUST_BE_IF, global->tokenbuf );

                dump_line( global, counter );

                return( FPP_OK );
                }
            else if( (*global->ifptr & ELSE_SEEN) != 0 )
                {
                cerror( global, ERROR_STRING_MAY_NOT_FOLLOW_ELSE, global->tokenbuf );

                dump_line( global, counter );

                return( FPP_OK );
                }

            if( (*global->ifptr & (WAS_COMPILING | TRUE_SEEN)) != WAS_COMPILING )
                {
                compiling = FALSE;        /* Done compiling stuff */

                dump_line( global, counter );   /* Skip this clause */

                return( FPP_OK );
                }

            ret = doif( global, L_if );

            if( ret )
                return(ret);

            break;

        case L_error:
            cerror(global, ERROR_ERROR);
            break;

        case L_if:
        case L_ifdef:
        case L_ifndef:
            if( ++global->ifptr < &global->ifstack[BLK_NEST] )
                {
                *global->ifptr = WAS_COMPILING;

                ret = doif( global, hash );

                if( ret )
                    return(ret);

                break;
                }

            cfatal( global, FATAL_TOO_MANY_NESTINGS, global->tokenbuf );

            return( FPP_TOO_MANY_NESTED_STATEMENTS );

        case L_endif:
            if( global->ifptr == &global->ifstack[0] )
                {
                cerror( global, ERROR_STRING_MUST_BE_IF, global->tokenbuf );

                dump_line( global, counter );

                return(FPP_OK);
                }

            if( !compiling && (*global->ifptr & WAS_COMPILING) != 0 )
                global->wrongline = TRUE;

            compiling = ((*global->ifptr & WAS_COMPILING) != 0);

            --global->ifptr;

            break;

        case L_assert:
            {
            int result;

            ret = eval( global, &result );

            if(ret)
                return(ret);

            if( result == 0 )
                cerror( global, ERROR_PREPROC_FAILURE );
            }
            break;

        case L_pragma:
            /*
             * #pragma is provided to pass "options" to later
             * passes of the compiler.  cpp doesn't have any yet.
             */
            Putstring( global, "#pragma " );

            while( (c = get( global ) ) != '\n' && c != EOF_CHAR )
                Putchar( global, c );

            unget( global );

            Putchar( global, '\n' );

            break;

        default:
            /*
             * Undefined #control keyword.
             * Note: the correct behavior may be to warn and
             * pass the line to a subsequent compiler pass.
             * This would allow #asm or similar extensions.
             */
            if( global->warnillegalcpp )
                cwarn( global, WARN_ILLEGAL_COMMAND, global->tokenbuf );

            Putchar( global, '#' );
            Putstring( global, global->tokenbuf );
            Putchar( global, ' ' );

            while( (c = get( global ) ) != '\n' && c != EOF_CHAR )
                Putchar( global, c );

            unget( global );

            Putchar( global, '\n' );

            break;
        }

    if( hash != L_include )
        {
        #if OLD_PREPROCESSOR
        /*
         * Ignore the rest of the #control line so you can write
         *      #if foo
         *      #endif  foo
         */
        dump_line( global, counter );         /* Take common exit */

        return( FPP_OK );
        #else
          if (skipws(global) != '\n')
            {
            cwarn( global, WARN_UNEXPECTED_TEXT_IGNORED );

            skipnl( global );
            }
        #endif
        }

    (*counter)++;

    return( FPP_OK );
}
Exemplo n.º 8
0
Arquivo: cpp4.c Projeto: 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);
}