/** * process all input text * at this level, only static declarations, defines, includes, * and function definitions are legal. */ void parse(void) { while (!input_eof) { if (match("#")) { if (match("asm")) doasm(); else if (match("include")) doinclude(); else if (match("define")) dodefine(); else if (match("undef")) doundef(); } else if (amatch("extern", 6)) do_declarations(EXTERN, NULL_TAG, 0); else if (amatch("static", 6)) do_declarations(STATIC, NULL_TAG, 0); else if (do_declarations(PUBLIC, NULL_TAG, 0)) ; else { newfunc(); } blanks(); } }
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); }
int prep (void) /* Check for preprocessor commands */ { int b, c; char *ln; ln = line; while (*(++ln) == '#' || *ln == ' ') /* locate first directive character */ ; if ( ! *ln) /* NULL directive */ return (killine ()); /* fprintf(stderr,"prep - line=%s\n",ln); */ if (strcmp2 (ln, "if ") || strcmp2 (ln, "ifdef ") || strcmp2 (ln, "ifndef ")) { /* fprintf(stderr,"prep - calling doif(%s)\n",ln); */ doif (ln); return (killine ()); } if (strcmp2 (ln, "else")) { doelse (); return (killine ()); } if (strcmp2 (ln, "endif")) { doendif (); return (killine ()); } if (strcmp2 (ln, "elif ")) { doelif (ln); return (killine ()); } if (procsw) { if (strcmp2 (ln, "define ")) { c = getident (ln, 7) + 2; /* get end of identifier */ splittok (ln, c); /* tokenize rest of line */ dodefine (strlen (line), &ln[7] - line); /* store #define info */ /* fprintf(stderr,"PREP (after dodef): line=|%s|\n",line); */ tstdupdef (); /* Check for def duplication and fix */ return (killine ()); /* Discard #define line */ } if (strcmp2 (ln, "include ")) { doinclude (&ln[8]); /* open include file */ return (killine ()); /* Discard #include line */ } if (strcmp2 (ln, "undef ")) { /* fprintf(stderr,"prep - undef found %s\n",ln); */ doundef (&ln[6]); /* remove undef identifier from def table */ /* fprintf(stderr,"prep - doundef done\n"); */ return (killine ()); /* Discard #undef line */ } if (strcmp2 (ln, "error ")) { fprintf (stderr, "User error - %s\n", &ln[6]); /* print error */ return (killine ()); /* Discard #error line */ } if (strcmp2 (ln, "asm")) { for (;;) /* send all following lines through for assembler */ { getln (0); if (eflag) break; if (findstr (1, line, "#endasm")) break; if (cflag) puts ("#2"); else printf ("#pragma asm "); printf ("%s\n", line); } if (eflag && cflag) /* error only in Microware mode (no #endasm) */ doerr (18, 1); return (killine ()); } if (strcmp2 (ln, "pragma ")) { dopragma (ln + 7); return (killine ()); } if (strcmp2 (ln, "line ")) { doline (ln + 5); return (killine ()); } doerr (17, 1); /* Illegal preprocessor directive */ return (killine ()); } }
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 ); }
/* **************************************************************** * Analisa uma Linha de Controle * **************************************************************** */ void directive (void) { SYMTB *sp, **link_place; MAJOR maj; char *cp, c; /* * Convenção da STACK: * 'U': é indefinido, e nunca foi definido * 'N': é indefinido, mas já foi definido * 'D': é definido */ if ((maj = scan ()) == EOL) { skipline (); return; } if (maj != ID || !TYPE (sp, token.l_name, S_KEYWORD)) { err_msg ( ERRO, TOKMARK, "Esperava uma diretiva de préprocessamento" ); skipline (); return; } switch (sp->s_index) { case DEFINE: if (falselevel == 0) dodefine (); break; case UNDEF: if (falselevel == 0) doundef (); break; case INCLUDE: if (falselevel == 0) { doinclude (); return; } break; case IF: if (falselevel == 0) { if (expression ()) { *stackp++ = 'D'; putoutnl (); } else { *stackp++ = 'U'; falselevel++; } /* * A análise de expressões já processou * o fim de linha. Não devemos avançar mais. */ return; } else { *stackp++ = 'U'; falselevel++; } break; case IFDEF: if (scan () != ID) { err_msg (ERRO, TOKMARK, "Esperava um identificador"); *stackp++ = 'D'; break; } if (TYPE (sp, token.l_name, S_MACRO)) { *stackp++ = 'D'; if (falselevel == 0) putoutnl (); } else { *stackp++ = 'U'; falselevel++; } break; case IFNDEF: if (scan () != ID) { err_msg (ERRO, TOKMARK, "Esperava um identificador"); *stackp++ = 'D'; break; } if (!TYPE (sp, token.l_name, S_MACRO)) { *stackp++ = 'D'; if (falselevel == 0) putoutnl (); } else { *stackp++ = 'U'; falselevel++; } break; case ELIF: if (stackp <= stack) { err_msg ( ERRO, TOKMARK, "\"elif\" sem prévio \"if\" ou \"ifdef\"" ); break; } switch (stackp[-1]) { case 'U': if (falselevel == 1) { if (expression ()) { stackp[-1] = 'D'; falselevel--; /* == 0 */ putlineno (lineno); } else { /* Nada faz */ } return; } else { /* Nada faz */ } break; case 'N': /* Nada faz */ break; case 'D': stackp[-1] = 'N'; falselevel++; putoutnl (); break; default: err_msg ( ERRO, TOKMARK, "Estado inválido da STACK: '%c'", stackp[-1] ); } break; case ELSE: if (stackp <= stack) { err_msg ( ERRO, TOKMARK, "\"else\" sem prévio \"if\" ou \"ifdef\"" ); break; } switch (stackp[-1]) { case 'U': stackp[-1] = 'D'; if (--falselevel == 0) putlineno (lineno + 1); break; case 'N': /* Nada faz */ break; case 'D': stackp[-1] = 'U'; falselevel++; break; default: err_msg ( ERRO, TOKMARK, "Estado inválido da STACK: '%c'", stackp[-1] ); } break; case ENDIF: if (stackp <= stack) { err_msg ( ERRO, TOKMARK, "\"endif\" sem prévio \"if\" ou \"ifdef\"" ); break; } switch (*--stackp) { case 'U': case 'N': if (--falselevel == 0) putlineno (lineno + 1); break; case 'D': putoutnl (); break; default: err_msg ( ERRO, TOKMARK, "Estado inválido da STACK: '%c'", stackp[0] ); } break; case ERROR: if (falselevel == 0) { const char *msg; for (cp = (char *)nextp; CATEG (cp) == SEPAR; cp++) /* vazio */; msg = cp; while (*cp != '\n' && (*cp != '/' || cp[1] != '*')) cp++; c = *cp; *cp = '\0'; err_msg (ERRO, NOMARK, msg); *cp = c; nextp = msg; putoutnl (); } break; case PRAGMA: if (falselevel == 0) dopragma (); break; case LINE: if (falselevel == 0) { if (scan () != ICTE) { err_msg ( ERRO, TOKMARK, "Esperava uma constante" ); }; lineno = token.l_ival - 1; if (scan () == STR) { srcname = token.l_begin + 1; ((char *)token.l_end)[0] = '\0'; scan (); } return; } break; default: err_msg ( COMP, TOKMARK, "Erro no s_index para diretivas" ); } /* end switch (sp->s_index) */ skipline (); } /* end directive */
static void getflags(int *xargc, char ***xargv, int *option_end) { char *arg; char *t; wchar_t *s[3]; while (*xargc > 1) { arg = (*xargv)[1]; /* point arg to current argument */ /* * This argument is not an option if it equals "-" or if * "--" has already been parsed. */ if (arg[0] != '-' || arg[1] == EOS || *option_end) break; if (arg[0] == '-' && arg[1] == '-' && arg[2] == '\0') { *option_end = 1; } else { switch (arg[1]) { case 'B': chkspace(&arg, xargc, xargv); bufsize = atoi(&arg[2]); if (bufsize <= 0) { bufsize = DEF_BUFSIZE; } break; case 'D': initalloc(); chkspace(&arg, xargc, xargv); for (t = &arg[2]; *t; t++) { if (*t == '=') { *t++ = EOS; break; } } s[1] = str2wstr(&arg[2], 1); s[2] = str2wstr(t, 1); dodef(&s[0], 2); free(s[1]); free(s[2]); break; case 'H': chkspace(&arg, xargc, xargv); hshsize = atoi(&arg[2]); if (hshsize <= 0) { hshsize = DEF_HSHSIZE; } break; case 'S': chkspace(&arg, xargc, xargv); stksize = atoi(&arg[2]); if (stksize <= 0) { stksize = DEF_STKSIZE; } break; case 'T': chkspace(&arg, xargc, xargv); toksize = atoi(&arg[2]); if (toksize <= 0) { toksize = DEF_TOKSIZE; } break; case 'U': initalloc(); chkspace(&arg, xargc, xargv); s[1] = str2wstr(&arg[2], 1); doundef(&s[0], 1); free(s[1]); break; case 'e': setbuf(stdout, NULL); (void) signal(SIGINT, SIG_IGN); break; case 's': /* turn on line sync */ sflag = 1; break; default: (void) fprintf(stderr, gettext("%s: bad option: %s\n"), procnam, arg); delexit(NOT_OK, 0); } } /* end else not "--" */ (*xargv)++; --(*xargc); } /* end while options to process */ }