| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| #include "cpp.h" |
| |
| #include <stdlib.h> |
| #include <string.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, rnd; |
| |
| 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 (rnd = 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 (rnd) |
| goto syntax; |
| *vp++ = tokval(tp); |
| rnd = 1; |
| continue; |
| |
| /* unary */ |
| case DEFINED: |
| case TILDE: |
| case NOT: |
| if (rnd) |
| goto syntax; |
| *op++ = tp->type; |
| continue; |
| |
| /* unary-binary */ |
| case PLUS: |
| case MINUS: |
| case STAR: |
| case AND: |
| if (rnd == 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 (rnd == 0) |
| goto syntax; |
| if (evalop(priority[tp->type]) != 0) |
| return 0; |
| *op++ = tp->type; |
| rnd = 0; |
| continue; |
| |
| case LP: |
| if (rnd) |
| goto syntax; |
| *op++ = LP; |
| continue; |
| |
| case RP: |
| if (!rnd) |
| 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 (rnd) |
| goto syntax; |
| *op++ = ARCHITECTURE; |
| continue; |
| } |
| } |
| /* fall through */ |
| |
| default: |
| error(ERROR, "Bad operator (%t) in #if/#elsif", tp); |
| return 0; |
| } |
| } |
| if (rnd == 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; |
| struct value v2 = { 0, UND }; |
| 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''\"\"??\\\\"; |
| static size_t cvlen = sizeof(cvcon) - 1; |
| |
| size_t j; |
| for (j = 0; j < cvlen; j += 2) |
| { |
| if (*p == cvcon[j]) |
| { |
| n = cvcon[j + 1]; |
| break; |
| } |
| } |
| p += 1; |
| if (j >= cvlen) |
| 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; |
| } |