summaryrefslogtreecommitdiff
path: root/idlc/source/preproc/eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'idlc/source/preproc/eval.c')
-rw-r--r--idlc/source/preproc/eval.c790
1 files changed, 790 insertions, 0 deletions
diff --git a/idlc/source/preproc/eval.c b/idlc/source/preproc/eval.c
new file mode 100644
index 000000000000..cd3adc2204c7
--- /dev/null
+++ b/idlc/source/preproc/eval.c
@@ -0,0 +1,790 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#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);
+ if (np && (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 = { 0, 0 };
+ 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 < (int)sizeof(cvcon); i += 2)
+ {
+ if (*p == cvcon[i])
+ {
+ n = cvcon[i + 1];
+ break;
+ }
+ }
+ p += 1;
+ if (i >= (int)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;
+}