/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 .
*/
#include"cpp.h"
#define NSTAK 32 #define SGN 0 #define UNS 1 #define UND 2
staticint evalop(struct pri); staticstruct value tokval(Token *); staticstruct value vals[NSTAK], *vp; staticenum 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;
size_t ntok; int 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, "");
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 */ caseDEFINED: case TILDE: caseNOT: if (rnd) goto syntax;
*op++ = tp->type; continue;
/* unary-binary */ case PLUS: case MINUS: case STAR: caseAND: if (rnd == 0)
{ if (tp->type == MINUS)
*op++ = UMINUS; if (tp->type == STAR || tp->type == AND)
{
error(ERROR, "Illegal operator * or & in #if/#elif"); return 0;
} continue;
} /* fall 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: caseOR: 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/#elif", 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/#elif"); return 0;
} if (vals[0].type == UND)
error(ERROR, "Undefined expression value"); return vals[0].val;
syntax:
error(ERROR, "Syntax error in #if/#elif"); return 0;
}
int
evalop(struct pri pri)
{ struct value v1; struct value v2 = { 0, UND }; int 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 = (unsignedlong)rv1 <= (unsignedlong)rv2; break; case GEQ | UNSMARK:
rv1 = (unsignedlong)rv1 >= (unsignedlong)rv2; break; case LT | UNSMARK:
rv1 = (unsignedlong)rv1 < (unsignedlong)rv2; break; case GT | UNSMARK:
rv1 = (unsignedlong)rv1 > (unsignedlong)rv2; break; case LSH:
rv1 <<= rv2; break; case LSH | UNSMARK:
rv1 = (unsignedlong) rv1 << rv2; break; case RSH:
rv1 >>= rv2; break; case RSH | UNSMARK:
rv1 = (unsignedlong) 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; caseAND:
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; caseOR:
rv1 |= rv2; break; case CIRC:
rv1 ^= rv2; break; case TILDE:
rv1 = ~rv1; break; caseNOT:
rv1 = !rv1; if (rtype != UND)
rtype = SGN; break; case SLASH: if (rv2 == 0)
{
rtype = UND; break;
} if (rtype == UNS)
rv1 /= (unsignedlong) rv2; else
rv1 /= rv2; break; case PCT: if (rv2 == 0)
{
rtype = UND; break;
} if (rtype == UNS)
rv1 %= (unsignedlong) 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;
struct value
tokval(Token * tp)
{ struct value v;
Nlist *np; int i, base; unsignedint n;
uchar *p, c;
v.type = SGN;
v.val = 0; switch (tp->type)
{
case NAME:
v.val = 0; break;
case NAME1:
np = lookup(tp, 0); if (np != NULL && np->flag & (ISDEFINED | ISMAC))
v.val = 1; break;
case NAME2:
np = lookup(tp, 0); if (np != 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/#elif", 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;
i = digit(*p); if (i >= 0 && i <= 7)
{
n = i;
p += 1;
i = digit(*p); if (i >= 0 && i <= 7)
{
p += 1;
n <<= 3;
n += i;
i = digit(*p); if (i >= 0 && i <= 7)
{
p += 1;
n <<= 3;
n += i;
}
}
} else if (*p == 'x')
{
p += 1; while (1)
{
i = digit(*p); if (i < 0 || i > 16) break;
p += 1;
n <<= 4;
n += i;
}
} else
{ staticconstchar 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/#elif"); 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;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.