int preprocess() { ++lptr; lastch = ' '; NextToken(); /* get first word on line */ if( lastst != id ) { error(ERR_PREPROC); return getline(incldepth == 0); } if( strcmp(lastid,"include") == 0 ) return doinclude(); else if( strcmp(lastid,"define") == 0 ) return dodefine(); else if (strcmp(lastid,"ifdef")==0) return doifdef(); else if (strcmp(lastid,"ifndef")==0) return doifndef(); else if (strcmp(lastid,"endif")==0) return doendif(); else { error(ERR_PREPROC); return getline(incldepth == 0); } }
int parse() { token=getlex(); do { if (token <= 0) return 1; if (istoken('#')) { if (istoken(T_DEFINE)) dodefine(); else if (istoken(T_INCLUDE)) doinclude(); else error1("define oder include erwartet"); } else{ typeName(); if (token=='(') dofunc(); else doglob(); } } while(1); }
/* * called from main() to start parsing. * name[0] may be \0 if stdin. */ int inilex(char *name) { nincl = 0; inclp = NULL; doinclude(name); lexstate = NEWSTMT; return(NO); }
/* * process all input text * * at this level, only static declarations, defines, includes, * and function definitions are legal. * */ void parse (void) { if (!startup_incl) { inc_startup(); incl_globals(); } while (1) { blanks(); if (feof(input)) break; // Note: // At beginning of 'parse' call, the header has been output to '.s' // file, as well as all the -Asym=val operands from command line. // // But initial '#include "startup.asm"' statement was not yet output // (allowing for additional asm define's to be parsed and output first. // // We can parse some trivial tokens first (including the asmdef...), // but the #include "startup.asm" line must be output before actual code // (And only once...) // if (amatch("#asmdef", 7)) { doasmdef(); continue; } if (amatch("extern", 6)) dodcls(EXTERN, NULL_TAG, 0); else if (amatch("static", 6)) { if (amatch("const", 5)) { /* XXX: what about the static part? */ dodcls(CONST, NULL_TAG, 0); } else dodcls(STATIC, NULL_TAG, 0); } else if (amatch("const", 5)) dodcls(CONST, NULL_TAG, 0); else if (amatch("typedef", 7)) dotypedef(); else if (dodcls(PUBLIC, NULL_TAG, 0)) ; else if (match("#asm")) doasm(); else if (match("#include")) doinclude(); else if (match("#inc")) dopsdinc(); else if (match("#def")) dopsddef(); else newfunc(NULL, 0, 0, 0, 0); } if (optimize) flush_ins(); }
/* definitions are legal... */ parse() { while (eof==0) /* do until no more input */ { if(amatch("char",4)){declglb(cchar);ns();} else if(amatch("int",3)){declglb(cint);ns();} else if(match("#asm"))doasm(); else if(match("#include"))doinclude(); else if(match("#define"))addmac(); else newfunc(); blanks(); /* force eof if pending */ } }
void parse() { while ( eof == 0 ) { /* do until no more input */ if ( amatch("extern") ) dodeclare(EXTERNAL, NULL_TAG, 0) ; else if (amatch("static")) dodeclare(LSTATIC, NULL_TAG, 0) ; else if (amatch("typedef")) dodeclare(TYPDEF,NULL_TAG,0) ; else if (dodeclare(STATIK, NULL_TAG, 0) ) ; else if ( ch() == '#' ) { if (match("#asm")) doasm(); else if (match("#include")) doinclude() ; else if (match("#define") ) addmac() ; else { clear(); blanks(); } } else newfunc(); blanks(); /* force eof if pending */ } }
/** * 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(); } }
void control(Tokenrow *trp) { Nlist *np; Token *tp; tp = trp->tp; if (tp->type!=NAME) { if (tp->type==NUMBER) goto kline; if (tp->type != NL) error(ERROR, "Unidentifiable control line"); return; /* else empty line */ } if ((np = lookup(tp, 0))==NULL || (np->flag&ISKW)==0 && !skipping) { error(WARNING, "Unknown preprocessor control %t", tp); return; } if (skipping) { if ((np->flag&ISKW)==0) return; switch (np->val) { case KENDIF: if (--ifdepth<skipping) skipping = 0; --cursource->ifdepth; setempty(trp); return; case KIFDEF: case KIFNDEF: case KIF: if (++ifdepth >= NIF) error(FATAL, "#if too deeply nested"); ++cursource->ifdepth; return; case KELIF: case KELSE: if (ifdepth<=skipping) break; return; default: return; } } switch (np->val) { case KDEFINE: dodefine(trp); break; case KUNDEF: tp += 1; if (tp->type!=NAME || trp->lp - trp->bp != 4) { error(ERROR, "Syntax error in #undef"); break; } if ((np = lookup(tp, 0)) != NULL) np->flag &= ~ISDEFINED; break; case KPRAGMA: return; case KIFDEF: case KIFNDEF: case KIF: if (++ifdepth >= NIF) error(FATAL, "#if too deeply nested"); ++cursource->ifdepth; ifsatisfied[ifdepth] = 0; if (eval(trp, np->val)) ifsatisfied[ifdepth] = 1; else skipping = ifdepth; break; case KELIF: if (ifdepth==0) { error(ERROR, "#elif with no #if"); return; } if (ifsatisfied[ifdepth]==2) error(ERROR, "#elif after #else"); if (eval(trp, np->val)) { if (ifsatisfied[ifdepth]) skipping = ifdepth; else { skipping = 0; ifsatisfied[ifdepth] = 1; } } else skipping = ifdepth; break; case KELSE: if (ifdepth==0 || cursource->ifdepth==0) { error(ERROR, "#else with no #if"); return; } if (ifsatisfied[ifdepth]==2) error(ERROR, "#else after #else"); if (trp->lp - trp->bp != 3) error(ERROR, "Syntax error in #else"); skipping = ifsatisfied[ifdepth]? ifdepth: 0; ifsatisfied[ifdepth] = 2; break; case KENDIF: if (ifdepth==0 || cursource->ifdepth==0) { error(ERROR, "#endif with no #if"); return; } --ifdepth; --cursource->ifdepth; if (trp->lp - trp->bp != 3) error(WARNING, "Syntax error in #endif"); break; case KERROR: trp->tp = tp+1; error(WARNING, "#error directive: %r", trp); break; case KLINE: trp->tp = tp+1; expandrow(trp, "<line>"); tp = trp->bp+2; kline: if (tp+1>=trp->lp || tp->type!=NUMBER || tp+3<trp->lp || (tp+3==trp->lp && ((tp+1)->type!=STRING)||*(tp+1)->t=='L')){ error(ERROR, "Syntax error in #line"); return; } cursource->line = atol((char*)tp->t)-1; if (cursource->line<0 || cursource->line>=32768) error(WARNING, "#line specifies number out of range"); tp = tp+1; if (tp+1<trp->lp) cursource->filename=(char*)newstring(tp->t+1,tp->len-2,0); return; case KDEFINED: error(ERROR, "Bad syntax for control line"); break; case KINCLUDE: doinclude(trp); trp->lp = trp->bp; return; case KEVAL: eval(trp, np->val); break; default: error(ERROR, "Preprocessor control `%t' not yet implemented", tp); break; } setempty(trp); return; }
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 ()); } }
void nIncludeall(rdWin *w, nGroup *g, int first, int last, char *arg) { doinclude(w,g,first,last,arg,1); }
/** * control - 处理预处理控制指令(头文件包含指令,行控制指令,条件编译指令) * @trp: 一行源程序的Token * 返回值:无 */ void control(Tokenrow *trp) { Nlist *np; Token *tp; tp = trp->tp; /* 获得Tokenrow中的当前Token(指向预处理控制指令关键字) */ if (tp->type!=NAME) { /* 如果当前Token不是标识符 */ if (tp->type==NUMBER) /* 如果当前Token是数字 */ goto kline; /* 跳转,处理行控制指令 */ if (tp->type != NL) /* 如果该Token既不是标识符,也不是数字 */ error(ERROR, "Unidentifiable control line"); /* 则,打印信息`无法识别的控制指令行' */ return; /* 该行处理完毕,函数返回(该行为空行,无控制信息,else empty line) */ } /* 如果当前Token是标识符但标识符不在标识符hash表中 或 标识符在hash表中但不是关键字且不能略过(TODO:啥是略过?) */ if ((np = lookup(tp, 0))==NULL || (np->flag&ISKW)==0 && !skipping) { error(WARNING, "Unknown preprocessor control %t", tp); /* 打印信息,无法识别的预处理控制指令 */ return; /* 该行处理完毕 */ } if (skipping) { /* TODO: 啥是skipping? */ if ((np->flag&ISKW)==0) /* 如果np不是关键字 */ return; /* 函数返回 */ switch (np->val) { case KENDIF: if (--ifdepth<skipping) skipping = 0; --cursource->ifdepth; setempty(trp); return; case KIFDEF: case KIFNDEF: case KIF: if (++ifdepth >= NIF) error(FATAL, "#if too deeply nested"); ++cursource->ifdepth; return; case KELIF: case KELSE: if (ifdepth<=skipping) break; return; default: return; } } switch (np->val) { case KDEFINE: /* #define,定义宏 */ dodefine(trp); /* 定义宏 */ break; case KUNDEF: /* #undef */ tp += 1; /* tp指向宏名 */ if (tp->type!=NAME || trp->lp - trp->bp != 4) { /* 如果tp不是标识符类型 或者 lp-bp!=4 (lp和bp之间有4个Token) */ error(ERROR, "Syntax error in #undef"); /* 打印错误信息 */ break; } if ((np = lookup(tp, 0)) != NULL) /* 如果在hash表中找到了tp所指向的宏名 */ np->flag &= ~ISDEFINED; /* 清零ISDEFINED标志位 */ break; case KPRAGMA: /* #pragma */ return; case KIFDEF: /* #ifdef */ case KIFNDEF: /* #ifndef */ case KIF: /* #if */ if (++ifdepth >= NIF) /* 全局条件编译语句的嵌套深度值加1 */ error(FATAL, "#if too deeply nested"); /* 如果嵌套深度值大于NIF,则打印错误信息 `#if中嵌入太深' */ ++cursource->ifdepth; /* 当前输入源的条件编译语句的嵌套深度值加1 */ ifsatisfied[ifdepth] = 0; /* 设定条件编译语句的嵌套深度值对应的if语句还未被满足 */ if (eval(trp, np->val)) ifsatisfied[ifdepth] = 1; else skipping = ifdepth; break; case KELIF: /* #elif */ if (ifdepth==0) { error(ERROR, "#elif with no #if"); return; } if (ifsatisfied[ifdepth]==2) error(ERROR, "#elif after #else"); if (eval(trp, np->val)) { if (ifsatisfied[ifdepth]) skipping = ifdepth; else { skipping = 0; ifsatisfied[ifdepth] = 1; } } else skipping = ifdepth; break; case KELSE: /* #else */ if (ifdepth==0 || cursource->ifdepth==0) { error(ERROR, "#else with no #if"); return; } if (ifsatisfied[ifdepth]==2) error(ERROR, "#else after #else"); if (trp->lp - trp->bp != 3) error(ERROR, "Syntax error in #else"); skipping = ifsatisfied[ifdepth]? ifdepth: 0; ifsatisfied[ifdepth] = 2; break; case KENDIF: /* #endif */ if (ifdepth==0 || cursource->ifdepth==0) { error(ERROR, "#endif with no #if"); return; } --ifdepth; --cursource->ifdepth; if (trp->lp - trp->bp != 3) error(WARNING, "Syntax error in #endif"); break; case KERROR: /* #error */ trp->tp = tp+1; error(WARNING, "#error directive: %r", trp); break; case KLINE: /* #line */ trp->tp = tp+1; expandrow(trp, "<line>"); tp = trp->bp+2; kline: /* 行控制信息处理(line control)*/ if (tp+1>=trp->lp || tp->type!=NUMBER || tp+3<trp->lp || (tp+3==trp->lp && ((tp+1)->type!=STRING)||*(tp+1)->t=='L')) { /* 如果行控制语法有误 */ /* 上面的if判断中共有5种语法错误检查: * 1. 如果只有`# 123\n' * 2. 如果当前token不是数字类型 * 3. 如果有类似`# 123 "file.c" 2 3'的行,那么这种行不被lcc的预处理程序支持。TODO:lcc不支持行控制中的flag语法. * 4. 如果在`# linenum filename'中,filename不是字符串 * 5. 如果filename是宽字符字符串 */ error(ERROR, "Syntax error in #line"); /* 打印错误信息 */ return; /* 该函数返回 */ } cursource->line = atol((char*)tp->t)-1; /* 更新当前输入源的行号信息 */ if (cursource->line<0 || cursource->line>=32768) /* 如果转化后的行号小于0或者行号大于32768 */ error(WARNING, "#line specifies number out of range"); /* 打印错误信息 */ tp = tp+1; /* 指针移动到filename位置 */ if (tp+1<trp->lp) /* 如果filename存在(因为filename后通常紧跟一个换行符token) */ cursource->filename=(char*)newstring(tp->t+1,tp->len-2,0); /* 保存输入源的文件名 */ return; /* 该行处理完毕,函数返回 */ case KDEFINED: /* #defined */ error(ERROR, "Bad syntax for control line"); /* 打印语法错误提示 */ break; case KINCLUDE: /* #include */ doinclude(trp); trp->lp = trp->bp; return; case KEVAL: /* #eval */ eval(trp, np->val); break; default: /* # other */ error(ERROR, "Preprocessor control `%t' not yet implemented", tp); /* 未实现的预处理控制指令 */ break; } setempty(trp); /* 置空Tokenrow */ return; }
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 */