mirror of
https://github.com/ioquake/ioq3.git
synced 2025-05-30 16:41:31 +00:00
The Quake III Arena sources as originally released under the GPL license on August 20, 2005.
This commit is contained in:
commit
dbe4ddb103
1409 changed files with 806066 additions and 0 deletions
520
lcc/cpp/eval.c
Normal file
520
lcc/cpp/eval.c
Normal file
|
@ -0,0 +1,520 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "cpp.h"
|
||||
|
||||
#define NSTAK 32
|
||||
#define SGN 0
|
||||
#define UNS 1
|
||||
#define UND 2
|
||||
|
||||
#define UNSMARK 0x1000
|
||||
|
||||
struct value {
|
||||
long val;
|
||||
int type;
|
||||
};
|
||||
|
||||
/* conversion types */
|
||||
#define RELAT 1
|
||||
#define ARITH 2
|
||||
#define LOGIC 3
|
||||
#define SPCL 4
|
||||
#define SHIFT 5
|
||||
#define UNARY 6
|
||||
|
||||
/* operator priority, arity, and conversion type, indexed by tokentype */
|
||||
struct pri {
|
||||
char pri;
|
||||
char arity;
|
||||
char ctype;
|
||||
} priority[] = {
|
||||
{ 0, 0, 0 }, /* END */
|
||||
{ 0, 0, 0 }, /* UNCLASS */
|
||||
{ 0, 0, 0 }, /* NAME */
|
||||
{ 0, 0, 0 }, /* NUMBER */
|
||||
{ 0, 0, 0 }, /* STRING */
|
||||
{ 0, 0, 0 }, /* CCON */
|
||||
{ 0, 0, 0 }, /* NL */
|
||||
{ 0, 0, 0 }, /* WS */
|
||||
{ 0, 0, 0 }, /* DSHARP */
|
||||
{ 11, 2, RELAT }, /* EQ */
|
||||
{ 11, 2, RELAT }, /* NEQ */
|
||||
{ 12, 2, RELAT }, /* LEQ */
|
||||
{ 12, 2, RELAT }, /* GEQ */
|
||||
{ 13, 2, SHIFT }, /* LSH */
|
||||
{ 13, 2, SHIFT }, /* RSH */
|
||||
{ 7, 2, LOGIC }, /* LAND */
|
||||
{ 6, 2, LOGIC }, /* LOR */
|
||||
{ 0, 0, 0 }, /* PPLUS */
|
||||
{ 0, 0, 0 }, /* MMINUS */
|
||||
{ 0, 0, 0 }, /* ARROW */
|
||||
{ 0, 0, 0 }, /* SBRA */
|
||||
{ 0, 0, 0 }, /* SKET */
|
||||
{ 3, 0, 0 }, /* LP */
|
||||
{ 3, 0, 0 }, /* RP */
|
||||
{ 0, 0, 0 }, /* DOT */
|
||||
{ 10, 2, ARITH }, /* AND */
|
||||
{ 15, 2, ARITH }, /* STAR */
|
||||
{ 14, 2, ARITH }, /* PLUS */
|
||||
{ 14, 2, ARITH }, /* MINUS */
|
||||
{ 16, 1, UNARY }, /* TILDE */
|
||||
{ 16, 1, UNARY }, /* NOT */
|
||||
{ 15, 2, ARITH }, /* SLASH */
|
||||
{ 15, 2, ARITH }, /* PCT */
|
||||
{ 12, 2, RELAT }, /* LT */
|
||||
{ 12, 2, RELAT }, /* GT */
|
||||
{ 9, 2, ARITH }, /* CIRC */
|
||||
{ 8, 2, ARITH }, /* OR */
|
||||
{ 5, 2, SPCL }, /* QUEST */
|
||||
{ 5, 2, SPCL }, /* COLON */
|
||||
{ 0, 0, 0 }, /* ASGN */
|
||||
{ 4, 2, 0 }, /* COMMA */
|
||||
{ 0, 0, 0 }, /* SHARP */
|
||||
{ 0, 0, 0 }, /* SEMIC */
|
||||
{ 0, 0, 0 }, /* CBRA */
|
||||
{ 0, 0, 0 }, /* CKET */
|
||||
{ 0, 0, 0 }, /* ASPLUS */
|
||||
{ 0, 0, 0 }, /* ASMINUS */
|
||||
{ 0, 0, 0 }, /* ASSTAR */
|
||||
{ 0, 0, 0 }, /* ASSLASH */
|
||||
{ 0, 0, 0 }, /* ASPCT */
|
||||
{ 0, 0, 0 }, /* ASCIRC */
|
||||
{ 0, 0, 0 }, /* ASLSH */
|
||||
{ 0, 0, 0 }, /* ASRSH */
|
||||
{ 0, 0, 0 }, /* ASOR */
|
||||
{ 0, 0, 0 }, /* ASAND */
|
||||
{ 0, 0, 0 }, /* ELLIPS */
|
||||
{ 0, 0, 0 }, /* DSHARP1 */
|
||||
{ 0, 0, 0 }, /* NAME1 */
|
||||
{ 16, 1, UNARY }, /* DEFINED */
|
||||
{ 16, 0, UNARY }, /* UMINUS */
|
||||
};
|
||||
|
||||
int evalop(struct pri);
|
||||
struct value tokval(Token *);
|
||||
struct value vals[NSTAK], *vp;
|
||||
enum toktype ops[NSTAK], *op;
|
||||
|
||||
/*
|
||||
* Evaluate an #if #elif #ifdef #ifndef line. trp->tp points to the keyword.
|
||||
*/
|
||||
long
|
||||
eval(Tokenrow *trp, int kw)
|
||||
{
|
||||
Token *tp;
|
||||
Nlist *np;
|
||||
int ntok, rand;
|
||||
|
||||
trp->tp++;
|
||||
if (kw==KIFDEF || kw==KIFNDEF) {
|
||||
if (trp->lp - trp->bp != 4 || trp->tp->type!=NAME) {
|
||||
error(ERROR, "Syntax error in #ifdef/#ifndef");
|
||||
return 0;
|
||||
}
|
||||
np = lookup(trp->tp, 0);
|
||||
return (kw==KIFDEF) == (np && np->flag&(ISDEFINED|ISMAC));
|
||||
}
|
||||
ntok = trp->tp - trp->bp;
|
||||
kwdefined->val = KDEFINED; /* activate special meaning of defined */
|
||||
expandrow(trp, "<if>");
|
||||
kwdefined->val = NAME;
|
||||
vp = vals;
|
||||
op = ops;
|
||||
*op++ = END;
|
||||
for (rand=0, tp = trp->bp+ntok; tp < trp->lp; tp++) {
|
||||
switch(tp->type) {
|
||||
case WS:
|
||||
case NL:
|
||||
continue;
|
||||
|
||||
/* nilary */
|
||||
case NAME:
|
||||
case NAME1:
|
||||
case NUMBER:
|
||||
case CCON:
|
||||
case STRING:
|
||||
if (rand)
|
||||
goto syntax;
|
||||
*vp++ = tokval(tp);
|
||||
rand = 1;
|
||||
continue;
|
||||
|
||||
/* unary */
|
||||
case DEFINED:
|
||||
case TILDE:
|
||||
case NOT:
|
||||
if (rand)
|
||||
goto syntax;
|
||||
*op++ = tp->type;
|
||||
continue;
|
||||
|
||||
/* unary-binary */
|
||||
case PLUS: case MINUS: case STAR: case AND:
|
||||
if (rand==0) {
|
||||
if (tp->type==MINUS)
|
||||
*op++ = UMINUS;
|
||||
if (tp->type==STAR || tp->type==AND) {
|
||||
error(ERROR, "Illegal operator * or & in #if/#elsif");
|
||||
return 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* flow through */
|
||||
|
||||
/* plain binary */
|
||||
case EQ: case NEQ: case LEQ: case GEQ: case LSH: case RSH:
|
||||
case LAND: case LOR: case SLASH: case PCT:
|
||||
case LT: case GT: case CIRC: case OR: case QUEST:
|
||||
case COLON: case COMMA:
|
||||
if (rand==0)
|
||||
goto syntax;
|
||||
if (evalop(priority[tp->type])!=0)
|
||||
return 0;
|
||||
*op++ = tp->type;
|
||||
rand = 0;
|
||||
continue;
|
||||
|
||||
case LP:
|
||||
if (rand)
|
||||
goto syntax;
|
||||
*op++ = LP;
|
||||
continue;
|
||||
|
||||
case RP:
|
||||
if (!rand)
|
||||
goto syntax;
|
||||
if (evalop(priority[RP])!=0)
|
||||
return 0;
|
||||
if (op<=ops || op[-1]!=LP) {
|
||||
goto syntax;
|
||||
}
|
||||
op--;
|
||||
continue;
|
||||
|
||||
default:
|
||||
error(ERROR,"Bad operator (%t) in #if/#elsif", tp);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (rand==0)
|
||||
goto syntax;
|
||||
if (evalop(priority[END])!=0)
|
||||
return 0;
|
||||
if (op!=&ops[1] || vp!=&vals[1]) {
|
||||
error(ERROR, "Botch in #if/#elsif");
|
||||
return 0;
|
||||
}
|
||||
if (vals[0].type==UND)
|
||||
error(ERROR, "Undefined expression value");
|
||||
return vals[0].val;
|
||||
syntax:
|
||||
error(ERROR, "Syntax error in #if/#elsif");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
evalop(struct pri pri)
|
||||
{
|
||||
struct value v1, v2;
|
||||
long rv1, rv2;
|
||||
int rtype, oper;
|
||||
|
||||
rv2=0;
|
||||
rtype=0;
|
||||
while (pri.pri < priority[op[-1]].pri) {
|
||||
oper = *--op;
|
||||
if (priority[oper].arity==2) {
|
||||
v2 = *--vp;
|
||||
rv2 = v2.val;
|
||||
}
|
||||
v1 = *--vp;
|
||||
rv1 = v1.val;
|
||||
/*lint -e574 -e644 */
|
||||
switch (priority[oper].ctype) {
|
||||
case 0:
|
||||
default:
|
||||
error(WARNING, "Syntax error in #if/#endif");
|
||||
return 1;
|
||||
case ARITH:
|
||||
case RELAT:
|
||||
if (v1.type==UNS || v2.type==UNS)
|
||||
rtype = UNS;
|
||||
else
|
||||
rtype = SGN;
|
||||
if (v1.type==UND || v2.type==UND)
|
||||
rtype = UND;
|
||||
if (priority[oper].ctype==RELAT && rtype==UNS) {
|
||||
oper |= UNSMARK;
|
||||
rtype = SGN;
|
||||
}
|
||||
break;
|
||||
case SHIFT:
|
||||
if (v1.type==UND || v2.type==UND)
|
||||
rtype = UND;
|
||||
else
|
||||
rtype = v1.type;
|
||||
if (rtype==UNS)
|
||||
oper |= UNSMARK;
|
||||
break;
|
||||
case UNARY:
|
||||
rtype = v1.type;
|
||||
break;
|
||||
case LOGIC:
|
||||
case SPCL:
|
||||
break;
|
||||
}
|
||||
switch (oper) {
|
||||
case EQ: case EQ|UNSMARK:
|
||||
rv1 = rv1==rv2; break;
|
||||
case NEQ: case NEQ|UNSMARK:
|
||||
rv1 = rv1!=rv2; break;
|
||||
case LEQ:
|
||||
rv1 = rv1<=rv2; break;
|
||||
case GEQ:
|
||||
rv1 = rv1>=rv2; break;
|
||||
case LT:
|
||||
rv1 = rv1<rv2; break;
|
||||
case GT:
|
||||
rv1 = rv1>rv2; break;
|
||||
case LEQ|UNSMARK:
|
||||
rv1 = (unsigned long)rv1<=rv2; break;
|
||||
case GEQ|UNSMARK:
|
||||
rv1 = (unsigned long)rv1>=rv2; break;
|
||||
case LT|UNSMARK:
|
||||
rv1 = (unsigned long)rv1<rv2; break;
|
||||
case GT|UNSMARK:
|
||||
rv1 = (unsigned long)rv1>rv2; break;
|
||||
case LSH:
|
||||
rv1 <<= rv2; break;
|
||||
case LSH|UNSMARK:
|
||||
rv1 = (unsigned long)rv1<<rv2; break;
|
||||
case RSH:
|
||||
rv1 >>= rv2; break;
|
||||
case RSH|UNSMARK:
|
||||
rv1 = (unsigned long)rv1>>rv2; break;
|
||||
case LAND:
|
||||
rtype = UND;
|
||||
if (v1.type==UND)
|
||||
break;
|
||||
if (rv1!=0) {
|
||||
if (v2.type==UND)
|
||||
break;
|
||||
rv1 = rv2!=0;
|
||||
} else
|
||||
rv1 = 0;
|
||||
rtype = SGN;
|
||||
break;
|
||||
case LOR:
|
||||
rtype = UND;
|
||||
if (v1.type==UND)
|
||||
break;
|
||||
if (rv1==0) {
|
||||
if (v2.type==UND)
|
||||
break;
|
||||
rv1 = rv2!=0;
|
||||
} else
|
||||
rv1 = 1;
|
||||
rtype = SGN;
|
||||
break;
|
||||
case AND:
|
||||
rv1 &= rv2; break;
|
||||
case STAR:
|
||||
rv1 *= rv2; break;
|
||||
case PLUS:
|
||||
rv1 += rv2; break;
|
||||
case MINUS:
|
||||
rv1 -= rv2; break;
|
||||
case UMINUS:
|
||||
if (v1.type==UND)
|
||||
rtype = UND;
|
||||
rv1 = -rv1; break;
|
||||
case OR:
|
||||
rv1 |= rv2; break;
|
||||
case CIRC:
|
||||
rv1 ^= rv2; break;
|
||||
case TILDE:
|
||||
rv1 = ~rv1; break;
|
||||
case NOT:
|
||||
rv1 = !rv1; if (rtype!=UND) rtype = SGN; break;
|
||||
case SLASH:
|
||||
if (rv2==0) {
|
||||
rtype = UND;
|
||||
break;
|
||||
}
|
||||
if (rtype==UNS)
|
||||
rv1 /= (unsigned long)rv2;
|
||||
else
|
||||
rv1 /= rv2;
|
||||
break;
|
||||
case PCT:
|
||||
if (rv2==0) {
|
||||
rtype = UND;
|
||||
break;
|
||||
}
|
||||
if (rtype==UNS)
|
||||
rv1 %= (unsigned long)rv2;
|
||||
else
|
||||
rv1 %= rv2;
|
||||
break;
|
||||
case COLON:
|
||||
if (op[-1] != QUEST)
|
||||
error(ERROR, "Bad ?: in #if/endif");
|
||||
else {
|
||||
op--;
|
||||
if ((--vp)->val==0)
|
||||
v1 = v2;
|
||||
rtype = v1.type;
|
||||
rv1 = v1.val;
|
||||
}
|
||||
break;
|
||||
case DEFINED:
|
||||
break;
|
||||
default:
|
||||
error(ERROR, "Eval botch (unknown operator)");
|
||||
return 1;
|
||||
}
|
||||
/*lint +e574 +e644 */
|
||||
v1.val = rv1;
|
||||
v1.type = rtype;
|
||||
*vp++ = v1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct value
|
||||
tokval(Token *tp)
|
||||
{
|
||||
struct value v;
|
||||
Nlist *np;
|
||||
int i, base, c;
|
||||
unsigned long n;
|
||||
uchar *p;
|
||||
|
||||
v.type = SGN;
|
||||
v.val = 0;
|
||||
switch (tp->type) {
|
||||
|
||||
case NAME:
|
||||
v.val = 0;
|
||||
break;
|
||||
|
||||
case NAME1:
|
||||
if ((np = lookup(tp, 0)) != NULL && np->flag&(ISDEFINED|ISMAC))
|
||||
v.val = 1;
|
||||
break;
|
||||
|
||||
case NUMBER:
|
||||
n = 0;
|
||||
base = 10;
|
||||
p = tp->t;
|
||||
c = p[tp->len];
|
||||
p[tp->len] = '\0';
|
||||
if (*p=='0') {
|
||||
base = 8;
|
||||
if (p[1]=='x' || p[1]=='X') {
|
||||
base = 16;
|
||||
p++;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
for (;; p++) {
|
||||
if ((i = digit(*p)) < 0)
|
||||
break;
|
||||
if (i>=base)
|
||||
error(WARNING,
|
||||
"Bad digit in number %t", tp);
|
||||
n *= base;
|
||||
n += i;
|
||||
}
|
||||
if (n>=0x80000000 && base!=10)
|
||||
v.type = UNS;
|
||||
for (; *p; p++) {
|
||||
if (*p=='u' || *p=='U')
|
||||
v.type = UNS;
|
||||
else if (*p=='l' || *p=='L')
|
||||
;
|
||||
else {
|
||||
error(ERROR,
|
||||
"Bad number %t in #if/#elsif", tp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
v.val = n;
|
||||
tp->t[tp->len] = c;
|
||||
break;
|
||||
|
||||
case CCON:
|
||||
n = 0;
|
||||
p = tp->t;
|
||||
if (*p=='L') {
|
||||
p += 1;
|
||||
error(WARNING, "Wide char constant value undefined");
|
||||
}
|
||||
p += 1;
|
||||
if (*p=='\\') {
|
||||
p += 1;
|
||||
if ((i = digit(*p))>=0 && i<=7) {
|
||||
n = i;
|
||||
p += 1;
|
||||
if ((i = digit(*p))>=0 && i<=7) {
|
||||
p += 1;
|
||||
n <<= 3;
|
||||
n += i;
|
||||
if ((i = digit(*p))>=0 && i<=7) {
|
||||
p += 1;
|
||||
n <<= 3;
|
||||
n += i;
|
||||
}
|
||||
}
|
||||
} else if (*p=='x') {
|
||||
p += 1;
|
||||
while ((i = digit(*p))>=0 && i<=15) {
|
||||
p += 1;
|
||||
n <<= 4;
|
||||
n += i;
|
||||
}
|
||||
} else {
|
||||
static char cvcon[]
|
||||
= "b\bf\fn\nr\rt\tv\v''\"\"??\\\\";
|
||||
for (i=0; i<sizeof(cvcon); i+=2) {
|
||||
if (*p == cvcon[i]) {
|
||||
n = cvcon[i+1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
p += 1;
|
||||
if (i>=sizeof(cvcon))
|
||||
error(WARNING,
|
||||
"Undefined escape in character constant");
|
||||
}
|
||||
} else if (*p=='\'')
|
||||
error(ERROR, "Empty character constant");
|
||||
else
|
||||
n = *p++;
|
||||
if (*p!='\'')
|
||||
error(WARNING, "Multibyte character constant undefined");
|
||||
else if (n>127)
|
||||
error(WARNING, "Character constant taken as not signed");
|
||||
v.val = n;
|
||||
break;
|
||||
|
||||
case STRING:
|
||||
error(ERROR, "String in #if/#elsif");
|
||||
break;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
int
|
||||
digit(int i)
|
||||
{
|
||||
if ('0'<=i && i<='9')
|
||||
i -= '0';
|
||||
else if ('a'<=i && i<='f')
|
||||
i -= 'a'-10;
|
||||
else if ('A'<=i && i<='F')
|
||||
i -= 'A'-10;
|
||||
else
|
||||
i = -1;
|
||||
return i;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue