/* WARNING: This file is #included into two places, since the definition of malloc() differs. Be careful. */ static int cond_get_exp (int); static void handle_cond (int); #ifndef LEXER #undef DXALLOC #define DXALLOC(x, y, z) malloc(x) #undef FREE #define FREE(x) free(x) #undef ALLOCATE #define ALLOCATE(x, y, z) (x *)malloc(sizeof(x)) #undef DREALLOC #define DREALLOC(w, x, y, z) realloc(w, x) #endif static defn_t *defns[DEFHASH]; static ifstate_t *iftop = 0; static defn_t *lookup_definition (const char * s) { defn_t *p; int h; h = defhash(s); for (p = defns[h]; p; p = p->next) if (strcmp(s, p->name) == 0) return p; return 0; } defn_t *lookup_define (const char * s) { defn_t *p = lookup_definition(s); if (p && (p->flags & DEF_IS_UNDEFINED)) return 0; else return p; } static void add_define (const char * name, int nargs, char * exps) { defn_t *p = lookup_definition(name); int h, len; /* trim off leading and trailing whitespace */ while (uisspace(*exps)) exps++; for (len = strlen(exps); len && uisspace(exps[len - 1]); len--); if (*exps == '#' && *(exps + 1) == '#') { yyerror("'##' at start of macro definition"); return; } if (len > 2 && *(exps + len - 2) == '#' && *(exps + len - 1) == '#') { yyerror("'##' at end of macro definition"); return; } if (p) { if (p->flags & DEF_IS_UNDEFINED) { p->exps = (char *)DREALLOC(p->exps, len + 1, TAG_COMPILER, "add_define: redef"); memcpy(p->exps, exps, len); p->exps[len] = 0; p->flags = 0; p->nargs = nargs; } else { if (p->flags & DEF_IS_PREDEF) { yyerror("Illegal to redefine predefined value."); return; } if (nargs != p->nargs || strcmp(exps, p->exps)) { char buf[200 + NSIZE]; sprintf(buf, "redefinition of #define %s\n", name); yywarn(buf); p->exps = (char *)DREALLOC(p->exps, len + 1, TAG_COMPILER, "add_define: redef"); memcpy(p->exps, exps, len); p->exps[len] = 0; p->nargs = nargs; } #ifndef LEXER p->flags &= ~DEF_IS_NOT_LOCAL; #endif } } else { p = ALLOCATE(defn_t, TAG_COMPILER, "add_define: def"); p->name = (char *) DXALLOC(strlen(name) + 1, TAG_COMPILER, "add_define: def name"); strcpy(p->name, name); p->exps = (char *) DXALLOC(len + 1, TAG_COMPILER, "add_define: def exps"); memcpy(p->exps, exps, len); p->exps[len] = 0; p->flags = 0; p->nargs = nargs; h = defhash(name); p->next = defns[h]; defns[h] = p; } } #ifdef LEXER static void handle_elif (char * sp) #else static void handle_elif() #endif { if (iftop) { if (iftop->state == EXPECT_ELSE) { /* last cond was false... */ int cond; ifstate_t *p = iftop; /* pop previous condition */ iftop = p->next; FREE((char *) p); #ifdef LEXER *--outp = '\0'; add_input(sp); #endif cond = cond_get_exp(0); #ifdef LEXER if (*outp++) { yyerror("Condition too complex in #elif"); while (*outp++); #else if (*outp != '\n') { yyerror("Condition too complex in #elif"); #endif } else handle_cond(cond); } else {/* EXPECT_ENDIF */ /* * last cond was true...skip to end of * conditional */ skip_to("endif", (char *) 0); } } else { yyerrorp("Unexpected %celif"); } } static void handle_else (void) { if (iftop) { if (iftop->state == EXPECT_ELSE) { iftop->state = EXPECT_ENDIF; } else { skip_to("endif", (char *) 0); } } else { yyerrorp("Unexpected %cendif"); } } static void handle_endif (void) { if (iftop && (iftop->state == EXPECT_ENDIF || iftop->state == EXPECT_ELSE)) { ifstate_t *p = iftop; iftop = p->next; FREE((char *) p); } else { yyerrorp("Unexpected %cendif"); } } #define BNOT 1 #define LNOT 2 #define UMINUS 3 #define UPLUS 4 #define MULT 1 #define DIV 2 #define MOD 3 #define BPLUS 4 #define BMINUS 5 #define LSHIFT 6 #define RSHIFT 7 #define LESS 8 #define LEQ 9 #define GREAT 10 #define GEQ 11 #define EQ 12 #define NEQ 13 #define BAND 14 #define XOR 15 #define BOR 16 #define LAND 17 #define LOR 18 #define QMARK 19 static char _optab[] = {0, 4, 0, 0, 0, 26, 56, 0, 0, 0, 18, 14, 0, 10, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 50, 40, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 1}; static char optab2[] = {BNOT, 0, 0, LNOT, '=', NEQ, 7, 0, 0, UMINUS, 0, BMINUS, 10, UPLUS, 0, BPLUS, 10, 0, 0, MULT, 11, 0, 0, DIV, 11, 0, 0, MOD, 11, 0, '<', LSHIFT, 9, '=', LEQ, 8, 0, LESS, 8, 0, '>', RSHIFT, 9, '=', GEQ, 8, 0, GREAT, 8, 0, '=', EQ, 7, 0, 0, 0, '&', LAND, 3, 0, BAND, 6, 0, '|', LOR, 2, 0, BOR, 4, 0, 0, XOR, 5, 0, 0, QMARK, 1}; #define optab1 (_optab-' ') static int cond_get_exp (int priority) { int c; int value, value2, x; #ifdef LEXER do c = exgetc(); while (is_wspace(c)); if (c == '(') { #else if ((c = exgetc()) == '(') { #endif value = cond_get_exp(0); #ifdef LEXER do c = exgetc(); while (is_wspace(c)); if (c != ')') { yyerror("bracket not paired in #if"); if (!c) *--outp = '\0'; } #else if ((c = exgetc()) != ')') yyerrorp("bracket not paired in %cif"); #endif } else if (ispunct(c)) { if (!(x = optab1[c])) { yyerrorp("illegal character in %cif"); return 0; } value = cond_get_exp(12); switch (optab2[x - 1]) { case BNOT: value = ~value; break; case LNOT: value = !value; break; case UMINUS: value = -value; break; case UPLUS: value = value; break; default: yyerrorp("illegal unary operator in %cif"); } } else { int base; if (!isdigit(c)) { #ifdef LEXER if (!c) { #else if (c == '\n') { #endif yyerrorp("missing expression in %cif"); } else yyerrorp("illegal character in %cif"); return 0; } value = 0; if (c != '0') base = 10; else { c = *outp++; if (c == 'x' || c == 'X') { base = 16; c = *outp++; } else base = 8; } for (;;) { if (isdigit(c)) x = -'0'; else if (isupper(c)) x = -'A' + 10; else if (islower(c)) x = -'a' + 10; else break; x += c; if (x > base) break; value = value * base + x; c = *outp++; } outp--; } for (;;) { #ifdef LEXER do c = exgetc(); while (is_wspace(c)); if (!ispunct(c)) break; #else if (!ispunct(c = exgetc())) break; #endif if (!(x = optab1[c])) break; value2 = *outp++; for (;; x += 3) { if (!optab2[x]) { outp--; if (!optab2[x + 1]) { yyerrorp("illegal operator use in %cif"); return 0; } break; } if (value2 == optab2[x]) break; } if (priority >= optab2[x + 2]) { if (optab2[x]) *--outp = value2; break; } value2 = cond_get_exp(optab2[x + 2]); switch (optab2[x + 1]) { case MULT: value *= value2; break; case DIV: if (value2) value /= value2; else yyerrorp("division by 0 in %cif"); break; case MOD: if (value2) value %= value2; else yyerrorp("modulo by 0 in %cif"); break; case BPLUS: value += value2; break; case BMINUS: value -= value2; break; case LSHIFT: value <<= value2; break; case RSHIFT: value >>= value2; break; case LESS: value = value < value2; break; case LEQ: value = value <= value2; break; case GREAT: value = value > value2; break; case GEQ: value = value >= value2; break; case EQ: value = value == value2; break; case NEQ: value = value != value2; break; case BAND: value &= value2; break; case XOR: value ^= value2; break; case BOR: value |= value2; break; case LAND: value = value && value2; break; case LOR: value = value || value2; break; case QMARK: #ifdef LEXER do c = exgetc(); while (isspace(c)); if (c != ':') { yyerror("'?' without ':' in #if"); outp--; return 0; } #else if ((c = exgetc()) != ':') yyerrorp("'?' without ':' in %cif"); #endif if (value) { cond_get_exp(1); value = value2; } else value = cond_get_exp(1); break; } } outp--; return value; } static void handle_cond (int c) { ifstate_t *p; if (!c) skip_to("else", "endif"); p = ALLOCATE(ifstate_t, TAG_COMPILER, "handle_cond"); p->next = iftop; iftop = p; p->state = c ? EXPECT_ENDIF : EXPECT_ELSE; }