int extoken_fn(register Expr_t* ex) { register int c; register char* s; register int q; char* e; if (ex->eof || ex->errors) return 0; again: for (;;) switch (c = lex(ex)) { case 0: goto eof; case '/': switch (q = lex(ex)) { case '*': for (;;) switch (lex(ex)) { case '\n': BUMP (error_info.line); continue; case '*': switch (lex(ex)) { case 0: goto eof; case '\n': BUMP (error_info.line); break; case '*': exunlex(ex, '*'); break; case '/': goto again; } break; } break; case '/': while ((c = lex(ex)) != '\n') if (!c) goto eof; break; default: goto opeq; } /*FALLTHROUGH*/ case '\n': BUMP (error_info.line); /*FALLTHROUGH*/ case ' ': case '\t': break; case '(': case '{': case '[': ex->input->nesting++; return exlval.op = c; case ')': case '}': case ']': ex->input->nesting--; return exlval.op = c; case '+': case '-': if ((q = lex(ex)) == c) return exlval.op = c == '+' ? INC : DEC; goto opeq; case '*': case '%': case '^': q = lex(ex); opeq: exlval.op = c; if (q == '=') c = '='; else if (q == '%' && c == '%') { if (ex->input->fp) ex->more = (const char*)ex->input->fp; else ex->more = ex->input->sp; goto eof; } else exunlex(ex, q); return c; case '&': case '|': if ((q = lex(ex)) == '=') { exlval.op = c; return '='; } if (q == c) c = c == '&' ? AND : OR; else exunlex(ex, q); return exlval.op = c; case '<': case '>': if ((q = lex(ex)) == c) { exlval.op = c = c == '<' ? LS : RS; if ((q = lex(ex)) == '=') c = '='; else exunlex(ex, q); return c; } goto relational; case '=': case '!': q = lex(ex); relational: if (q == '=') switch (c) { case '<': c = LE; break; case '>': c = GE; break; case '=': c = EQ; break; case '!': c = NE; break; } else exunlex(ex, q); return exlval.op = c; case '#': if (!ex->linewrap && !(ex->disc->flags & EX_PURE)) { s = ex->linep - 1; while (s > ex->line && isspace(*(s - 1))) s--; if (s == ex->line) { switch (extoken_fn(ex)) { case DYNAMIC: case ID: case NAME: s = exlval.id->name; break; default: s = ""; break; } if (streq(s, "include")) { if (extoken_fn(ex) != STRING) exerror("#%s: string argument expected", s); else if (!expush(ex, exlval.string, 1, NiL, NiL)) { setcontext(ex); goto again; } } else exerror("unknown directive"); } } return exlval.op = c; case '\'': case '"': q = c; sfstrset(ex->tmp, 0); ex->input->nesting++; while ((c = lex(ex)) != q) { if (c == '\\') { sfputc(ex->tmp, c); c = lex(ex); } if (!c) { exerror("unterminated %c string", q); goto eof; } if (c == '\n') { BUMP (error_info.line); } sfputc(ex->tmp, c); } ex->input->nesting--; s = sfstruse(ex->tmp); if (q == '"' || (ex->disc->flags & EX_CHARSTRING)) { if (!(exlval.string = vmstrdup(ex->vm, s))) goto eof; stresc(exlval.string); return STRING; } exlval.integer = chrtoi(s); return INTEGER; case '.': if (isdigit(c = lex(ex))) { sfstrset(ex->tmp, 0); sfputc(ex->tmp, '0'); sfputc(ex->tmp, '.'); goto floating; } exunlex(ex, c); return exlval.op = '.'; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': sfstrset(ex->tmp, 0); sfputc(ex->tmp, c); q = INTEGER; if ((c = lex(ex)) == 'x' || c == 'X') { sfputc(ex->tmp, c); for (;;) { switch (c = lex(ex)) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': sfputc(ex->tmp, c); continue; } break; } } else { while (isdigit(c)) { sfputc(ex->tmp, c); c = lex(ex); } if (c == '#') { sfputc(ex->tmp, c); /* s = sfstruse(ex->tmp); */ /* b = strtol(s, NiL, 10); */ do { sfputc(ex->tmp, c); } while (isalnum(c = lex(ex))); } else { if (c == '.') { floating: q = FLOATING; sfputc(ex->tmp, c); while (isdigit(c = lex(ex))) sfputc(ex->tmp, c); } if (c == 'e' || c == 'E') { q = FLOATING; sfputc(ex->tmp, c); if ((c = lex(ex)) == '-' || c == '+') { sfputc(ex->tmp, c); c = lex(ex); } while (isdigit(c)) { sfputc(ex->tmp, c); c = lex(ex); } } } } s = sfstruse(ex->tmp); if (q == FLOATING) exlval.floating = strtod(s, &e); else { if (c == 'u' || c == 'U') { q = UNSIGNED; c = lex(ex); exlval.integer = strToL(s, &e); } else exlval.integer = strToL(s, &e); if (*e) { *--e = 1; exlval.integer *= strton(e, &e, NiL, 0); } } exunlex(ex, c); if (*e || isalpha(c) || c == '_' || c == '$') { exerror("%s: invalid numeric constant", s); goto eof; } return q; default: if (isalpha(c) || c == '_' || c == '$') { sfstrset(ex->tmp, 0); sfputc(ex->tmp, c); while (isalnum(c = lex(ex)) || c == '_' || c == '$') sfputc(ex->tmp, c); exunlex(ex, c); s = sfstruse(ex->tmp); if (!(exlval.id = (Exid_t*)dtmatch(ex->symbols, s))) { if (!(exlval.id = newof(0, Exid_t, 1, strlen(s) - EX_NAMELEN + 1))) { exerror("out of space"); goto eof; } strcpy(exlval.id->name, s); exlval.id->lex = NAME; dtinsert((ex->formals || !ex->symbols->view) ? ex->symbols : ex->symbols->view, exlval.id); } /* * lexical analyzer state controlled by the grammar */ switch (exlval.id->lex) { case DECLARE: if (exlval.id->index == CHAR) { /* * `char*' === `string' * the * must immediately follow char */ if (c == '*') { lex(ex); exlval.id = id_string; } } break; case NAME: /* * action labels are disambiguated from ?: * through the expr.nolabel grammar hook * the : must immediately follow labels */ if (c == ':' && !expr.nolabel) return LABEL; break; case PRAGMA: /* * user specific statement stripped and * passed as string */ { int b; int n; int pc = 0; int po; int t; /*UNDENT...*/ sfstrset(ex->tmp, 0); b = 1; n = 0; po = 0; t = 0; for (c = t = lex(ex);; c = lex(ex)) { switch (c) { case 0: goto eof; case '/': switch (q = lex(ex)) { case '*': for (;;) { switch (lex(ex)) { case '\n': BUMP (error_info.line); continue; case '*': switch (lex(ex)) { case 0: goto eof; case '\n': BUMP (error_info.line); continue; case '*': exunlex(ex, '*'); continue; case '/': break; default: continue; } break; } if (!b++) goto eof; sfputc(ex->tmp, ' '); break; } break; case '/': while ((c = lex(ex)) != '\n') if (!c) goto eof; BUMP (error_info.line); b = 1; sfputc(ex->tmp, '\n'); break; default: b = 0; sfputc(ex->tmp, c); sfputc(ex->tmp, q); break; } continue; case '\n': BUMP (error_info.line); b = 1; sfputc(ex->tmp, '\n'); continue; case ' ': case '\t': if (!b++) goto eof; sfputc(ex->tmp, ' '); continue; case '(': case '{': case '[': b = 0; if (!po) { switch (po = c) { case '(': pc = ')'; break; case '{': pc = '}'; break; case '[': pc = ']'; break; } n++; } else if (c == po) n++; sfputc(ex->tmp, c); continue; case ')': case '}': case ']': b = 0; if (!po) { exunlex(ex, c); break; } sfputc(ex->tmp, c); if (c == pc && --n <= 0) { if (t == po) break; po = 0; } continue; case ';': b = 0; if (!n) break; sfputc(ex->tmp, c); continue; case '\'': case '"': b = 0; sfputc(ex->tmp, c); ex->input->nesting++; q = c; while ((c = lex(ex)) != q) { if (c == '\\') { sfputc(ex->tmp, c); c = lex(ex); } if (!c) { exerror("unterminated %c string", q); goto eof; } if (c == '\n') { BUMP (error_info.line); } sfputc(ex->tmp, c); } ex->input->nesting--; continue; default: b = 0; sfputc(ex->tmp, c); continue; } break; } (*ex->disc->reff)(ex, NiL, exlval.id, NiL, sfstruse(ex->tmp), 0, ex->disc); /*..INDENT*/ } goto again; } return exlval.id->lex; } return exlval.op = c; } eof: ex->eof = 1; return exlval.op = ';'; }
static long subexpr(register int precedence, int* pun) { register int c; register long n; register long x; register int operand = 1; int un = 0; int xn; switch (lex(c)) { case 0: case '\n': unlex(c); if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "more tokens expected"; return 0; case '-': n = -subexpr(13, &un); break; case '+': n = subexpr(13, &un); break; case '!': n = !subexpr(13, &un); break; case '~': n = ~subexpr(13, &un); break; default: unlex(c); n = 0; operand = 0; break; } un <<= 1; for (;;) { switch (lex(c)) { case 0: case '\n': goto done; case ')': if (!precedence) { if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "too many )'s"; return 0; } goto done; case '(': n = subexpr(1, &un); if (lex(c) != ')') { unlex(c); if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "closing ) expected"; return 0; } gotoperand: if (operand) { if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "operator expected"; return 0; } operand = 1; un <<= 1; continue; case '?': if (precedence > 1) goto done; un = 0; if (lex(c) == ':') { if (!n) n = subexpr(2, &un); else { x = pp.mode; pp.mode |= INACTIVE; subexpr(2, &xn); pp.mode = x; } } else { unlex(c); x = subexpr(2, &xn); if (lex(c) != ':') { unlex(c); if (!errmsg && !(pp.mode & INACTIVE)) errmsg = ": expected for ? operator"; return 0; } if (n) { n = x; un = xn; subexpr(2, &xn); } else n = subexpr(2, &un); } break; case ':': goto done; case T_ANDAND: case T_OROR: xn = (c == T_ANDAND) ? 4 : 3; if (precedence >= xn) goto done; if ((n != 0) == (c == T_ANDAND)) n = subexpr(xn, &un) != 0; else { x = pp.mode; pp.mode |= INACTIVE; subexpr(xn, &un); pp.mode = x; } un = 0; break; case '|': if (precedence > 4) goto done; n |= subexpr(5, &un); break; case '^': if (precedence > 5) goto done; n ^= subexpr(6, &un); break; case '&': if (precedence > 6) goto done; n &= subexpr(7, &un); break; case T_EQ: case T_NE: if (precedence > 7) goto done; n = (n == subexpr(8, &un)) == (c == T_EQ); un = 0; break; case '<': case T_LE: case T_GE: case '>': if (precedence > 8) goto done; x = subexpr(9, &un); switch (c) { case '<': switch (un) { case 01: n = n < (unsigned long)x; break; case 02: n = (unsigned long)n < x; break; case 03: n = (unsigned long)n < (unsigned long)x; break; default: n = n < x; break; } break; case T_LE: switch (un) { case 01: n = n <= (unsigned long)x; break; case 02: n = (unsigned long)n <= x; break; case 03: n = (unsigned long)n <= (unsigned long)x; break; default: n = n <= x; break; } break; case T_GE: switch (un) { case 01: n = n >= (unsigned long)x; break; case 02: n = (unsigned long)n >= x; break; case 03: n = (unsigned long)n >= (unsigned long)x; break; default: n = n >= x; break; } break; case '>': switch (un) { case 01: n = n > (unsigned long)x; break; case 02: n = (unsigned long)n > x; break; case 03: n = (unsigned long)n > (unsigned long)x; break; default: n = n > x; break; } break; } un = 0; break; case T_LSHIFT: case T_RSHIFT: if (precedence > 9) goto done; x = subexpr(10, &un); if (c == T_LSHIFT) n <<= x; else n >>= x; un >>= 1; break; case '+': case '-': if (precedence > 10) goto done; x = subexpr(11, &un); if (c == '+') n += x; else n -= x; break; case '*': case '/': case '%': if (precedence > 11) goto done; x = subexpr(12, &un); if (c == '*') n *= x; else if (x == 0) { if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "divide by zero"; return 0; } else if (c == '/') n /= x; else n %= x; break; case '#': pp.state |= DISABLE; c = pplex(); pp.state &= ~DISABLE; if (c != T_ID) { if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "# must precede a predicate identifier"; return 0; } n = predicate(0); goto gotoperand; case T_ID: n = predicate(1); goto gotoperand; case T_CHARCONST: c = *(pp.toknxt - 1); *(pp.toknxt - 1) = 0; n = chrtoi(pp.token + 1); *(pp.toknxt - 1) = c; if (n & ~((1<<CHAR_BIT)-1)) { if (!(pp.mode & HOSTED)) error(1, "'%s': multi-character character constants are not portable", pp.token); } #if CHAR_MIN < 0 else n = (char)n; #endif goto gotoperand; case T_DECIMAL_U: case T_DECIMAL_UL: case T_OCTAL_U: case T_OCTAL_UL: case T_HEXADECIMAL_U: case T_HEXADECIMAL_UL: un |= 01; /*FALLTHROUGH*/ case T_DECIMAL: case T_DECIMAL_L: case T_OCTAL: case T_OCTAL_L: case T_HEXADECIMAL: case T_HEXADECIMAL_L: n = strtoul(pp.token, NiL, 0); if ((unsigned long)n > LONG_MAX) un |= 01; goto gotoperand; case T_WCHARCONST: n = chrtoi(pp.token); goto gotoperand; default: if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "invalid token"; return 0; } if (errmsg) return 0; if (!operand) goto nooperand; } done: unlex(c); if (!operand) { nooperand: if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "operand expected"; return 0; } if (un) *pun |= 01; return n; }