/* Find the specific macro in the table. Expand it if it is not expanded. * */ CMacro * CMaExpander::GetMacro(sym_t mid) { CMacro *ma = tc->maMap.Lookup(mid); if( IS_MACRO(ma) && ma->id == SSID_INVALID ) { handle_define(tc, mid, ma); free(ma->line); ma->line = NULL; return tc->maMap.Lookup(mid); } return ma; }
static int yylex1(void) { register char *yyp; register int c; register int c1, c2; for (;;) { if (lex_fatal) { return -1; } switch(c = mygetc()) { case EOF: if (inctop) { struct incstate *p; p = inctop; (void)fclose(yyin); /*(void)fprintf(stderr, "popping to %s\n", p->file);*/ free(current_file); nexpands = 0; current_file = p->file; current_line = p->line + 1; current_incfile = p->incfnum; pragma_strict_types = p->pragma_strict_types; yyin = p->yyin; slast = p->slast; lastchar = p->lastchar; inctop = p->next; if (p->nbuf) { nbuf = p->nbuf; outp = defbuf + DEFMAX - nbuf; memcpy(outp, p->outp, nbuf); free((char *)p->outp); } else { nbuf = 0; outp = defbuf + DEFMAX; } store_line_number_info(current_incfile, current_line); incdepth--; free((char *)p); break; } if (iftop) { struct ifstate *p = iftop; lexerror(p->state == EXPECT_ENDIF ? "Missing #endif" : "Missing #else"); while (iftop) { p = iftop; iftop = p->next; free((char *)p); } } return -1; case '\n': { nexpands=0; store_line_number_info(current_incfile, current_line); current_line++; total_lines++; } /* FALLTHROUGH */ case ' ': case '\t': case '\f': case '\v': break; case '+': TRY('+', F_INC); TRY('=', F_ADD_EQ); return c; case '-': TRY('>', F_ARROW); TRY('-', F_DEC); TRY('=', F_SUB_EQ); return c; case '&': TRY('&', F_LAND); TRY('=', F_AND_EQ); return c; case '|': TRY('|', F_LOR); TRY('=', F_OR_EQ); return c; case '^': TRY('=', F_XOR_EQ); return c; case '<': if (gobble('<')) { TRY('=', F_LSH_EQ); return F_LSH; } TRY('=', F_LE); return c; case '>': if (gobble('>')) { TRY('=', F_RSH_EQ); return F_RSH; } TRY('=', F_GE); return c; case '*': TRY('=', F_MULT_EQ); return c; case '%': TRY('=', F_MOD_EQ); return F_MOD; case '/': if (gobble('*')) { skip_comment(); break; } else if (gobble('/')) { skip_comment2(); break; } TRY('=', F_DIV_EQ); return c; case '=': TRY('=', F_EQ); return c; case ';': case '(': case ')': case ',': case '{': case '}': case '~': case '[': case ']': case '?': case '@': return c; case '!': TRY('=', F_NE); return F_NOT; case ':': TRY(':', F_COLON_COLON); return ':'; case '.': if (gobble('.')) { if (gobble('.')) return F_VARARG; else return F_RANGE; } return c; case '#': if (lastchar == '\n') { char *ssp = 0; int quote; yyp = yytext; do { c = mygetc(); } while (isspace(c)); for (quote = 0;;) { if (c == '"') quote ^= 1; /*gc - handle comments cpp-like! 1.6.91 @@@*/ while (!quote && c == '/') { if (gobble('*')) { skip_comment(); c = mygetc(); } else break; } if (!ssp && isspace(c)) ssp = yyp; if (c == '\n' || c == EOF) break; SAVEC; c = mygetc(); } if (ssp) { *ssp++ = 0; while (isspace(*ssp)) ssp++; } else { ssp = yyp; } *yyp = 0; if (strcmp("define", yytext) == 0) { handle_define(ssp); } else if (strcmp("if", yytext) == 0) { #if 0 short int nega=0; /*@@@ allow #if !VAR gc 1.6.91*/ if (*ssp=='!'){ ssp++; nega=1;} if (isdigit(*ssp)) { char *p; long l; l = strtol(ssp, &p, 10); while (isspace(*p)) p++; if (*p) lexerror("Condition too complex in #if"); else handle_cond(nega ? !(int)l : (int)l); } else if (isalunum(*ssp)) { char *p = ssp; while (isalunum(*p)) p++; if (*p) { *p++ = 0; while (isspace(*p)) p++; } if (*p) lexerror("Condition too complex in #if"); else { struct defn *d; d = lookup_define(ssp); if (d) { handle_cond(nega ? !atoi(d->exps) : atoi(d->exps));/* a hack! */ } else { handle_cond(nega?1:0); /* cpp-like gc*/ } } } else lexerror("Condition too complex in #if"); #else int cond; myungetc(0); add_input(ssp); cond = cond_get_exp(0); if (mygetc()) { lexerror("Condition too complex in #if"); while (mygetc()) ; } else handle_cond(cond); #endif } else if (strcmp("ifdef", yytext) == 0) { deltrail(ssp); handle_cond(lookup_define(ssp) != 0); } else if (strcmp("ifndef", yytext) == 0) { deltrail(ssp); handle_cond(lookup_define(ssp) == 0); } else if (strcmp("else", yytext) == 0) { if (iftop && iftop->state == EXPECT_ELSE) { struct ifstate *p = iftop; /*(void)fprintf(stderr, "found else\n");*/ iftop = p->next; free((char *)p); (void)skip_to("endif", (char *)0); store_line_number_info(current_incfile, current_line); current_line++; total_lines++; } else { lexerror("Unexpected #else"); } } else if (strcmp("endif", yytext) == 0) { if (iftop && (iftop->state == EXPECT_ENDIF || iftop->state == EXPECT_ELSE)) { struct ifstate *p = iftop; /*(void)fprintf(stderr, "found endif\n");*/ iftop = p->next; free((char *)p); } else { lexerror("Unexpected #endif"); } } else if (strcmp("undef", yytext) == 0) { struct defn *d; deltrail(ssp); if ((d = lookup_define(ssp)) != NULL ) d->undef++; } else if (strcmp("echo", yytext) == 0) { (void)fprintf(stderr, "%s\n", ssp); } else if (strcmp("include", yytext) == 0) { /*(void)fprintf(stderr, "including %s\n", ssp); */ handle_include(ssp, 0); } else if (strcmp("pragma", yytext) == 0) { deltrail(ssp); handle_pragma(ssp); } else if (strcmp("error", yytext) == 0) { handle_exception(ERROR, ssp); } else if (strcmp("warning", yytext) == 0) { handle_exception(WARNING, ssp); } else { lexerror("Unrecognised # directive"); } myungetc('\n'); break; } else goto badlex; case '\'': yylval.number = mygetc(); if (yylval.number == '\\') { int tmp = mygetc(); switch (tmp) { case 'n': yylval.number = '\n'; break; case 't': yylval.number = '\t'; break; case 'b': yylval.number = '\b'; break; case 'a': yylval.number = '\a'; break; case 'v': yylval.number = '\v'; break; case '\'': case '\\': case '"': yylval.number = tmp; break; default: lexwarning("Bad character escape sequence"); yylval.number = tmp; break; } } if (!gobble('\'')) lexerror("Illegal character constant"); return F_NUMBER; case '"': yyp = yytext; *yyp++ = c; for (;;) { c = mygetc(); if (c == EOF) { lexerror("End of file in string"); return string("\"\""); } else if (c == '\n') { lexerror("Newline in string"); return string("\"\""); } SAVEC; if (c == '"') break; if (c == '\\') { c = mygetc(); if ( c == '\n' ) { yyp--; store_line_number_info(current_incfile, current_line); current_line++; total_lines++; } else if ( c == EOF ) { /* some operating systems give EOF only once */ myungetc(c); } else *yyp++ = c; } } *yyp = 0; return string(yytext); case '0': c = mygetc(); if ( c == 'X' || c == 'x' || c == 'o') { char *endptr; long long value; int base = 16; if (c == 'o') base = 8; yyp = yytext; for (;;) { c = mygetc(); if (!isxdigit(c)) break; SAVEC; } myungetc(c); *yyp = '\0'; value = strtoll(yytext, &endptr, base); if (*endptr != '\0') { fprintf(stderr, "%s\n", yytext); lexwarning("Invalid digits in octal number number"); } return number(value); } myungetc(c); c = '0'; /* FALLTHROUGH */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': yyp = yytext; *yyp++ = c; for (;;) { c = mygetc(); if (!isdigit(c)) break; SAVEC; } if (c == '.') { if (isdigit(c1 = mygetc())) { SAVEC; c = c1; SAVEC; for (c = mygetc(); isdigit(c); c = mygetc()) SAVEC; if (c == 'e' || c == 'E') { c1 = mygetc(); if (c1 == '-' || c1 == '+') { c2 = mygetc(); if (isdigit(c2)) { SAVEC; c = c1; SAVEC; c = c2; SAVEC; for (c = mygetc(); isdigit(c); c = mygetc()) SAVEC; } else { myungetc(c2); myungetc(c1); } } else if (isdigit(c1)) { SAVEC; c = c1; SAVEC; for (c = mygetc(); isdigit(c); c = mygetc()) SAVEC; } else myungetc(c1); } myungetc(c); *yyp = 0; return real(strtod(yytext, NULL)); } myungetc(c1); } myungetc(c); *yyp = 0; if (*yytext == '0') { /* OCTALS */ char *endptr; long long value; value = strtoll(yytext, &endptr, 010); if (*endptr != '\0') lexwarning("Invalid digits in octal number"); if (value != 0) lexwarning("Obsolete octal format used. Use 0o111 syntax"); return number(value); } return number(atoll(yytext)); default: if (isalpha(c) || c == '_') { int r; yyp = yytext; *yyp++ = c; for (;;) { c = mygetc(); if (!isalunum(c)) break; SAVEC; } *yyp = 0; myungetc(c); if (!expand_define()) { r = lookup_resword(yytext); if (r >= 0) { return r; } else return ident(yytext); } break; } goto badlex; } } badlex: { lexerror("Illegal character (hex %02x) '%c'", c, c); return ' '; } }
void preprocess_file(preprocessor_state* preproc) { lexer_state save_lexer, *lexer = &preproc->lexer; long fpos; int c; token_lex tlex[10]; FILE* input = preproc->input; FILE* output = preproc->output; // if not -P fprintf(output, "# 0 \"%s\"\n", lexer->cur_file); tlex[0] = read_token(input, lexer, output); for ( ; tlex[0].tok.type != END; tlex[0] = read_token(input, lexer, output)) { if (tlex[0].tok.type == ID) { int is_macro = look_up_macro_loc(preproc, tlex[0].tok.v.id); if (is_macro >= 0) { macro_params* p = GET_PARAM(&preproc->params, is_macro); //for a function style macro if the name isn't followed by a ( it's not an error //it's just not an invocation so just print it out if (p->num_params >= 0) { save_lexer = *lexer; if ((fpos = ftell(input)) == -1) { perror("ftell failure in preprocess_file"); exit(0); } tlex[1] = read_token(input, lexer, NULL); if (tlex[1].tok.type != LPAREN) { *lexer = save_lexer; if (fseek(input, fpos, SEEK_SET)) { perror("fseek failure in preprocess_file"); exit(0); } if (tlex[1].tok.type == ID || tlex[1].tok.type == STR_LITERAL) free(tlex[1].tok.v.id); print_token(&tlex[0].tok, output, 0); free(tlex[0].tok.v.id); continue; } //restore ( for symmetry in handle_macro *lexer = save_lexer; if (fseek(input, fpos, SEEK_SET)) { perror("fseek failure in preprocess_file"); exit(0); } } handle_macro(preproc, is_macro); } else { print_token(&tlex[0].tok, output, 0); } free(tlex[0].tok.v.id); } else if (tlex[0].tok.type == POUND) { //has to be the first token if (lexer->cur_tok != 1) { preprocessor_error(NULL, lexer, "Error: stray # in program\n"); } save_lexer = *lexer; if ((fpos = ftell(input)) == -1) { perror("ftell failure in preprocess_file"); exit(0); } tlex[1] = read_token(input, lexer, NULL); if (tlex[0].line != tlex[1].line) { //null directive (EOF is always on it's own line) if (tlex[1].tok.type == POUND) { tlex[0] = tlex[1]; continue; } else if (tlex[1].tok.type == ID || tlex[1].tok.type == STR_LITERAL) { free(tlex[1].tok.v.id); } *lexer = save_lexer; if (fseek(input, fpos, SEEK_SET)) { perror("fseek failure in preprocess_file"); exit(0); } continue; } if (tlex[1].tok.type != ID) { preprocessor_error(&tlex[1], lexer, "expected ID as macro name,"); } if (!strcmp(tlex[1].tok.v.id, "define")) { free(tlex[1].tok.v.id); handle_define(preproc); goto eat_newline; } if (!strcmp(tlex[1].tok.v.id, "undef")) { free(tlex[1].tok.v.id); save_lexer = *lexer; fpos = ftell(input); tlex[1] = read_token(input, lexer, NULL); if (tlex[1].line != tlex[0].line) { preprocessor_error(NULL, lexer, "macro name missing in undef directive\n"); } if (tlex[1].tok.type != ID) { preprocessor_error(&tlex[1], lexer, "ID expected in undef directive,"); } int exists = look_up_macro_loc(preproc, tlex[0].tok.v.id); if (exists >= 0) { cvec_erase_str(&preproc->macros, exists, exists); cvec_erase_str(&preproc->values, exists, exists); cvec_erase_void(&preproc->params, exists, exists); } free(tlex[1].tok.v.id); goto eat_newline; } if (!strcmp(tlex[1].tok.v.id, "include")) { free(tlex[1].tok.v.id); handle_include(preproc); goto eat_newline; } if (!strcmp(tlex[1].tok.v.id, "if")) { free(tlex[1].tok.v.id); } if (!strcmp(tlex[1].tok.v.id, "ifdef")) { free(tlex[1].tok.v.id); handle_ifdef(preproc); goto eat_newline; } if (!strcmp(tlex[1].tok.v.id, "ifndef")) { free(tlex[1].tok.v.id); } if (!strcmp(tlex[1].tok.v.id, "else")) { } if (!strcmp(tlex[1].tok.v.id, "endif")) { } if (!strcmp(tlex[1].tok.v.id, "elif")) { } if (!strcmp(tlex[1].tok.v.id, "defined")) { } if (!strcmp(tlex[1].tok.v.id, "pragma")) { } if (!strcmp(tlex[1].tok.v.id, "error")) { // check for string // preprocessor_error(NULL, } eat_newline: //the newline should reset the position //but since the line of a directive should be //invisible to the final program it shouldn't affect line count do { c = getc(preproc->input); if (!isspace(c)) preprocessor_error(NULL, lexer, "extra tokens in directive\n"); } while (c != '\n'); lexer->cur_pos = 1; lexer->cur_tok = 0; } } }