e3afbc9662
2005/09/05 17:39:43 rt 1.1.150.1: #i54170# Change license header: remove SISSL
795 lines
20 KiB
C
795 lines
20 KiB
C
/*************************************************************************
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* $RCSfile: eval.c,v $
|
|
*
|
|
* $Revision: 1.2 $
|
|
*
|
|
* last change: $Author: rt $ $Date: 2005-09-07 18:14:12 $
|
|
*
|
|
* The Contents of this file are made available subject to
|
|
* the terms of GNU Lesser General Public License Version 2.1.
|
|
*
|
|
*
|
|
* GNU Lesser General Public License Version 2.1
|
|
* =============================================
|
|
* Copyright 2005 by Sun Microsystems, Inc.
|
|
* 901 San Antonio Road, Palo Alto, CA 94303, USA
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License version 2.1, as published by the Free Software Foundation.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
* MA 02111-1307 USA
|
|
*
|
|
************************************************************************/
|
|
#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 */
|
|
{
|
|
0, 0, 0
|
|
}, /* NAME2 */
|
|
{
|
|
16, 1, UNARY
|
|
}, /* DEFINED */
|
|
{
|
|
16, 0, UNARY
|
|
}, /* UMINUS */
|
|
{
|
|
16, 1, UNARY
|
|
}, /* ARCHITECTURE */
|
|
};
|
|
|
|
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 NAME2:
|
|
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;
|
|
|
|
case SHARP:
|
|
if (((tp + 1) < trp->lp) &&
|
|
(np = lookup(tp + 1, 0)) && (np->val == KMACHINE))
|
|
{
|
|
tp++;
|
|
if (rand)
|
|
goto syntax;
|
|
*op++ = ARCHITECTURE;
|
|
continue;
|
|
}
|
|
/* fall through */
|
|
|
|
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 <= (unsigned long)rv2;
|
|
break;
|
|
case GEQ | UNSMARK:
|
|
rv1 = (unsigned long)rv1 >= (unsigned long)rv2;
|
|
break;
|
|
case LT | UNSMARK:
|
|
rv1 = (unsigned long)rv1 < (unsigned long)rv2;
|
|
break;
|
|
case GT | UNSMARK:
|
|
rv1 = (unsigned long)rv1 > (unsigned long)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:
|
|
case ARCHITECTURE:
|
|
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;
|
|
unsigned long n;
|
|
uchar *p, c;
|
|
|
|
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 NAME2:
|
|
if ((np = lookup(tp, 0)) != NULL && np->flag & (ISARCHITECTURE))
|
|
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;
|
|
}
|