429 lines
10 KiB
C
429 lines
10 KiB
C
/* 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
|
|
void free(void *);
|
|
#define FREE(x) free(x)
|
|
#undef ALLOCATE
|
|
void *malloc(size_t);
|
|
#define ALLOCATE(x, y, z) (x *)malloc(sizeof(x))
|
|
#undef DREALLOC
|
|
void *realloc(void *, size_t);
|
|
#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, const 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;
|
|
}
|
|
|
|
|