summaryrefslogtreecommitdiff
path: root/src/SDCCval.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/SDCCval.c')
-rw-r--r--src/SDCCval.c3295
1 files changed, 3295 insertions, 0 deletions
diff --git a/src/SDCCval.c b/src/SDCCval.c
new file mode 100644
index 0000000..fc2016d
--- /dev/null
+++ b/src/SDCCval.c
@@ -0,0 +1,3295 @@
+/*----------------------------------------------------------------------
+ SDCCval.c :- has routine to do all kinds of fun stuff with the
+ value wrapper & with initialiser lists.
+
+ Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998)
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them. Help stamp out software-hoarding!
+-------------------------------------------------------------------------*/
+
+#include "common.h"
+#include <math.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+#include "newalloc.h"
+#include "dbuf_string.h"
+
+long cNestLevel;
+
+
+/*-----------------------------------------------------------------*/
+/* newValue - allocates and returns a new value */
+/*-----------------------------------------------------------------*/
+value *
+newValue (void)
+{
+ value *val;
+
+ val = Safe_alloc (sizeof (value));
+
+ return val;
+}
+
+/*-----------------------------------------------------------------*/
+/* newiList - new initializer list */
+/*-----------------------------------------------------------------*/
+initList *
+newiList (int type, void *ilist)
+{
+ initList *nilist;
+
+ nilist = Safe_alloc (sizeof (initList));
+
+ nilist->type = type;
+ nilist->filename = lexFilename;
+ nilist->lineno = lexLineno;
+ nilist->designation = NULL;
+
+ switch (type)
+ {
+ case INIT_NODE:
+ nilist->init.node = (struct ast *) ilist;
+ break;
+
+ case INIT_DEEP:
+ nilist->init.deep = (struct initList *) ilist;
+ break;
+ }
+
+ return nilist;
+}
+
+/*------------------------------------------------------------------*/
+/* revinit - reverses the initial values for a value chain */
+/*------------------------------------------------------------------*/
+initList *
+revinit (initList * val)
+{
+ initList *prev, *curr, *next;
+
+ if (!val)
+ return NULL;
+
+ prev = val;
+ curr = val->next;
+
+ while (curr)
+ {
+ next = curr->next;
+ curr->next = prev;
+ prev = curr;
+ curr = next;
+ }
+ val->next = (void *) NULL;
+ return prev;
+}
+
+bool
+convertIListToConstList (initList * src, literalList ** lList, int size)
+{
+ int cnt = 0;
+ initList *iLoop;
+ literalList *head, *last, *newL;
+
+ head = last = NULL;
+
+ if (src && src->type != INIT_DEEP)
+ {
+ return FALSE;
+ }
+
+ iLoop = src ? src->init.deep : NULL;
+
+ while (iLoop)
+ {
+ if (iLoop->designation != NULL)
+ {
+ return FALSE;
+ }
+
+ if (iLoop->type != INIT_NODE)
+ {
+ return FALSE;
+ }
+
+ if (!IS_AST_LIT_VALUE (decorateType (resolveSymbols (iLoop->init.node), RESULT_TYPE_NONE)))
+ {
+ return FALSE;
+ }
+ iLoop = iLoop->next;
+ cnt++;
+ }
+ if (!size)
+ {
+ size = cnt;
+ }
+
+ /* We've now established that the initializer list contains only literal values. */
+
+ iLoop = src ? src->init.deep : NULL;
+ while (size--)
+ {
+ double val = iLoop ? AST_FLOAT_VALUE (iLoop->init.node) : 0;
+
+ if (last && last->literalValue == val)
+ {
+ last->count++;
+ }
+ else
+ {
+ newL = Safe_alloc (sizeof (literalList));
+ newL->literalValue = val;
+ newL->count = 1;
+ newL->next = NULL;
+
+ if (last)
+ {
+ last->next = newL;
+ }
+ else
+ {
+ head = newL;
+ }
+ last = newL;
+ }
+ iLoop = iLoop ? iLoop->next : NULL;
+ }
+
+ if (!head)
+ {
+ return FALSE;
+ }
+
+ *lList = head;
+ return TRUE;
+}
+
+literalList *
+copyLiteralList (literalList * src)
+{
+ literalList *head, *prev, *newL;
+
+ head = prev = NULL;
+
+ while (src)
+ {
+ newL = Safe_alloc (sizeof (literalList));
+
+ newL->literalValue = src->literalValue;
+ newL->count = src->count;
+ newL->next = NULL;
+
+ if (prev)
+ {
+ prev->next = newL;
+ }
+ else
+ {
+ head = newL;
+ }
+ prev = newL;
+ src = src->next;
+ }
+
+ return head;
+}
+
+/*------------------------------------------------------------------*/
+/* copyIlist - copy initializer list */
+/*------------------------------------------------------------------*/
+initList *
+copyIlist (initList * src)
+{
+ initList *dest = NULL;
+
+ if (!src)
+ return NULL;
+
+ switch (src->type)
+ {
+ case INIT_DEEP:
+ dest = newiList (INIT_DEEP, copyIlist (src->init.deep));
+ break;
+ case INIT_NODE:
+ dest = newiList (INIT_NODE, copyAst (src->init.node));
+ break;
+ }
+
+ if (src->designation)
+ dest->designation = copyDesignation (src->designation);
+
+ if (src->next)
+ assert (dest != NULL);
+ dest->next = copyIlist (src->next);
+
+ return dest;
+}
+
+/*------------------------------------------------------------------*/
+/* list2int - converts the first element of the list to value */
+/*------------------------------------------------------------------*/
+double
+list2int (initList * val)
+{
+ initList *i = val;
+
+ assert (i->type != INIT_HOLE);
+
+ if (i->type == INIT_DEEP)
+ return list2int (val->init.deep);
+
+ return floatFromVal (constExprValue (val->init.node, TRUE));
+}
+
+/*------------------------------------------------------------------*/
+/* list2val - converts the first element of the list to value */
+/*------------------------------------------------------------------*/
+value *
+list2val (initList * val, int check)
+{
+ if (!val)
+ return NULL;
+
+ if(val->type == INIT_HOLE)
+ return NULL;
+
+ if (val->type == INIT_DEEP)
+ return list2val (val->init.deep, check);
+
+ if (val->type == INIT_NODE && val->init.node->opval.op == CAST)
+ return constExprValue (val->init.node->right, check);
+
+ return constExprValue (val->init.node, check);
+}
+
+/*------------------------------------------------------------------*/
+/* list2expr - returns the first expression in the initializer list */
+/*------------------------------------------------------------------*/
+ast *
+list2expr (initList * ilist)
+{
+ if (!ilist)
+ return NULL;
+
+ assert (ilist->type != INIT_HOLE);
+
+ if (ilist->type == INIT_DEEP)
+ return list2expr (ilist->init.deep);
+ return ilist->init.node;
+}
+
+/*------------------------------------------------------------------*/
+/* resolveIvalSym - resolve symbols in initial values */
+/*------------------------------------------------------------------*/
+void
+resolveIvalSym (initList *ilist, sym_link *type)
+{
+ int is_ptr = IS_PTR (type) || (IS_ARRAY(type) && IS_PTR(type->next));
+ RESULT_TYPE resultType = getResultTypeFromType (getSpec (type));
+
+ while (ilist)
+ {
+ if (ilist->type == INIT_NODE)
+ {
+ ilist->init.node = decorateType (resolveSymbols (ilist->init.node), is_ptr ? RESULT_TYPE_INT : resultType);
+ }
+ else if (ilist->type == INIT_DEEP)
+ {
+ resolveIvalSym (ilist->init.deep, type);
+ }
+
+ ilist = ilist->next;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* newDesignation - new designation */
+/*-----------------------------------------------------------------*/
+designation *
+newDesignation (int type, void *designator)
+{
+ designation *ndesignation;
+
+ ndesignation = Safe_alloc (sizeof (designation));
+
+ ndesignation->type = type;
+ ndesignation->filename = lexFilename;
+ ndesignation->lineno = lexLineno;
+
+ switch (type)
+ {
+ case DESIGNATOR_STRUCT:
+ ndesignation->designator.tag = (struct symbol *) designator;
+ break;
+
+ case DESIGNATOR_ARRAY:
+ ndesignation->designator.elemno = * ((int *) designator);
+ break;
+ }
+
+ return ndesignation;
+}
+
+/*------------------------------------------------------------------*/
+/* revDesignation - reverses the designation chain */
+/*------------------------------------------------------------------*/
+designation *
+revDesignation (designation * val)
+{
+ designation *prev, *curr, *next;
+
+ if (!val)
+ return NULL;
+
+ prev = val;
+ curr = val->next;
+
+ while (curr)
+ {
+ next = curr->next;
+ curr->next = prev;
+ prev = curr;
+ curr = next;
+ }
+ val->next = (void *) NULL;
+ return prev;
+}
+
+/*------------------------------------------------------------------*/
+/* copyDesignation - copy designation list */
+/*------------------------------------------------------------------*/
+designation *
+copyDesignation (designation * src)
+{
+ designation *dest = NULL;
+
+ if (!src)
+ return NULL;
+
+ switch (src->type)
+ {
+ case DESIGNATOR_STRUCT:
+ dest = newDesignation (DESIGNATOR_STRUCT, copySymbol (src->designator.tag));
+ break;
+ case DESIGNATOR_ARRAY:
+ dest = newDesignation (DESIGNATOR_ARRAY, &(src->designator.elemno) );
+ break;
+ }
+
+ dest->lineno = src->lineno;
+ dest->filename = src->filename;
+
+ if (src->next)
+ dest->next = copyDesignation (src->next);
+
+ return dest;
+}
+
+/*------------------------------------------------------------------*/
+/* moveNestedInit - rewrites an initList node with a nested */
+/* designator to remove one level of nesting. */
+/*------------------------------------------------------------------*/
+static
+void moveNestedInit(initList *deepParent, initList *src)
+{
+ initList *dst = NULL, **eol;
+
+ /** Create new initList element */
+ switch (src->type)
+ {
+ case INIT_NODE:
+ dst = newiList(INIT_NODE, src->init.node);
+ break;
+ case INIT_DEEP:
+ dst = newiList(INIT_DEEP, src->init.deep);
+ break;
+ }
+ dst->filename = src->filename;
+ dst->lineno = src->lineno;
+ dst->designation = src->designation->next;
+
+ /* add dst to end of deepParent */
+ if (deepParent->type != INIT_DEEP)
+ {
+ werrorfl (deepParent->filename, deepParent->lineno,
+ E_INIT_STRUCT, "<unknown>");
+ return;
+ }
+ for (eol = &(deepParent->init.deep); *eol ; )
+ eol = &((*eol)->next);
+ *eol = dst;
+}
+
+/*-----------------------------------------------------------------*/
+/* findStructField - find a specific field in a struct definition */
+/*-----------------------------------------------------------------*/
+static int
+findStructField (symbol *fields, symbol *target)
+{
+ int i;
+
+ for (i=0 ; fields; fields = fields->next)
+ {
+ /* skip past unnamed bitfields */
+ if (IS_BITFIELD (fields->type) && SPEC_BUNNAMED (fields->etype))
+ continue;
+ /* is this it? */
+ if (strcmp(fields->name, target->name) == 0)
+ return i;
+ i++;
+ }
+
+ /* not found */
+ werrorfl (target->fileDef, target->lineDef, E_NOT_MEMBER, target->name);
+ return 0;
+}
+
+/*------------------------------------------------------------------*/
+/* reorderIlist - expands an initializer list to match designated */
+/* initializers. */
+/*------------------------------------------------------------------*/
+initList *reorderIlist (sym_link * type, initList * ilist)
+{
+ initList *iloop, *nlist, **nlistArray;
+ symbol *sflds;
+ int size=0, idx;
+
+ if (!IS_AGGREGATE (type))
+ /* uninteresting: no designated initializers */
+ return ilist;
+
+ if (ilist && ilist->type == INIT_HOLE)
+ /* ditto; just a uninitialized hole */
+ return ilist;
+
+ /* special case: check for string initializer */
+ if (IS_ARRAY (type) && IS_CHAR (type->next) &&
+ ilist && ilist->type == INIT_NODE)
+ {
+ ast *iast = ilist->init.node;
+ value *v = (iast->type == EX_VALUE ? iast->opval.val : NULL);
+ if (v && IS_ARRAY (v->type) && IS_CHAR (v->etype))
+ {
+ /* yep, it's a string; no changes needed here. */
+ return ilist;
+ }
+ }
+
+ if (ilist && ilist->type != INIT_DEEP)
+ {
+ werrorfl (ilist->filename, ilist->lineno, E_INIT_STRUCT, "<unknown>");
+ return NULL;
+ }
+
+ /* okay, allocate enough space */
+ if (IS_ARRAY (type))
+ size = getNelements(type, ilist);
+ else if (IS_STRUCT (type))
+ {
+ /* compute size from struct type. */
+ size = 0;
+ for (sflds = SPEC_STRUCT (type)->fields; sflds; sflds = sflds->next)
+ {
+ /* skip past unnamed bitfields */
+ if (IS_BITFIELD (sflds->type) && SPEC_BUNNAMED (sflds->etype))
+ continue;
+ size++;
+ }
+ }
+ nlistArray = Safe_calloc ( size, sizeof(initList *) );
+
+ /* pull together all the initializers into an ordered list */
+ iloop = ilist ? ilist->init.deep : NULL;
+ for (idx = 0 ; iloop ; iloop = iloop->next, idx++)
+ {
+ if (iloop->designation)
+ {
+ assert (iloop->type != INIT_HOLE);
+
+ if (IS_ARRAY (type))
+ {
+ if (iloop->designation->type == DESIGNATOR_ARRAY)
+ idx = iloop->designation->designator.elemno;
+ else
+ werrorfl (iloop->filename, iloop->lineno, E_BAD_DESIGNATOR);
+ }
+ else if (IS_STRUCT (type))
+ {
+ if (iloop->designation->type == DESIGNATOR_STRUCT)
+ idx = findStructField (SPEC_STRUCT (type)->fields,
+ iloop->designation->designator.tag);
+ else
+ werrorfl (iloop->filename, iloop->lineno, E_BAD_DESIGNATOR);
+ }
+ else
+ {
+ assert (0);
+ }
+
+ if (iloop->designation->next)
+ {
+ if (idx >= size)
+ continue;
+ if (nlistArray[idx] == NULL)
+ nlistArray[idx] = newiList(INIT_DEEP, NULL);
+ moveNestedInit(nlistArray[idx], iloop);
+ continue;
+ }
+ }
+
+ /* overwrite any existing entry with iloop */
+ if (iloop->type != INIT_HOLE)
+ {
+ if (idx >= size)
+ continue;
+ if (nlistArray[idx] != NULL)
+ werrorfl (iloop->filename, iloop->lineno, W_DUPLICATE_INIT, idx);
+ nlistArray[idx] = iloop;
+ }
+ }
+
+ /* create new list from nlistArray/size */
+ nlist = NULL;
+ sflds = IS_STRUCT (type) ? SPEC_STRUCT (type)->fields : NULL;
+ for ( idx=0; idx < size; idx++ )
+ {
+ initList *src = nlistArray[idx], *dst = NULL;
+ if (!src || src->type==INIT_HOLE)
+ {
+ dst = newiList(INIT_HOLE, NULL);
+ dst->filename = ilist->filename;
+ dst->lineno = ilist->lineno;
+ }
+ else
+ {
+ switch (src->type)
+ {
+ case INIT_NODE:
+ dst = newiList(INIT_NODE, src->init.node);
+ break;
+ case INIT_DEEP:
+ dst = newiList(INIT_DEEP, src->init.deep);
+ break;
+ }
+ dst->filename = src->filename;
+ dst->lineno = src->lineno;
+ }
+ dst->next = nlist;
+ nlist = dst;
+ /* advance to next field which is not an unnamed bitfield */
+ do
+ {
+ sflds = sflds ? sflds->next : NULL;
+ }
+ while (sflds &&
+ IS_BITFIELD (sflds->type) && SPEC_BUNNAMED (sflds->etype));
+ }
+
+ nlist = newiList(INIT_DEEP, revinit (nlist));
+ nlist->filename = ilist->filename;
+ nlist->lineno = ilist->lineno;
+ nlist->designation = ilist->designation;
+ nlist->next = ilist->next;
+ return nlist;
+}
+
+/*------------------------------------------------------------------*/
+/* symbolVal - creates a value for a symbol */
+/*------------------------------------------------------------------*/
+value *
+symbolVal (symbol * sym)
+{
+ value *val;
+
+ if (!sym)
+ return NULL;
+
+ val = newValue ();
+ val->sym = sym;
+
+ if (sym->type)
+ {
+ val->type = sym->type;
+ val->etype = getSpec (val->type);
+ }
+
+ if (*sym->rname)
+ {
+ SNPRINTF (val->name, sizeof (val->name), "%s", sym->rname);
+ }
+ else
+ {
+ SNPRINTF (val->name, sizeof (val->name), "_%s", sym->name);
+ }
+
+ return val;
+}
+
+/*--------------------------------------------------------------------*/
+/* cheapestVal - try to reduce 'signed int' to 'char' */
+/*--------------------------------------------------------------------*/
+static value *
+cheapestVal (value * val)
+{
+ /* only int can be reduced */
+ if (!IS_INT (val->type))
+ return val;
+
+ /* long must not be changed */
+ if (SPEC_LONG (val->type) || SPEC_LONGLONG (val->type))
+ return val;
+
+ /* unsigned must not be changed */
+ if (SPEC_USIGN (val->type))
+ return val;
+
+ /* the only possible reduction is from signed int to (un)signed char,
+ because it's automatically promoted back to signed int.
+
+ a reduction from unsigned int to unsigned char is a bug,
+ because an _unsigned_ char is promoted to _signed_ int! */
+ if (SPEC_CVAL (val->type).v_int < -128 || SPEC_CVAL (val->type).v_int > 255)
+ {
+ /* not in the range of (un)signed char */
+ return val;
+ }
+
+ SPEC_NOUN (val->type) = V_CHAR;
+
+ /* 'unsigned char' promotes to 'signed int', so that we can
+ reduce it the other way */
+ if (SPEC_CVAL (val->type).v_int >= 0)
+ {
+ /* 'bool' promotes to 'signed int' too */
+ if (SPEC_CVAL (val->type).v_int <= 1)
+ {
+ /* Do not use V_BIT here because in some contexts it also */
+ /* implies a storage class. */
+ SPEC_NOUN (val->type) = V_BOOL;
+ }
+ else
+ {
+ /* Boolean types are intrinsically unsigned, so only */
+ /* set the USIGN flag for char types to avoid triggering */
+ /* type checking errors/warnings. */
+ SPEC_USIGN (val->type) = 1;
+ }
+ }
+
+ return (val);
+}
+
+/*-----------------------------------------------------------------*/
+/* double2ul - double to unsigned long conversion */
+/*-----------------------------------------------------------------*/
+unsigned long
+double2ul (double val)
+{
+/*
+ * See ISO/IEC 9899, chapter 6.3.1.4 Real floating and integer:
+ * If the value of the integral part cannot be represented by the integer type, the behavior is undefined.
+ * This shows up on Mac OS X i386 platform which useus SSE unit instead of the x87 FPU for floating-point operations
+ */
+/*
+ * on Mac OS X ppc (long) 2147483648.0 equals to 2147483647, so we explicitely convert it to 0x80000000
+ * on other known platforms (long) 2147483648.0 equals to -2147483648
+ */
+ return ((val) < 0) ? (((val) < -2147483647.0) ? 0x80000000UL : (unsigned long) -((long) -(val))) : (unsigned long) (val);
+}
+
+/*--------------------------------------------------------------------*/
+/* checkConstantRange - check if constant fits in numeric range of */
+/* var type in comparisons and assignments */
+/*--------------------------------------------------------------------*/
+CCR_RESULT
+checkConstantRange (sym_link * var, sym_link * lit, int op, bool exchangeLeftRight)
+{
+ sym_link *reType;
+ TYPE_TARGET_LONGLONG litVal;
+ TYPE_TARGET_ULONGLONG ulitVal;
+ TYPE_TARGET_ULONGLONG signExtMask;
+ TYPE_TARGET_ULONGLONG signMask;
+ bool litValUnsigned;
+ int varBits;
+
+ litVal = ullFromLit (lit);
+ ulitVal = (TYPE_TARGET_ULONGLONG) litVal;
+ litValUnsigned = SPEC_USIGN (lit);
+ varBits = bitsForType (var);
+ signMask = 1ull << (varBits-1);
+ signExtMask = varBits >= sizeof(TYPE_TARGET_ULONGLONG)*8 ? 0 : ~((1ull << varBits)-1);
+
+#if 0
+ printf(" ulitVal = 0x%016lx\n", ulitVal);
+ printf(" signExtMask = 0x%016lx\n", signExtMask);
+ printf(" signMask = 0x%016lx\n",signMask);
+#endif
+
+ //return CCR_OK; /* EEP - debug for long long */
+ /* sanity checks */
+ if (IS_FLOAT (var) || IS_FIXED (var))
+ return CCR_OK;
+ if (varBits < 1)
+ return CCR_ALWAYS_FALSE;
+ if (varBits > 64)
+ return CCR_ALWAYS_TRUE;
+
+ /* special: assignment */
+ if (op == '=')
+ {
+ if (IS_BOOLEAN (var))
+ return CCR_OK;
+
+ if (1) // Though the else branch is dead, I still would like to keep it.
+ //if (getenv ("SDCC_VERY_PEDANTIC"))
+ {
+ if (SPEC_USIGN (var))
+ {
+ if ((!litValUnsigned && litVal < 0) || (litVal & signExtMask) != 0)
+ return CCR_OVL;
+ return CCR_OK;
+ }
+ else
+ {
+ if (litValUnsigned)
+ {
+ if ((ulitVal & (signExtMask | signMask)) == 0)
+ return CCR_OK;
+ }
+ else
+ {
+ if ((litVal & (signExtMask | signMask)) == 0)
+ return CCR_OK;
+ if ((litVal & (signExtMask | signMask)) == (signExtMask | signMask))
+ return CCR_OK;
+ }
+ return CCR_OVL;
+ }
+ }
+ else
+ {
+ /* ignore signedness, e.g. allow everything
+ from -127...+255 for (unsigned) char */
+ if ((litVal & signExtMask) == 0)
+ return CCR_OK;
+ if ((litVal & (signExtMask | signMask)) == (signExtMask | signMask))
+ return CCR_OK;
+ return CCR_OVL;
+ }
+ }
+
+ if (exchangeLeftRight)
+ switch (op)
+ {
+ case EQ_OP:
+ break;
+ case NE_OP:
+ break;
+ case '>':
+ op = '<';
+ break;
+ case GE_OP:
+ op = LE_OP;
+ break;
+ case '<':
+ op = '>';
+ break;
+ case LE_OP:
+ op = GE_OP;
+ break;
+ default:
+ return CCR_ALWAYS_FALSE;
+ }
+
+ reType = computeType (var, lit, RESULT_TYPE_NONE, op);
+
+ if (SPEC_USIGN (reType))
+ {
+ /* unsigned operation */
+ int reBits = bitsForType (reType);
+ TYPE_TARGET_ULONGLONG minValP, maxValP, minValM, maxValM;
+ TYPE_TARGET_ULONGLONG opBitsMask = reBits >= sizeof(opBitsMask)*8 ? ~0ull : ((1ull << reBits)-1);
+
+ if (IS_BOOL (var))
+ {
+ minValP = 0;
+ maxValP = 1;
+ minValM = 0;
+ maxValM = 1;
+ }
+ else if (SPEC_USIGN (lit) && SPEC_USIGN (var))
+ {
+ /* both operands are unsigned, this is easy */
+ minValP = 0;
+ maxValP = ~signExtMask;
+ /* there's only range, just copy it to 2nd set */
+ minValM = minValP;
+ maxValM = maxValP;
+ }
+ else if (SPEC_USIGN (var))
+ {
+ /* lit is casted from signed to unsigned, e.g.:
+ unsigned u;
+ u == (char) -17
+ -> u == 0xffef'
+ */
+ minValP = 0;
+ maxValP = ~signExtMask;
+ /* there's only one range, just copy it to 2nd set */
+ minValM = minValP;
+ maxValM = maxValP;
+
+ /* it's an unsigned operation */
+ ulitVal &= opBitsMask;
+ }
+ else /* SPEC_USIGN (lit) */
+ {
+ /* var is casted from signed to unsigned, e.g.:
+ signed char c;
+ c == (unsigned) -17
+ -> c == 0xffef'
+
+ The possible values after casting var
+ split up in two, nonconsecutive ranges:
+
+ minValP = 0; positive range: 0...127
+ maxValP = 0x7f;
+ minValM = 0xff80; negative range: -128...-1
+ maxValM = 0xffff;
+ */
+
+ /* positive range */
+ minValP = 0;
+ maxValP = ~(signExtMask | signMask);
+
+ /* negative range */
+ minValM = signExtMask | signMask;
+ maxValM = (TYPE_TARGET_ULONGLONG)~0ull; /* -1 */
+ /* limit number of bits to size of return type */
+ minValM &= opBitsMask;
+ maxValM &= opBitsMask;
+ }
+#if 0
+ printf(" reType = ");
+ printTypeChain (reType, NULL);
+ printf(" ulitVal = 0x%016lx\n", ulitVal);
+ printf(" opBitsMask = 0x%016lx\n", opBitsMask);
+ printf(" maxValP = 0x%016lx\n", maxValP);
+ printf(" minValP = 0x%016lx\n", minValP);
+ printf(" maxValM = 0x%016lx\n", maxValM);
+ printf(" minValM = 0x%016lx\n", minValM);
+#endif
+
+ switch (op)
+ {
+ case EQ_OP: /* var == lit */
+ if (ulitVal <= maxValP && ulitVal >= minValP) /* 0 */
+ return CCR_OK;
+ if (ulitVal <= maxValM && ulitVal >= minValM)
+ return CCR_OK;
+ return CCR_ALWAYS_FALSE;
+ case NE_OP: /* var != lit */
+ if (ulitVal <= maxValP && ulitVal >= minValP) /* 0 */
+ return CCR_OK;
+ if (ulitVal <= maxValM && ulitVal >= minValM)
+ return CCR_OK;
+ return CCR_ALWAYS_TRUE;
+ case '>': /* var > lit */
+ if (ulitVal >= maxValM)
+ return CCR_ALWAYS_FALSE;
+ if (ulitVal < minValP) /* 0 */
+ return CCR_ALWAYS_TRUE;
+ return CCR_OK;
+ case GE_OP: /* var >= lit */
+ if (ulitVal > maxValM)
+ return CCR_ALWAYS_FALSE;
+ if (ulitVal <= minValP) /* 0 */
+ return CCR_ALWAYS_TRUE;
+ return CCR_OK;
+ case '<': /* var < lit */
+ if (ulitVal > maxValM)
+ return CCR_ALWAYS_TRUE;
+ if (ulitVal <= minValP) /* 0 */
+ return CCR_ALWAYS_FALSE;
+ return CCR_OK;
+ case LE_OP: /* var <= lit */
+ if (ulitVal >= maxValM)
+ return CCR_ALWAYS_TRUE;
+ if (ulitVal < minValP) /* 0 */
+ return CCR_ALWAYS_FALSE;
+ return CCR_OK;
+ default:
+ return CCR_ALWAYS_FALSE;
+ }
+ }
+ else
+ {
+ /* signed operation */
+ TYPE_TARGET_LONGLONG minVal, maxVal;
+
+ if (IS_BOOL (var))
+ {
+ minVal = 0;
+ maxVal = 1;
+ }
+ else if (SPEC_USIGN (var))
+ {
+ /* unsigned var, but signed operation. This happens
+ when var is promoted to signed int.
+ Set actual min/max values of var. */
+ minVal = 0;
+ maxVal = ~signExtMask;
+ }
+ else
+ {
+ /* signed var */
+ minVal = signExtMask | signMask;
+ maxVal = ~(signExtMask | signMask);
+ }
+
+ switch (op)
+ {
+ case EQ_OP: /* var == lit */
+ if (litVal > maxVal || litVal < minVal)
+ return CCR_ALWAYS_FALSE;
+ return CCR_OK;
+ case NE_OP: /* var != lit */
+ if (litVal > maxVal || litVal < minVal)
+ return CCR_ALWAYS_TRUE;
+ return CCR_OK;
+ case '>': /* var > lit */
+ if (litVal >= maxVal)
+ return CCR_ALWAYS_FALSE;
+ if (litVal < minVal)
+ return CCR_ALWAYS_TRUE;
+ return CCR_OK;
+ case GE_OP: /* var >= lit */
+ if (litVal > maxVal)
+ return CCR_ALWAYS_FALSE;
+ if (litVal <= minVal)
+ return CCR_ALWAYS_TRUE;
+ return CCR_OK;
+ case '<': /* var < lit */
+ if (litVal > maxVal)
+ return CCR_ALWAYS_TRUE;
+ if (litVal <= minVal)
+ return CCR_ALWAYS_FALSE;
+ return CCR_OK;
+ case LE_OP: /* var <= lit */
+ if (litVal >= maxVal)
+ return CCR_ALWAYS_TRUE;
+ if (litVal < minVal)
+ return CCR_ALWAYS_FALSE;
+ return CCR_OK;
+ default:
+ return CCR_ALWAYS_FALSE;
+ }
+ }
+}
+
+#if 0
+CCR_RESULT
+checkConstantRange (sym_link * var, sym_link * lit, int op, bool exchangeLeftRight)
+{
+ CCR_RESULT result;
+
+ printf ("checkConstantRange:\n");
+ printf (" var: ");
+ printTypeChain (var, NULL);
+ printf (" lit = 0x%lx: ",ullFromLit (lit));
+ printTypeChain (lit, NULL);
+ printf (" op: '");
+ switch (op)
+ {
+ case '<': printf ("<"); break;
+ case '=': printf ("="); break;
+ case '>': printf (">"); break;
+ case LE_OP: printf ("<="); break;
+ case GE_OP: printf (">="); break;
+ case EQ_OP: printf ("=="); break;
+ case NE_OP: printf ("!="); break;
+ default: printf ("%d",op);
+ }
+ printf("'\n");
+ result = checkConstantRange2 (var, lit, op, exchangeLeftRight);
+ switch (result)
+ {
+ case CCR_ALWAYS_TRUE: printf (" CCR_ALWAYS_TRUE\n"); break;
+ case CCR_ALWAYS_FALSE: printf (" CCR_ALWAYS_FALSE\n"); break;
+ case CCR_OK: printf (" CCR_OK\n"); break;
+ case CCR_OVL: printf (" CCR_OVL\n"); break;
+ default: printf(" CCR_%d\n",result);
+ }
+ return result;
+}
+#endif
+
+
+/*-----------------------------------------------------------------*/
+/* valueFromLit - creates a value from a literal */
+/*-----------------------------------------------------------------*/
+value *
+valueFromLit (double lit)
+{
+ struct dbuf_s dbuf;
+ value *ret;
+
+ if ((((TYPE_TARGET_LONG) lit) - lit) == 0)
+ {
+ dbuf_init (&dbuf, 128);
+ dbuf_printf (&dbuf, "%d", (TYPE_TARGET_LONG) lit);
+ ret = constVal (dbuf_c_str (&dbuf));
+ dbuf_destroy (&dbuf);
+ return ret;
+ }
+
+ dbuf_init (&dbuf, 128);
+ dbuf_printf (&dbuf, "%f", lit);
+ ret = constFloatVal (dbuf_c_str (&dbuf));
+ dbuf_destroy (&dbuf);
+ return ret;
+}
+
+/*-----------------------------------------------------------------*/
+/* constFloatVal - converts a FLOAT constant to value */
+/*-----------------------------------------------------------------*/
+value *
+constFloatVal (const char *s)
+{
+ value *val = newValue ();
+ double sval;
+ char *p;
+
+ sval = strtod (s, &p);
+ if (p == s)
+ {
+ werror (E_INVALID_FLOAT_CONST, s);
+ return constCharVal (0);
+ }
+
+ val->type = val->etype = newLink (SPECIFIER);
+ SPEC_NOUN (val->type) = V_FLOAT;
+ SPEC_SCLS (val->type) = S_LITERAL;
+ SPEC_CONST (val->type) = 1;
+ SPEC_CVAL (val->type).v_float = sval;
+
+ return val;
+}
+
+/*-----------------------------------------------------------------*/
+/* constFixed16x16Val - converts a FIXED16X16 constant to value */
+/*-----------------------------------------------------------------*/
+value *
+constFixed16x16Val (const char *s)
+{
+ value *val = newValue ();
+ double sval;
+ char *p;
+
+ sval = strtod (s, &p);
+ if (p == s)
+ {
+ werror (E_INVALID_FLOAT_CONST, s);
+ return constCharVal (0);
+ }
+
+ val->type = val->etype = newLink (SPECIFIER);
+ SPEC_NOUN (val->type) = V_FLOAT;
+ SPEC_SCLS (val->type) = S_LITERAL;
+ SPEC_CONST (val->type) = 1;
+ SPEC_CVAL (val->type).v_fixed16x16 = fixed16x16FromDouble (sval);
+
+ return val;
+}
+
+/*-----------------------------------------------------------------*/
+/* constVal - converts a constant into a cheap value type */
+/*-----------------------------------------------------------------*/
+value *
+constVal (const char *s)
+{
+ value *val = constIntVal (s);
+
+ wassert (SPEC_NOUN (val->type) == V_INT);
+
+ if (SPEC_LONGLONG (val->type))
+ ;
+ else if (SPEC_LONG (val->type))
+ ;
+ else if (SPEC_USIGN (val->type))
+ {
+ unsigned int i = SPEC_CVAL (val->type).v_uint;
+ if (i < 256)
+ SPEC_NOUN (val->type) = V_CHAR;
+ }
+ else
+ {
+ int i = SPEC_CVAL (val->type).v_int;
+ if (i >= 0 && i < 256)
+ {
+ SPEC_NOUN (val->type) = V_CHAR;
+ SPEC_USIGN (val->type) = TRUE;
+ SPEC_CVAL (val->type).v_uint = i;
+ }
+ else if (i >= -128 && i < 128)
+ {
+ SPEC_NOUN (val->type) = V_CHAR;
+ }
+ }
+
+ return val;
+}
+
+/*-----------------------------------------------------------------*/
+/* constIntVal - converts an integer constant into correct type */
+/* See ISO C11, section 6.4.4.1 for the rules. */
+/*-----------------------------------------------------------------*/
+value *
+constIntVal (const char *s)
+{
+ char *p, *p2;
+ double dval;
+ long long int llval;
+ value *val = newValue ();
+ bool decimal, u_suffix = FALSE, l_suffix = FALSE, ll_suffix = FALSE;
+
+ val->type = val->etype = newLink (SPECIFIER);
+ SPEC_SCLS (val->type) = S_LITERAL;
+ SPEC_CONST (val->type) = 1;
+ SPEC_USIGN (val->type) = 0;
+
+ errno = 0;
+
+ if (s[0] == '0')
+ {
+ if (s[1] == 'b' || s[1] == 'B')
+ llval = strtoull (s + 2, &p, 2);
+ else
+ llval = strtoull (s, &p, 0);
+ dval = (double)(unsigned long long int) llval;
+ decimal = FALSE;
+ }
+ else
+ {
+ dval = strtod (s, &p);
+ if (dval >= 0.0)
+ llval = strtoull (s, &p, 0);
+ else
+ llval = strtoll (s, &p, 0);
+ decimal = TRUE;
+ }
+
+ if (errno)
+ {
+ dval = 4294967295.0;
+ werror (W_INVALID_INT_CONST, s, dval);
+ }
+
+ // Check suffixes
+ if ((p2 = strchr (p, 'u')) || (p2 = strchr (p, 'U')))
+ {
+ u_suffix = TRUE;
+ p2++;
+ if (strchr (p2, 'u') || strchr (p2, 'U'))
+ werror (E_INTEGERSUFFIX, p);
+ }
+
+ if ((p2 = strstr (p, "ll")) || (p2 = strstr (p, "LL")))
+ {
+ ll_suffix = TRUE;
+ p2 += 2;
+ if (strchr (p2, 'l') || strchr (p2, 'L'))
+ werror (E_INTEGERSUFFIX, p);
+ }
+ else if ((p2 = strchr (p, 'l')) || (p2 = strchr (p, 'L')))
+ {
+ l_suffix = TRUE;
+ p2++;
+ if (strchr (p2, 'l') || strchr (p2, 'L'))
+ werror (E_INTEGERSUFFIX, p);
+ }
+
+ SPEC_NOUN (val->type) = V_INT;
+
+ if (u_suffix) // Choose first of unsigned int, unsigned long int, unsigned long long int that fits.
+ {
+ SPEC_USIGN (val->type) = 1;
+ if (ll_suffix || dval > 0xffffffff)
+ SPEC_LONGLONG (val->type) = 1;
+ else if(l_suffix || dval > 0xffff)
+ SPEC_LONG (val->type) = 1;
+ }
+ else
+ {
+ if (decimal) // Choose first of int, long int, long long int that fits.
+ {
+ if (ll_suffix || dval > 0x7fffffff || dval < -0x80000000ll)
+ {
+ if (!options.std_c99) // C90 exception: Use unsigned long
+ {
+ SPEC_USIGN (val->type) = 1;
+ SPEC_LONG (val->type) = 1;
+ }
+ else
+ SPEC_LONGLONG (val->type) = 1;
+ }
+ else if(l_suffix || dval > 0x7fff || dval < -0x8000l)
+ SPEC_LONG (val->type) = 1;
+ }
+ else // Choose first of int, unsigned int, long int, unsigned long int, long long int, unsigned long long int that fits.
+ {
+ if (dval > 0x7fffffffffffffff)
+ {
+ SPEC_USIGN (val->type) = 1;
+ SPEC_LONGLONG (val->type) = 1;
+ }
+ else if (ll_suffix || dval > 0xffffffff || dval < -0x80000000ll)
+ {
+ SPEC_LONGLONG (val->type) = 1;
+ }
+ else if (dval > 0x7fffffff)
+ {
+ SPEC_USIGN (val->type) = 1;
+ SPEC_LONG (val->type) = 1;
+ }
+ else if (l_suffix || dval > 0xffff || dval < -0x8000l)
+ {
+ SPEC_LONG (val->type) = 1;
+ }
+ else if (dval > 0x7fff)
+ {
+ SPEC_USIGN (val->type) = 1;
+ }
+ }
+ }
+
+ /* check for out of range */
+ if (!SPEC_LONGLONG (val->type))
+ {
+ if (dval < -2147483648.0)
+ {
+ dval = -2147483648.0;
+ werror (W_INVALID_INT_CONST, s, dval);
+ }
+ if (dval > 2147483648.0 && !SPEC_USIGN (val->type))
+ {
+ dval = 2147483647.0;
+ werror (W_INVALID_INT_CONST, s, dval);
+ }
+ if (dval > 4294967295.0)
+ {
+ dval = 4294967295.0;
+ werror (W_INVALID_INT_CONST, s, dval);
+ }
+ }
+
+ if (SPEC_LONGLONG (val->type))
+ {
+ if (SPEC_USIGN (val->type))
+ {
+ SPEC_CVAL (val->type).v_ulonglong = (TYPE_TARGET_ULONGLONG) llval;
+ }
+ else
+ {
+ SPEC_CVAL (val->type).v_longlong = (TYPE_TARGET_LONGLONG) llval;
+ }
+ }
+ else if (SPEC_LONG (val->type))
+ {
+ if (SPEC_USIGN (val->type))
+ {
+ SPEC_CVAL (val->type).v_ulong = (TYPE_TARGET_ULONG) double2ul (dval);
+ }
+ else
+ {
+ SPEC_CVAL (val->type).v_long = (TYPE_TARGET_LONG) double2ul (dval);
+ }
+ }
+ else
+ {
+ if (SPEC_USIGN (val->type))
+ {
+ SPEC_CVAL (val->type).v_uint = (TYPE_TARGET_UINT) double2ul (dval);
+ }
+ else
+ {
+ SPEC_CVAL (val->type).v_int = (TYPE_TARGET_INT) double2ul (dval);
+ }
+ }
+
+ return val;
+}
+
+/*-----------------------------------------------------------------*/
+/* constCharacterVal - converts a character constant to value */
+/*-----------------------------------------------------------------*/
+value *
+constCharacterVal (unsigned long v, char type)
+{
+ value *val = newValue (); /* alloc space for value */
+
+ val->type = val->etype = newLink (SPECIFIER); /* create the specifier */
+ SPEC_SCLS (val->type) = S_LITERAL;
+ SPEC_CONST (val->type) = 1;
+
+ switch (type)
+ {
+ case 0: // character constant
+ SPEC_NOUN (val->type) = V_INT;
+ SPEC_USIGN (val->type) = 0;
+ SPEC_CVAL (val->type).v_int = options.signed_char ? (signed char) v : (unsigned char) v;
+ break;
+ case 'L': // wide character constant
+ if (!options.std_c95)
+ werror (E_WCHAR_CONST_C95);
+ SPEC_NOUN (val->type) = V_INT;
+ SPEC_USIGN (val->type) = 1;
+ SPEC_LONG (val->etype) = 1;
+ SPEC_CVAL (val->type).v_ulong = (TYPE_UDWORD) v;
+ break;
+ case 'u': // wide character constant
+ if (!options.std_c11)
+ werror (E_WCHAR_CONST_C11);
+ SPEC_NOUN (val->type) = V_INT;
+ SPEC_USIGN (val->type) = 1;
+ SPEC_CVAL (val->type).v_uint = (TYPE_UWORD) v;
+ break;
+ case 'U': // wide character constant
+ if (!options.std_c11)
+ werror (E_WCHAR_CONST_C11);
+ SPEC_NOUN (val->type) = V_INT;
+ SPEC_USIGN (val->type) = 1;
+ SPEC_LONG (val->etype) = 1;
+ SPEC_CVAL (val->type).v_ulong = (TYPE_UDWORD) v;
+ break;
+ default:
+ wassert (0);
+ }
+
+ return val;
+}
+
+/*-----------------------------------------------------------------*/
+/* constCharVal - converts a character constant to value */
+/*-----------------------------------------------------------------*/
+value *
+constCharVal (unsigned char v)
+{
+ return constCharacterVal (v, 0);
+}
+
+/*-----------------------------------------------------------------*/
+/* constBoolVal - converts a BOOL constant to value */
+/*-----------------------------------------------------------------*/
+value *
+constBoolVal (bool v)
+{
+ value *val = newValue (); /* alloc space for value */
+
+ val->type = val->etype = newLink (SPECIFIER); /* create the specifier */
+ SPEC_SCLS (val->type) = S_LITERAL;
+ SPEC_CONST (val->type) = 1;
+
+ SPEC_NOUN (val->type) = (bit) ? V_BIT : V_BOOL;
+
+ SPEC_CVAL (val->type).v_uint = (unsigned int) v;
+
+ return val;
+}
+
+// TODO: Move this function to SDCCutil?
+static const TYPE_UDWORD *utf_32_from_utf_8 (size_t *utf_32_len, const char *utf_8, size_t utf_8_len)
+{
+ size_t allocated = 0;
+ TYPE_UDWORD *utf_32 = 0;
+ unsigned char first_byte;
+ TYPE_UDWORD codepoint;
+ size_t seqlen;
+
+ for (*utf_32_len = 0; utf_8_len; (*utf_32_len)++)
+ {
+ if (allocated == *utf_32_len)
+ {
+ utf_32 = realloc (utf_32, sizeof(TYPE_UDWORD) * (*utf_32_len + 16));
+ wassert (utf_32);
+ allocated = *utf_32_len + 16;
+ }
+
+ first_byte = *utf_8;
+ seqlen = 1;
+ if (first_byte & 0x80)
+ {
+ while (first_byte & (0x80 >> seqlen))
+ seqlen++;
+ first_byte &= (0xff >> (seqlen + 1));
+ }
+ wassert (seqlen <= 6); // seqlen 5 and 6 are deprecated in current unicode standard, but for now, allow them.
+
+ codepoint = first_byte;
+ utf_8++;
+ utf_8_len--;
+ seqlen--;
+
+ for(; seqlen; seqlen--)
+ {
+ codepoint <<= 6;
+ codepoint |= (*utf_8 & 0x3f);
+ utf_8++;
+ utf_8_len--;
+ }
+
+ utf_32[*utf_32_len] = codepoint;
+ }
+ return (utf_32);
+}
+
+// TODO: Move this function to SDCCutil?
+static const TYPE_UWORD *utf_16_from_utf_32 (size_t *utf_16_len, const TYPE_UDWORD *utf_32, size_t utf_32_len)
+{
+ size_t allocated = 0;
+ TYPE_UWORD *utf_16 = 0;
+ TYPE_UDWORD codepoint;
+
+ for (*utf_16_len = 0; utf_32_len; utf_32_len--, utf_32++)
+ {
+ if (allocated <= *utf_16_len + 2)
+ {
+ utf_16 = realloc (utf_16, sizeof(TYPE_UWORD) * (*utf_16_len + 16));
+ wassert (utf_16);
+ allocated = *utf_16_len + 16;
+ }
+
+ codepoint = *utf_32;
+
+ if (codepoint < 0xd7ff || codepoint >= 0xe000 && codepoint <= 0xffff) // Code in basic multilingual plane.
+ {
+ utf_16[(*utf_16_len)++] = codepoint;
+ continue;
+ }
+
+ // Code point in supplementary plane.
+ wassert (codepoint >= 0x100000 && codepoint <= 0x10ffff);
+ codepoint -= 0x100000;
+
+ utf_16[(*utf_16_len)++] = ((codepoint >> 10) & 0x3ff) + 0xd800;
+ utf_16[(*utf_16_len)++] = (codepoint & 0x3ff) + 0xdc00;
+ }
+
+ return (utf_16);
+}
+
+/*------------------------------------------------------------------*/
+/* strVal - converts a string constant to a value */
+/*------------------------------------------------------------------*/
+value *
+strVal (const char *s)
+{
+ value *val;
+ const char *utf_8;
+ size_t utf_8_size;
+
+ val = newValue ();
+
+ /* get a declarator */
+ val->type = newLink (DECLARATOR);
+ DCL_TYPE (val->type) = ARRAY;
+ val->type->next = val->etype = newLink (SPECIFIER);
+ SPEC_SCLS (val->etype) = S_LITERAL;
+ SPEC_CONST (val->etype) = 1;
+
+ // Convert input string (mixed UTF-8 and UTF-32) to UTF-8 first (handling all escape sequences, etc).
+ utf_8 = copyStr (s[0] == '"' ? s : s + 1, &utf_8_size);
+
+ if (s[0] == '"') // UTF-8 string literal (any prefix u8 or L in the source would already have been stripped by earlier stages)
+ {
+ SPEC_NOUN (val->etype) = V_CHAR;
+ SPEC_USIGN (val->etype) = !options.signed_char;
+ val->etype->select.s.b_implicit_sign = true;
+ SPEC_CVAL (val->etype).v_char = utf_8;
+ DCL_ELEM (val->type) = utf_8_size;
+ }
+ else
+ {
+ size_t utf_32_size;
+ // Convert to UTF-32 next, since converting UTF-32 to UTF-16 is easier than UTF-8 to UTF-16.
+ const TYPE_UDWORD *utf_32 = utf_32_from_utf_8 (&utf_32_size, utf_8, utf_8_size);
+
+ dbuf_free (utf_8);
+
+ if (s[0] == 'U' || s[0] == 'L') // UTF-32 string literal
+ {
+ SPEC_NOUN (val->etype) = V_INT;
+ SPEC_USIGN (val->etype) = 1;
+ SPEC_LONG (val->etype) = 1;
+ SPEC_CVAL (val->etype).v_char32 = utf_32;
+ DCL_ELEM (val->type) = utf_32_size;
+ }
+ else if (s[0] == 'u') // UTF-16 string literal
+ {
+ size_t utf_16_size;
+ const TYPE_UWORD *utf_16 = utf_16_from_utf_32 (&utf_16_size, utf_32, utf_32_size);
+
+ SPEC_NOUN (val->etype) = V_INT;
+ SPEC_USIGN (val->etype) = 1;
+ SPEC_CVAL (val->etype).v_char16 = utf_16;
+ DCL_ELEM (val->type) = utf_16_size;
+ }
+ else
+ wassert (0);
+ }
+
+ return (val);
+}
+
+/*------------------------------------------------------------------*/
+/* rawStrVal - converts a string to a value */
+/*------------------------------------------------------------------*/
+value *
+rawStrVal (const char *s, size_t size)
+{
+ struct dbuf_s dbuf;
+ value *val = newValue ();
+
+ dbuf_init (&dbuf, size);
+ wassert (dbuf_append (&dbuf, s, size));
+
+ /* get a declarator */
+ val->type = newLink (DECLARATOR);
+ DCL_TYPE (val->type) = ARRAY;
+ val->type->next = val->etype = newLink (SPECIFIER);
+ SPEC_SCLS (val->etype) = S_LITERAL;
+ SPEC_CONST (val->etype) = 1;
+
+ SPEC_NOUN (val->etype) = V_CHAR;
+ SPEC_USIGN (val->etype) = !options.signed_char;
+ val->etype->select.s.b_implicit_sign = true;
+ SPEC_CVAL (val->etype).v_char = dbuf_detach (&dbuf);
+ DCL_ELEM (val->type) = size;
+
+ return (val);
+}
+
+/*------------------------------------------------------------------*/
+/* reverseValWithType - reverses value chain with type & etype */
+/*------------------------------------------------------------------*/
+value *
+reverseValWithType (value * val)
+{
+ sym_link *type;
+ sym_link *etype;
+
+ if (!val)
+ return NULL;
+
+ /* save the type * etype chains */
+ type = val->type;
+ etype = val->etype;
+
+ /* set the current one 2b null */
+ val->type = val->etype = NULL;
+ val = reverseVal (val);
+
+ /* restore type & etype */
+ val->type = type;
+ val->etype = etype;
+
+ return val;
+}
+
+/*------------------------------------------------------------------*/
+/* reverseVal - reverses the values for a value chain */
+/*------------------------------------------------------------------*/
+value *
+reverseVal (value * val)
+{
+ value *prev, *curr, *next;
+
+ if (!val)
+ return NULL;
+
+ prev = val;
+ curr = val->next;
+
+ while (curr)
+ {
+ next = curr->next;
+ curr->next = prev;
+ prev = curr;
+ curr = next;
+ }
+ val->next = (void *) NULL;
+ return prev;
+}
+
+/*------------------------------------------------------------------*/
+/* copyValueChain - will copy a chain of values */
+/*------------------------------------------------------------------*/
+value *
+copyValueChain (value * src)
+{
+ value *dest;
+
+ if (!src)
+ return NULL;
+
+ dest = copyValue (src);
+ dest->next = copyValueChain (src->next);
+
+ return dest;
+}
+
+/*------------------------------------------------------------------*/
+/* copyValue - copies contents of a value to a fresh one */
+/*------------------------------------------------------------------*/
+value *
+copyValue (value * src)
+{
+ value *dest;
+
+ dest = newValue ();
+ dest->sym = copySymbol (src->sym);
+ strncpyz (dest->name, src->name, SDCC_NAME_MAX);
+ dest->type = (src->type ? copyLinkChain (src->type) : NULL);
+ dest->etype = (src->type ? getSpec (dest->type) : NULL);
+
+ return dest;
+}
+
+/*------------------------------------------------------------------*/
+/* charVal - converts a character constant to a value */
+/*------------------------------------------------------------------*/
+value *
+charVal (const char *s)
+{
+ char type;
+
+ if (*s == 'L' || *s == 'u' || *s == 'U')
+ type = *s++;
+ else
+ type = 0;
+
+ s++; // Get rid of quotation.
+
+ /* if \ then special processing */
+ if (*s == '\\')
+ {
+ switch (*++s) /* go beyond the backslash */
+ {
+ case 'n':
+ return constCharacterVal ('\n', type);
+ case 't':
+ return constCharacterVal ('\t', type);
+ case 'v':
+ return constCharacterVal ('\v', type);
+ case 'b':
+ return constCharacterVal ('\b', type);
+ case 'r':
+ return constCharacterVal ('\r', type);
+ case 'f':
+ return constCharacterVal ('\f', type);
+ case 'a':
+ return constCharacterVal ('\a', type);
+ case '\\':
+ return constCharacterVal ('\\', type);
+ case '\?':
+ return constCharacterVal ('\?', type);
+ case '\'':
+ return constCharacterVal ('\'', type);
+ case '\"':
+ return constCharacterVal ('\"', type);
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ return constCharacterVal (octalEscape (&s), type);
+
+ case 'x':
+ return constCharacterVal (hexEscape (&s), type);
+
+ case 'u':
+ return constCharacterVal (universalEscape (&s, 4), type);
+
+ case 'U':
+ return constCharacterVal (universalEscape (&s, 8), type);
+
+ default:
+ return constCharacterVal (*s, type);
+ }
+ }
+ else if (type) // Wide character constant
+ {
+ size_t ulen;
+ const TYPE_UDWORD *ustr = utf_32_from_utf_8 (&ulen, s, strlen(s) - 1);
+ value *val = constCharacterVal (*ustr, type);
+ free ((void *)ustr);
+ return (val);
+ }
+ else // Character constant that is not wide - compability with legacy encodings.
+ return constCharacterVal (*s, 0);
+}
+
+/*------------------------------------------------------------------*/
+/* valFromType - creates a value from type given */
+/*------------------------------------------------------------------*/
+value *
+valFromType (sym_link * type)
+{
+ value *val = newValue ();
+ val->type = copyLinkChain (type);
+ val->etype = getSpec (val->type);
+ return val;
+}
+
+/*------------------------------------------------------------------*/
+/* floatFromVal - value to double float conversion */
+/*------------------------------------------------------------------*/
+double
+floatFromVal (value * val)
+{
+ if (!val)
+ return 0;
+
+ if (val->etype && SPEC_SCLS (val->etype) != S_LITERAL)
+ {
+ werror (E_CONST_EXPECTED, val->name);
+ return 0;
+ }
+
+ /* if it is not a specifier then we can assume that */
+ /* it will be an unsigned long */
+ if (!IS_SPEC (val->type))
+ return SPEC_CVAL (val->etype).v_ulong;
+
+ if (SPEC_NOUN (val->etype) == V_FLOAT)
+ return SPEC_CVAL (val->etype).v_float;
+
+ if (SPEC_NOUN (val->etype) == V_FIXED16X16)
+ return doubleFromFixed16x16 (SPEC_CVAL (val->etype).v_fixed16x16);
+
+ if (SPEC_LONGLONG (val->etype))
+ {
+ if (SPEC_USIGN (val->etype))
+ return (double)SPEC_CVAL (val->etype).v_ulonglong;
+ else
+ return (double)SPEC_CVAL (val->etype).v_longlong;
+ }
+
+ if (SPEC_LONG (val->etype))
+ {
+ if (SPEC_USIGN (val->etype))
+ return SPEC_CVAL (val->etype).v_ulong;
+ else
+ return SPEC_CVAL (val->etype).v_long;
+ }
+
+ if (SPEC_NOUN (val->etype) == V_INT)
+ {
+ if (SPEC_USIGN (val->etype))
+ return SPEC_CVAL (val->etype).v_uint;
+ else
+ return SPEC_CVAL (val->etype).v_int;
+ }
+
+ if (SPEC_NOUN (val->etype) == V_CHAR)
+ {
+ if (SPEC_USIGN (val->etype))
+ return (unsigned char) SPEC_CVAL (val->etype).v_uint;
+ else
+ return (signed char) SPEC_CVAL (val->etype).v_int;
+ }
+
+ if (IS_BOOL (val->etype) || IS_BITVAR (val->etype))
+ return SPEC_CVAL (val->etype).v_uint;
+
+ if (SPEC_NOUN (val->etype) == V_VOID)
+ return SPEC_CVAL (val->etype).v_ulong;
+
+ if (SPEC_NOUN (val->etype) == V_STRUCT)
+ return SPEC_CVAL (val->etype).v_ulong;
+
+ /* we are lost ! */
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "floatFromVal: unknown value");
+ return 0;
+}
+
+/*------------------------------------------------------------------*/
+/* ulFromVal - value to unsigned long conversion */
+/*------------------------------------------------------------------*/
+unsigned long
+ulFromVal (value *val)
+{
+ if (!val)
+ return 0;
+
+ if (val->etype && SPEC_SCLS (val->etype) != S_LITERAL)
+ {
+ werror (E_CONST_EXPECTED, val->name);
+ return 0;
+ }
+
+ /* if it is not a specifier then we can assume that */
+ /* it will be an unsigned long */
+ if (!IS_SPEC (val->type))
+ return SPEC_CVAL (val->etype).v_ulong;
+
+ if (SPEC_NOUN (val->etype) == V_FLOAT)
+ return double2ul (SPEC_CVAL (val->etype).v_float);
+
+ if (SPEC_NOUN (val->etype) == V_FIXED16X16)
+ return double2ul (doubleFromFixed16x16 (SPEC_CVAL (val->etype).v_fixed16x16));
+
+ if (SPEC_LONGLONG (val->etype))
+ {
+ if (SPEC_USIGN (val->etype))
+ return (unsigned long)SPEC_CVAL (val->etype).v_ulonglong;
+ else
+ return (unsigned long)SPEC_CVAL (val->etype).v_longlong;
+ }
+
+ if (SPEC_LONG (val->etype))
+ {
+ if (SPEC_USIGN (val->etype))
+ return SPEC_CVAL (val->etype).v_ulong;
+ else
+ return SPEC_CVAL (val->etype).v_long;
+ }
+
+ if (SPEC_NOUN (val->etype) == V_INT)
+ {
+ if (SPEC_USIGN (val->etype))
+ return SPEC_CVAL (val->etype).v_uint;
+ else
+ return SPEC_CVAL (val->etype).v_int;
+ }
+
+ if (SPEC_NOUN (val->etype) == V_CHAR)
+ {
+ if (SPEC_USIGN (val->etype))
+ return (unsigned char) SPEC_CVAL (val->etype).v_uint;
+ else
+ return (signed char) SPEC_CVAL (val->etype).v_int;
+ }
+
+ if (IS_BOOL (val->etype) || IS_BITVAR (val->etype))
+ return SPEC_CVAL (val->etype).v_uint;
+
+ if (SPEC_NOUN (val->etype) == V_VOID)
+ return SPEC_CVAL (val->etype).v_ulong;
+
+ if (SPEC_NOUN (val->etype) == V_STRUCT)
+ return SPEC_CVAL (val->etype).v_ulong;
+
+ /* we are lost ! */
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "ulFromVal: unknown value");
+ return 0;
+}
+
+/*------------------------------------------------------------------*/
+/* byteOfVal - extract a byte of a value */
+/* offset = 0 (LSB) ... n-1 (MSB) */
+/* higher offsets of signed ints will be sign extended, */
+/* other types will be extended with zero padding */
+/*------------------------------------------------------------------*/
+unsigned char
+byteOfVal (value * val, int offset)
+{
+ unsigned char *p;
+ int shift = 8*offset;
+
+ wassert (offset >= 0);
+
+ if (!val)
+ return 0;
+
+ if (val->etype && SPEC_SCLS (val->etype) != S_LITERAL)
+ {
+ werror (E_CONST_EXPECTED, val->name);
+ return 0;
+ }
+
+ /* if it is not a specifier then we can assume that */
+ /* it will be an unsigned long */
+ /* 2012-Apr-30 EEP - Why is this true? */
+ if (!IS_SPEC (val->type))
+ return offset < 4 ? (SPEC_CVAL (val->etype).v_ulong >> shift) & 0xff : 0;
+
+ if (SPEC_NOUN (val->etype) == V_FLOAT)
+ {
+ float f = (float)SPEC_CVAL (val->etype).v_float;
+
+ if (offset > 3)
+ return 0;
+ p = (unsigned char *)&f;
+#ifdef WORDS_BIGENDIAN
+ p += 3 - offset;
+#else
+ p += offset;
+#endif
+ return *p;
+ }
+
+ if (SPEC_NOUN (val->etype) == V_FIXED16X16)
+ return offset < 4 ? (SPEC_CVAL (val->etype).v_fixed16x16 >> shift) & 0xff : 0;
+
+ if (SPEC_LONGLONG (val->etype))
+ {
+ if (SPEC_USIGN (val->etype))
+ return offset < 8 ? (SPEC_CVAL (val->etype).v_ulonglong >> shift) & 0xff : 0;
+ else
+ return offset < 8 ? (SPEC_CVAL (val->etype).v_longlong >> shift) & 0xff :
+ (SPEC_CVAL (val->etype).v_longlong < 0 ? 0xff : 0);
+ }
+
+ if (SPEC_LONG (val->etype))
+ {
+ if (SPEC_USIGN (val->etype))
+ return offset < 4 ? (SPEC_CVAL (val->etype).v_ulong >> shift) & 0xff : 0;
+ else
+ return offset < 4 ? (SPEC_CVAL (val->etype).v_long >> shift) & 0xff :
+ (SPEC_CVAL (val->etype).v_long < 0 ? 0xff : 0);
+ }
+
+ if (SPEC_NOUN (val->etype) == V_INT)
+ {
+ if (SPEC_USIGN (val->etype))
+ return offset < 2 ? (SPEC_CVAL (val->etype).v_uint >> shift) & 0xff : 0;
+ else
+ return offset < 2 ? (SPEC_CVAL (val->etype).v_int >> shift) & 0xff :
+ (SPEC_CVAL (val->etype).v_int < 0 ? 0xff : 0);
+ }
+
+ if (SPEC_NOUN (val->etype) == V_CHAR)
+ {
+ if (SPEC_USIGN (val->etype))
+ return offset < 1 ? SPEC_CVAL (val->etype).v_uint & 0xff : 0;
+ else
+ return offset < 1 ? SPEC_CVAL (val->etype).v_int & 0xff :
+ (SPEC_CVAL (val->etype).v_int < 0 ? 0xff : 0);
+ }
+
+ if (IS_BOOL (val->etype) || IS_BITVAR (val->etype))
+ return offset < 2 ? (SPEC_CVAL (val->etype).v_uint >> shift) & 0xff : 0;
+
+ /* we are lost ! */
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "byteOfVal: unknown value");
+ return 0;
+}
+
+/*------------------------------------------------------------------*/
+/* ullFromLit - literal to unsigned long long conversion */
+/*------------------------------------------------------------------*/
+TYPE_TARGET_ULONGLONG
+ullFromLit (sym_link * lit)
+{
+ sym_link * etype = getSpec(lit);
+
+ if (!lit)
+ return 0;
+
+ if (etype && SPEC_SCLS (etype) != S_LITERAL)
+ {
+ werror (E_CONST_EXPECTED, "");
+ return 0;
+ }
+
+ /* if it is not a specifier then we can assume that */
+ /* it will be an unsigned long */
+ if (!IS_SPEC (lit))
+ return SPEC_CVAL (etype).v_ulong;
+
+ if (SPEC_NOUN (etype) == V_FLOAT)
+ return double2ul (SPEC_CVAL (etype).v_float); /* FIXME: this loses bits */
+
+ if (SPEC_NOUN (etype) == V_FIXED16X16)
+ return double2ul (doubleFromFixed16x16 (SPEC_CVAL (etype).v_fixed16x16)); /* FIXME: this loses bits */
+
+ if (SPEC_LONGLONG (etype))
+ {
+ if (SPEC_USIGN (etype))
+ return SPEC_CVAL (etype).v_ulonglong;
+ else
+ return SPEC_CVAL (etype).v_longlong;
+ }
+
+ if (SPEC_LONG (etype))
+ {
+ if (SPEC_USIGN (etype))
+ return SPEC_CVAL (etype).v_ulong;
+ else
+ return SPEC_CVAL (etype).v_long;
+ }
+
+ if (SPEC_NOUN (etype) == V_INT)
+ {
+ if (SPEC_USIGN (etype))
+ return SPEC_CVAL (etype).v_uint;
+ else
+ return SPEC_CVAL (etype).v_int;
+ }
+
+ if (SPEC_NOUN (etype) == V_CHAR)
+ {
+ if (SPEC_USIGN (etype))
+ return (unsigned char) SPEC_CVAL (etype).v_uint;
+ else
+ return (signed char) SPEC_CVAL (etype).v_int;
+ }
+
+ if (IS_BOOL (etype) || IS_BITVAR (etype))
+ return SPEC_CVAL (etype).v_uint;
+
+ if (SPEC_NOUN (etype) == V_VOID)
+ return SPEC_CVAL (etype).v_ulong;
+
+ if (SPEC_NOUN (etype) == V_STRUCT) /* ??? Why ??? EEP - 23 Nov 2012 */
+ return SPEC_CVAL (etype).v_ulong;
+
+ /* we are lost ! */
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "ullFromLit: unknown value");
+ return 0;
+}
+
+/*------------------------------------------------------------------*/
+/* ullFromVal - value to unsigned long long conversion */
+/*------------------------------------------------------------------*/
+unsigned long long
+ullFromVal (value * val)
+{
+ if (!val)
+ return 0;
+
+ if (val->etype && SPEC_SCLS (val->etype) != S_LITERAL)
+ {
+ werror (E_CONST_EXPECTED, val->name);
+ return 0;
+ }
+ return (unsigned long long) ullFromLit (val->type);
+}
+
+/*------------------------------------------------------------------*/
+/* csdOfVal - return 0 if the value can be represented as csd */
+/* topbit - highest nonzero bit in csd */
+/* nonzero - number of nonzero bits in csd */
+/* csd_add - positive bits in csd */
+/* csd_sub - negative bits in csd */
+/*------------------------------------------------------------------*/
+int csdOfVal (int *topbit, int *nonzero, unsigned long long *csd_add, unsigned long long *csd_sub, value *val)
+{
+ unsigned long long binary = ullFromVal (val);
+ bool gamma, theta, a;
+ int bit, next;
+
+ *topbit = 0;
+ *nonzero = 0;
+ *csd_add = 0;
+ *csd_sub = 0;
+
+ for (a = 0, gamma = 0, bit = 0; bit < 61; bit++)
+ {
+ theta = a ^ (binary & 1);
+ gamma = !gamma && theta;
+ next = (1 - 2 * (bool)(binary & 2)) * gamma;
+ if (next > 0)
+ *csd_add |= (1ull << bit);
+ else if (next < 0)
+ *csd_sub |= (1ull << bit);
+ if (next)
+ {
+ (*nonzero)++;
+ *topbit = bit;
+ }
+ a = (binary & 1);
+ binary >>= 1;
+ }
+ return((bool)binary);
+}
+
+/*------------------------------------------------------------------*/
+/* isEqualVal - return 1 if value is equal to specified constant */
+/*------------------------------------------------------------------*/
+int
+isEqualVal (value * val, int k)
+{
+ if (IS_SPEC (val->type))
+ {
+ if (SPEC_NOUN (val->type) == V_FLOAT || SPEC_NOUN (val->type) == V_FIXED16X16)
+ return floatFromVal (val) == k;
+ }
+ return ((TYPE_TARGET_LONGLONG) ullFromVal (val)) == k;
+}
+
+
+/*-----------------------------------------------------------------*/
+/* doubleFromFixed16x16 - convert a fixed16x16 to double */
+/*-----------------------------------------------------------------*/
+double
+doubleFromFixed16x16 (TYPE_TARGET_ULONG value)
+{
+#if 0
+ /* This version is incorrect negative values. */
+ double tmp = 0, exp = 2;
+
+ tmp = (value & 0xffff0000) >> 16;
+
+ while (value)
+ {
+ value &= 0xffff;
+ if (value & 0x8000)
+ tmp += 1 / exp;
+ exp *= 2;
+ value <<= 1;
+ }
+
+ return (tmp);
+#else
+ return ((double) (value * 1.0) / (double) (1UL << 16));
+#endif
+}
+
+TYPE_TARGET_ULONG
+fixed16x16FromDouble (double value)
+{
+#if 0
+ /* This version is incorrect negative values. */
+ unsigned int tmp = 0, pos = 16;
+ TYPE_TARGET_ULONG res;
+
+ tmp = floor (value);
+ res = tmp << 16;
+ value -= tmp;
+
+ tmp = 0;
+ while (pos--)
+ {
+ value *= 2;
+ if (value >= 1.0)
+ tmp |= (1 << pos);
+ value -= floor (value);
+ }
+
+ res |= tmp;
+
+ return (res);
+#else
+ return double2ul (value * (double) (1UL << 16));
+#endif
+}
+
+/*------------------------------------------------------------------*/
+/* valUnaryPM - does the unary +/- operation on a constant */
+/*------------------------------------------------------------------*/
+value *
+valUnaryPM (value * val)
+{
+ /* depending on type */
+ if (SPEC_NOUN (val->etype) == V_FLOAT)
+ SPEC_CVAL (val->etype).v_float = -1.0 * SPEC_CVAL (val->etype).v_float;
+ else if (SPEC_NOUN (val->etype) == V_FIXED16X16)
+ SPEC_CVAL (val->etype).v_fixed16x16 = (TYPE_TARGET_ULONG) - ((long) SPEC_CVAL (val->etype).v_fixed16x16);
+ else if (SPEC_LONGLONG (val->etype))
+ {
+ if (SPEC_USIGN (val->etype))
+ SPEC_CVAL (val->etype).v_ulonglong = 0 - SPEC_CVAL (val->etype).v_ulonglong;
+ else
+ SPEC_CVAL (val->etype).v_longlong = -SPEC_CVAL (val->etype).v_longlong;
+ }
+ else if (SPEC_LONG (val->etype))
+ {
+ if (SPEC_USIGN (val->etype))
+ SPEC_CVAL (val->etype).v_ulong = 0 - SPEC_CVAL (val->etype).v_ulong;
+ else
+ SPEC_CVAL (val->etype).v_long = -SPEC_CVAL (val->etype).v_long;
+ }
+ else
+ {
+ if (SPEC_USIGN (val->etype))
+ SPEC_CVAL (val->etype).v_uint = 0 - SPEC_CVAL (val->etype).v_uint;
+ else
+ SPEC_CVAL (val->etype).v_int = -SPEC_CVAL (val->etype).v_int;
+
+ if (SPEC_NOUN (val->etype) == V_CHAR)
+ {
+ /* promote to 'signed int', cheapestVal() might reduce it again */
+ SPEC_USIGN (val->etype) = 0;
+ SPEC_NOUN (val->etype) = V_INT;
+ }
+ return cheapestVal (val);
+ }
+ return val;
+}
+
+/*------------------------------------------------------------------*/
+/* valueComplement - complements a constant */
+/*------------------------------------------------------------------*/
+value *
+valComplement (value * val)
+{
+ /* depending on type */
+ if (SPEC_LONGLONG (val->etype))
+ {
+ if (SPEC_USIGN (val->etype))
+ SPEC_CVAL (val->etype).v_ulonglong = ~SPEC_CVAL (val->etype).v_ulonglong;
+ else
+ SPEC_CVAL (val->etype).v_longlong = ~SPEC_CVAL (val->etype).v_longlong;
+ }
+ else if (SPEC_LONG (val->etype))
+ {
+ if (SPEC_USIGN (val->etype))
+ SPEC_CVAL (val->etype).v_ulong = ~SPEC_CVAL (val->etype).v_ulong;
+ else
+ SPEC_CVAL (val->etype).v_long = ~SPEC_CVAL (val->etype).v_long;
+ }
+ else
+ {
+ if (SPEC_USIGN (val->etype))
+ SPEC_CVAL (val->etype).v_uint = ~SPEC_CVAL (val->etype).v_uint;
+ else
+ SPEC_CVAL (val->etype).v_int = ~SPEC_CVAL (val->etype).v_int;
+
+ if (SPEC_NOUN (val->etype) == V_CHAR)
+ {
+ /* promote to 'signed int', cheapestVal() might reduce it again */
+ SPEC_USIGN (val->etype) = 0;
+ SPEC_NOUN (val->etype) = V_INT;
+ }
+ return cheapestVal (val);
+ }
+ return val;
+}
+
+/*------------------------------------------------------------------*/
+/* valueNot - complements a constant */
+/*------------------------------------------------------------------*/
+value *
+valNot (value * val)
+{
+ /* depending on type */
+ if (SPEC_LONGLONG (val->etype))
+ {
+ if (SPEC_USIGN (val->etype))
+ SPEC_CVAL (val->etype).v_int = !SPEC_CVAL (val->etype).v_ulonglong;
+ else
+ SPEC_CVAL (val->etype).v_int = !SPEC_CVAL (val->etype).v_longlong;
+ }
+ else if (SPEC_LONG (val->etype))
+ {
+ if (SPEC_USIGN (val->etype))
+ SPEC_CVAL (val->etype).v_int = !SPEC_CVAL (val->etype).v_ulong;
+ else
+ SPEC_CVAL (val->etype).v_int = !SPEC_CVAL (val->etype).v_long;
+ }
+ else
+ {
+ if (SPEC_USIGN (val->etype))
+ SPEC_CVAL (val->etype).v_int = !SPEC_CVAL (val->etype).v_uint;
+ else
+ SPEC_CVAL (val->etype).v_int = !SPEC_CVAL (val->etype).v_int;
+
+ }
+ /* ANSI: result type is int, value is 0 or 1 */
+ /* sdcc will hold this in an 'unsigned char' */
+ SPEC_USIGN (val->etype) = 1;
+ SPEC_LONG (val->etype) = 0;
+ SPEC_LONGLONG (val->type) = 0;
+ SPEC_NOUN (val->etype) = V_CHAR;
+ return val;
+}
+
+/*------------------------------------------------------------------*/
+/* valMult - multiply constants */
+/*------------------------------------------------------------------*/
+value *
+valMult (value * lval, value * rval)
+{
+ value *val;
+
+ /* create a new value */
+ val = newValue ();
+ val->type = val->etype = computeType (lval->etype, rval->etype, RESULT_TYPE_INT, '*');
+ SPEC_SCLS (val->etype) = S_LITERAL; /* will remain literal */
+
+ if (IS_FLOAT (val->type))
+ SPEC_CVAL (val->type).v_float = floatFromVal (lval) * floatFromVal (rval);
+ else if (IS_FIXED16X16 (val->type))
+ SPEC_CVAL (val->type).v_fixed16x16 = fixed16x16FromDouble (floatFromVal (lval) * floatFromVal (rval));
+ /* signed and unsigned mul are the same, as long as the precision of the
+ result isn't bigger than the precision of the operands. */
+ else if (SPEC_LONGLONG (val->type))
+ SPEC_CVAL (val->type).v_ulonglong = (TYPE_TARGET_ULONGLONG) ullFromVal (lval) * (TYPE_TARGET_ULONGLONG) ullFromVal (rval);
+ else if (SPEC_LONG (val->type))
+ SPEC_CVAL (val->type).v_ulong = (TYPE_TARGET_ULONG) ulFromVal (lval) * (TYPE_TARGET_ULONG) ulFromVal (rval);
+ else if (SPEC_USIGN (val->type)) /* unsigned int */
+ {
+ TYPE_TARGET_ULONG ul = (TYPE_TARGET_UINT) ulFromVal (lval) * (TYPE_TARGET_UINT) ulFromVal (rval);
+
+ SPEC_CVAL (val->type).v_uint = (TYPE_TARGET_UINT) ul;
+ if (ul != (TYPE_TARGET_UINT) ul)
+ werror (W_INT_OVL);
+ }
+ else /* signed int */
+ {
+ TYPE_TARGET_LONG l = (TYPE_TARGET_INT) floatFromVal (lval) * (TYPE_TARGET_INT) floatFromVal (rval);
+
+ SPEC_CVAL (val->type).v_int = (TYPE_TARGET_INT) l;
+ if (l != (TYPE_TARGET_INT) l)
+ werror (W_INT_OVL);
+ }
+ return cheapestVal (val);
+}
+
+/*------------------------------------------------------------------*/
+/* valDiv - Divide constants */
+/*------------------------------------------------------------------*/
+value *
+valDiv (value * lval, value * rval)
+{
+ value *val;
+
+ if (isEqualVal (rval, 0) && !IS_FLOAT (computeType (lval->etype, rval->etype, RESULT_TYPE_INT, '/')))
+ {
+ werror (E_DIVIDE_BY_ZERO);
+ return rval;
+ }
+
+ /* create a new value */
+ val = newValue ();
+ val->type = val->etype = computeType (lval->etype, rval->etype, RESULT_TYPE_INT, '/');
+ SPEC_SCLS (val->etype) = S_LITERAL; /* will remain literal */
+
+ if (IS_FLOAT (val->type))
+ SPEC_CVAL (val->type).v_float = floatFromVal (lval) / floatFromVal (rval);
+ else if (IS_FIXED16X16 (val->type))
+ SPEC_CVAL (val->type).v_fixed16x16 = fixed16x16FromDouble (floatFromVal (lval) / floatFromVal (rval));
+ else if (SPEC_LONGLONG (val->type))
+ {
+ if (SPEC_USIGN (val->type))
+ SPEC_CVAL (val->type).v_ulonglong = (TYPE_TARGET_ULONGLONG) ullFromVal (lval) / (TYPE_TARGET_ULONGLONG) ullFromVal (rval);
+ else
+ SPEC_CVAL (val->type).v_longlong = (TYPE_TARGET_LONGLONG) ullFromVal (lval) / (TYPE_TARGET_LONGLONG) ullFromVal (rval);
+ }
+ else if (SPEC_LONG (val->type))
+ {
+ if (SPEC_USIGN (val->type))
+ SPEC_CVAL (val->type).v_ulong = (TYPE_TARGET_ULONG) ulFromVal (lval) / (TYPE_TARGET_ULONG) ulFromVal (rval);
+ else
+ SPEC_CVAL (val->type).v_long = (TYPE_TARGET_LONG) ulFromVal (lval) / (TYPE_TARGET_LONG) ulFromVal (rval);
+ }
+ else
+ {
+ if (SPEC_USIGN (val->type))
+ SPEC_CVAL (val->type).v_uint = (TYPE_TARGET_UINT) ulFromVal (lval) / (TYPE_TARGET_UINT) ulFromVal (rval);
+ else
+ SPEC_CVAL (val->type).v_int = (TYPE_TARGET_INT) ulFromVal (lval) / (TYPE_TARGET_INT) ulFromVal (rval);
+ }
+ return cheapestVal (val);
+}
+
+/*------------------------------------------------------------------*/
+/* valMod - Modulus constants */
+/*------------------------------------------------------------------*/
+value *
+valMod (value * lval, value * rval)
+{
+ value *val;
+
+ if (isEqualVal (rval, 0))
+ {
+ werror (E_DIVIDE_BY_ZERO);
+ return rval;
+ }
+
+ /* create a new value */
+ val = newValue ();
+ val->type = val->etype = computeType (lval->etype, rval->etype, RESULT_TYPE_INT, '%');
+ SPEC_SCLS (val->etype) = S_LITERAL; /* will remain literal */
+
+ if (SPEC_LONGLONG (val->type))
+ {
+ if (SPEC_USIGN (val->type))
+ SPEC_CVAL (val->type).v_ulonglong = (TYPE_TARGET_ULONGLONG) ullFromVal (lval) % (TYPE_TARGET_ULONGLONG) ullFromVal (rval);
+ else
+ SPEC_CVAL (val->type).v_longlong = (TYPE_TARGET_LONGLONG) ullFromVal (lval) % (TYPE_TARGET_LONGLONG) ullFromVal (rval);
+ }
+ else if (SPEC_LONG (val->type))
+ {
+ if (SPEC_USIGN (val->type))
+ SPEC_CVAL (val->type).v_ulong = (TYPE_TARGET_ULONG) ulFromVal (lval) % (TYPE_TARGET_ULONG) ulFromVal (rval);
+ else
+ SPEC_CVAL (val->type).v_long = (TYPE_TARGET_LONG) ulFromVal (lval) % (TYPE_TARGET_LONG) ulFromVal (rval);
+ }
+ else
+ {
+ if (SPEC_USIGN (val->type))
+ SPEC_CVAL (val->type).v_uint = (TYPE_TARGET_UINT) ulFromVal (lval) % (TYPE_TARGET_UINT) ulFromVal (rval);
+ else
+ SPEC_CVAL (val->type).v_int = (TYPE_TARGET_INT) ulFromVal (lval) % (TYPE_TARGET_INT) ulFromVal (rval);
+ }
+ return cheapestVal (val);
+}
+
+/*------------------------------------------------------------------*/
+/* valPlus - Addition constants */
+/*------------------------------------------------------------------*/
+value *
+valPlus (value * lval, value * rval)
+{
+ value *val;
+
+ /* create a new value */
+ val = newValue ();
+ val->type = computeType (lval->type, rval->type, RESULT_TYPE_INT, '+');
+ val->etype = getSpec (val->type);
+ SPEC_SCLS (val->etype) = S_LITERAL; /* will remain literal */
+
+ if (!IS_SPEC (val->type))
+ SPEC_CVAL (val->etype).v_ulong = (TYPE_TARGET_ULONG) ulFromVal (lval) + (TYPE_TARGET_ULONG) ulFromVal (rval);
+ else if (IS_FLOAT (val->type))
+ SPEC_CVAL (val->type).v_float = floatFromVal (lval) + floatFromVal (rval);
+ else if (IS_FIXED16X16 (val->type))
+ SPEC_CVAL (val->type).v_fixed16x16 = fixed16x16FromDouble (floatFromVal (lval) + floatFromVal (rval));
+ else if (SPEC_LONGLONG (val->type))
+ {
+ if (SPEC_USIGN (val->type))
+ SPEC_CVAL (val->type).v_ulonglong = (TYPE_TARGET_ULONGLONG) ullFromVal (lval) + (TYPE_TARGET_ULONGLONG) ullFromVal (rval);
+ else
+ SPEC_CVAL (val->type).v_longlong = (TYPE_TARGET_LONGLONG) ullFromVal (lval) + (TYPE_TARGET_LONGLONG) ullFromVal (rval);
+ }
+ else if (SPEC_LONG (val->type))
+ {
+ if (SPEC_USIGN (val->type))
+ SPEC_CVAL (val->type).v_ulong = (TYPE_TARGET_ULONG) ulFromVal (lval) + (TYPE_TARGET_ULONG) ulFromVal (rval);
+ else
+ SPEC_CVAL (val->type).v_long = (TYPE_TARGET_LONG) ulFromVal (lval) + (TYPE_TARGET_LONG) ulFromVal (rval);
+ }
+ else
+ {
+ if (SPEC_USIGN (val->type))
+ SPEC_CVAL (val->type).v_uint = (TYPE_TARGET_UINT) ulFromVal (lval) + (TYPE_TARGET_UINT) ulFromVal (rval);
+ else
+ SPEC_CVAL (val->type).v_int = (TYPE_TARGET_INT) ulFromVal (lval) + (TYPE_TARGET_INT) ulFromVal (rval);
+ }
+ return cheapestVal (val);
+}
+
+/*------------------------------------------------------------------*/
+/* valMinus - Addition constants */
+/*------------------------------------------------------------------*/
+value *
+valMinus (value * lval, value * rval)
+{
+ value *val;
+
+ /* create a new value */
+ val = newValue ();
+ val->type = computeType (lval->type, rval->type, RESULT_TYPE_INT, '-');
+ val->etype = getSpec (val->type);
+ SPEC_SCLS (val->etype) = S_LITERAL; /* will remain literal */
+
+ if (!IS_SPEC (val->type))
+ SPEC_CVAL (val->etype).v_ulong = (TYPE_TARGET_ULONG) ulFromVal (lval) - (TYPE_TARGET_ULONG) ulFromVal (rval);
+ else if (IS_FLOAT (val->type))
+ SPEC_CVAL (val->type).v_float = floatFromVal (lval) - floatFromVal (rval);
+ else if (IS_FIXED16X16 (val->type))
+ SPEC_CVAL (val->type).v_fixed16x16 = fixed16x16FromDouble (floatFromVal (lval) - floatFromVal (rval));
+ else if (SPEC_LONGLONG (val->type))
+ {
+ if (SPEC_USIGN (val->type))
+ SPEC_CVAL (val->type).v_ulonglong = (TYPE_TARGET_ULONGLONG) ullFromVal (lval) - (TYPE_TARGET_ULONGLONG) ullFromVal (rval);
+ else
+ SPEC_CVAL (val->type).v_longlong = (TYPE_TARGET_LONGLONG) ullFromVal (lval) - (TYPE_TARGET_LONGLONG) ullFromVal (rval);
+ }
+ else if (SPEC_LONG (val->type))
+ {
+ if (SPEC_USIGN (val->type))
+ SPEC_CVAL (val->type).v_ulong = (TYPE_TARGET_ULONG) ulFromVal (lval) - (TYPE_TARGET_ULONG) ulFromVal (rval);
+ else
+ SPEC_CVAL (val->type).v_long = (TYPE_TARGET_LONG) ulFromVal (lval) - (TYPE_TARGET_LONG) ulFromVal (rval);
+ }
+ else
+ {
+ if (SPEC_USIGN (val->type))
+ SPEC_CVAL (val->type).v_uint = (TYPE_TARGET_UINT) ulFromVal (lval) - (TYPE_TARGET_UINT) ulFromVal (rval);
+ else
+ SPEC_CVAL (val->type).v_int = (TYPE_TARGET_INT) ulFromVal (lval) - (TYPE_TARGET_INT) ulFromVal (rval);
+ }
+ return cheapestVal (val);
+}
+
+/*------------------------------------------------------------------*/
+/* valShift - Shift left or right */
+/*------------------------------------------------------------------*/
+value *
+valShift (value * lval, value * rval, int lr)
+{
+ value *val;
+
+ /* create a new value */
+ val = newValue ();
+ val->type = val->etype = computeType (lval->etype, NULL, RESULT_TYPE_INT, 'S');
+ SPEC_SCLS (val->etype) = S_LITERAL; /* will remain literal */
+
+ if (getSize (val->type) * 8 <= (TYPE_TARGET_ULONG) ulFromVal (rval) &&
+ /* left shift */
+ (lr ||
+ /* right shift and unsigned */
+ (!lr && SPEC_USIGN (rval->type))) &&
+ ((TYPE_TARGET_ULONG) ulFromVal (lval) != (TYPE_TARGET_ULONG) 0))
+ {
+ werror (W_SHIFT_CHANGED, (lr ? "left" : "right"));
+ }
+
+ if (SPEC_LONGLONG (val->type))
+ {
+ if (SPEC_USIGN (val->type))
+ {
+ SPEC_CVAL (val->type).v_ulonglong = lr ?
+ (TYPE_TARGET_ULONGLONG) ullFromVal (lval) << (TYPE_TARGET_ULONGLONG) ullFromVal (rval) :
+ (TYPE_TARGET_ULONGLONG) ullFromVal (lval) >> (TYPE_TARGET_ULONGLONG) ullFromVal (rval);
+ }
+ else
+ {
+ SPEC_CVAL (val->type).v_longlong = lr ?
+ (TYPE_TARGET_LONGLONG) ullFromVal (lval) << (TYPE_TARGET_ULONGLONG) ullFromVal (rval) :
+ (TYPE_TARGET_LONGLONG) ullFromVal (lval) >> (TYPE_TARGET_ULONGLONG) ullFromVal (rval);
+ }
+ }
+ else if (SPEC_LONG (val->type))
+ {
+ if (SPEC_USIGN (val->type))
+ {
+ SPEC_CVAL (val->type).v_ulong = lr ?
+ (TYPE_TARGET_ULONG) ulFromVal (lval) << (TYPE_TARGET_ULONG) ulFromVal (rval) :
+ (TYPE_TARGET_ULONG) ulFromVal (lval) >> (TYPE_TARGET_ULONG) ulFromVal (rval);
+ }
+ else
+ {
+ SPEC_CVAL (val->type).v_long = lr ?
+ (TYPE_TARGET_LONG) ulFromVal (lval) << (TYPE_TARGET_ULONG) ulFromVal (rval) :
+ (TYPE_TARGET_LONG) ulFromVal (lval) >> (TYPE_TARGET_ULONG) ulFromVal (rval);
+ }
+ }
+ else
+ {
+ if (SPEC_USIGN (val->type))
+ {
+ SPEC_CVAL (val->type).v_uint = lr ?
+ (TYPE_TARGET_UINT) ulFromVal (lval) << (TYPE_TARGET_ULONG) ulFromVal (rval) :
+ (TYPE_TARGET_UINT) ulFromVal (lval) >> (TYPE_TARGET_ULONG) ulFromVal (rval);
+ }
+ else
+ {
+ SPEC_CVAL (val->type).v_int = lr ?
+ (TYPE_TARGET_INT) ulFromVal (lval) << (TYPE_TARGET_ULONG) ulFromVal (rval) :
+ (TYPE_TARGET_INT) ulFromVal (lval) >> (TYPE_TARGET_ULONG) ulFromVal (rval);
+ }
+ }
+ return cheapestVal (val);
+}
+
+/*------------------------------------------------------------------*/
+/* valCompare - Compares two literal */
+/*------------------------------------------------------------------*/
+value *
+valCompare (value * lval, value * rval, int ctype)
+{
+ value *val;
+
+ /* create a new value */
+ val = newValue ();
+ val->type = val->etype = newCharLink ();
+ val->type->xclass = SPECIFIER;
+ SPEC_NOUN (val->type) = V_CHAR; /* type is char */
+ SPEC_USIGN (val->type) = 1;
+ SPEC_SCLS (val->type) = S_LITERAL; /* will remain literal */
+
+ switch (ctype)
+ {
+ /* FIXME: need to add long long support to inequalities */
+ case '<':
+ SPEC_CVAL (val->type).v_int = floatFromVal (lval) < floatFromVal (rval);
+ break;
+
+ case '>':
+ SPEC_CVAL (val->type).v_int = floatFromVal (lval) > floatFromVal (rval);
+ break;
+
+ case LE_OP:
+ SPEC_CVAL (val->type).v_int = floatFromVal (lval) <= floatFromVal (rval);
+ break;
+
+ case GE_OP:
+ SPEC_CVAL (val->type).v_int = floatFromVal (lval) >= floatFromVal (rval);
+ break;
+
+ case EQ_OP:
+ if (SPEC_NOUN (lval->type) == V_FLOAT || SPEC_NOUN (rval->type) == V_FLOAT)
+ {
+ SPEC_CVAL (val->type).v_int = floatFromVal (lval) == floatFromVal (rval);
+ }
+ else if (SPEC_NOUN (lval->type) == V_FIXED16X16 || SPEC_NOUN (rval->type) == V_FIXED16X16)
+ {
+ SPEC_CVAL (val->type).v_int = floatFromVal (lval) == floatFromVal (rval);
+ }
+ else
+ {
+ /* integrals: ignore signedness */
+ TYPE_TARGET_ULONGLONG l, r;
+
+ l = (TYPE_TARGET_ULONGLONG) ullFromVal (lval);
+ r = (TYPE_TARGET_ULONGLONG) ullFromVal (rval);
+ /* In order to correctly compare 'signed int' and 'unsigned int' it's
+ neccessary to strip them to 16 bit.
+ Literals are reduced to their cheapest type, therefore left and
+ right might have different types. It's neccessary to find a
+ common type: int (used for char too) or long */
+ if (!IS_LONGLONG (lval->etype) && !IS_LONGLONG (rval->etype))
+ {
+ r = (TYPE_TARGET_ULONG) r;
+ l = (TYPE_TARGET_ULONG) l;
+ }
+ if (!IS_LONG (lval->etype) && !IS_LONG (rval->etype))
+ {
+ r = (TYPE_TARGET_UINT) r;
+ l = (TYPE_TARGET_UINT) l;
+ }
+ SPEC_CVAL (val->type).v_int = l == r;
+ }
+ break;
+ case NE_OP:
+ if (SPEC_NOUN (lval->type) == V_FLOAT || SPEC_NOUN (rval->type) == V_FLOAT)
+ {
+ SPEC_CVAL (val->type).v_int = floatFromVal (lval) != floatFromVal (rval);
+ }
+ else if (SPEC_NOUN (lval->type) == V_FIXED16X16 || SPEC_NOUN (rval->type) == V_FIXED16X16)
+ {
+ SPEC_CVAL (val->type).v_int = floatFromVal (lval) != floatFromVal (rval);
+ }
+ else
+ {
+ /* integrals: ignore signedness */
+ TYPE_TARGET_ULONGLONG l, r;
+
+ l = (TYPE_TARGET_ULONGLONG) ullFromVal (lval);
+ r = (TYPE_TARGET_ULONGLONG) ullFromVal (rval);
+ /* In order to correctly compare 'signed int' and 'unsigned int' it's
+ neccessary to strip them to 16 bit.
+ Literals are reduced to their cheapest type, therefore left and
+ right might have different types. It's neccessary to find a
+ common type: int (used for char too) or long */
+ if (!IS_LONGLONG (lval->etype) && !IS_LONGLONG (rval->etype))
+ {
+ r = (TYPE_TARGET_ULONG) r;
+ l = (TYPE_TARGET_ULONG) l;
+ }
+ if (!IS_LONG (lval->etype) && !IS_LONG (rval->etype))
+ {
+ r = (TYPE_TARGET_UINT) r;
+ l = (TYPE_TARGET_UINT) l;
+ }
+ SPEC_CVAL (val->type).v_int = l != r;
+ }
+ break;
+
+ }
+
+ return val;
+}
+
+/*------------------------------------------------------------------*/
+/* valBitwise - Bitwise operation */
+/*------------------------------------------------------------------*/
+value *
+valBitwise (value * lval, value * rval, int op)
+{
+ value *val;
+
+ /* create a new value */
+ val = newValue ();
+ val->type = computeType (lval->etype, rval->etype, RESULT_TYPE_CHAR, op);
+ val->etype = getSpec (val->type);
+ SPEC_SCLS (val->etype) = S_LITERAL;
+
+ switch (op)
+ {
+ case '&':
+ if (SPEC_LONGLONG (val->type))
+ {
+ if (SPEC_USIGN (val->type))
+ SPEC_CVAL (val->type).v_ulonglong = (TYPE_TARGET_ULONGLONG) ullFromVal (lval) & (TYPE_TARGET_ULONGLONG) ullFromVal (rval);
+ else
+ SPEC_CVAL (val->type).v_longlong = (TYPE_TARGET_LONGLONG) ullFromVal (lval) & (TYPE_TARGET_LONGLONG) ullFromVal (rval);
+ }
+ else if (SPEC_LONG (val->type))
+ {
+ if (SPEC_USIGN (val->type))
+ SPEC_CVAL (val->type).v_ulong = (TYPE_TARGET_ULONG) ulFromVal (lval) & (TYPE_TARGET_ULONG) ulFromVal (rval);
+ else
+ SPEC_CVAL (val->type).v_long = (TYPE_TARGET_LONG) ulFromVal (lval) & (TYPE_TARGET_LONG) ulFromVal (rval);
+ }
+ else
+ {
+ if (SPEC_USIGN (val->type))
+ SPEC_CVAL (val->type).v_uint = (TYPE_TARGET_UINT) ulFromVal (lval) & (TYPE_TARGET_UINT) ulFromVal (rval);
+ else
+ SPEC_CVAL (val->type).v_int = (TYPE_TARGET_INT) ulFromVal (lval) & (TYPE_TARGET_INT) ulFromVal (rval);
+ }
+ break;
+
+ case '|':
+ if (SPEC_LONGLONG (val->type))
+ {
+ if (SPEC_USIGN (val->type))
+ SPEC_CVAL (val->type).v_ulonglong = (TYPE_TARGET_ULONGLONG) ullFromVal (lval) | (TYPE_TARGET_ULONGLONG) ullFromVal (rval);
+ else
+ SPEC_CVAL (val->type).v_longlong = (TYPE_TARGET_LONGLONG) ullFromVal (lval) | (TYPE_TARGET_LONGLONG) ullFromVal (rval);
+ }
+ else if (SPEC_LONG (val->type))
+ {
+ if (SPEC_USIGN (val->type))
+ SPEC_CVAL (val->type).v_ulong = (TYPE_TARGET_ULONG) ulFromVal (lval) | (TYPE_TARGET_ULONG) ulFromVal (rval);
+ else
+ SPEC_CVAL (val->type).v_long = (TYPE_TARGET_LONG) ulFromVal (lval) | (TYPE_TARGET_LONG) ulFromVal (rval);
+ }
+ else
+ {
+ if (SPEC_USIGN (val->type))
+ SPEC_CVAL (val->type).v_uint = (TYPE_TARGET_UINT) ulFromVal (lval) | (TYPE_TARGET_UINT) ulFromVal (rval);
+ else
+ SPEC_CVAL (val->type).v_int = (TYPE_TARGET_INT) ulFromVal (lval) | (TYPE_TARGET_INT) ulFromVal (rval);
+ }
+
+ break;
+
+ case '^':
+ if (SPEC_LONGLONG (val->type))
+ {
+ if (SPEC_USIGN (val->type))
+ SPEC_CVAL (val->type).v_ulonglong = (TYPE_TARGET_ULONGLONG) ullFromVal (lval) ^ (TYPE_TARGET_ULONGLONG) ullFromVal (rval);
+ else
+ SPEC_CVAL (val->type).v_longlong = (TYPE_TARGET_LONGLONG) ullFromVal (lval) ^ (TYPE_TARGET_LONGLONG) ullFromVal (rval);
+ }
+ else if (SPEC_LONG (val->type))
+ {
+ if (SPEC_USIGN (val->type))
+ SPEC_CVAL (val->type).v_ulong = (TYPE_TARGET_ULONG) ulFromVal (lval) ^ (TYPE_TARGET_ULONG) ulFromVal (rval);
+ else
+ SPEC_CVAL (val->type).v_long = (TYPE_TARGET_LONG) ulFromVal (lval) ^ (TYPE_TARGET_LONG) ulFromVal (rval);
+ }
+ else
+ {
+ if (SPEC_USIGN (val->type))
+ SPEC_CVAL (val->type).v_uint = (TYPE_TARGET_UINT) ulFromVal (lval) ^ (TYPE_TARGET_UINT) ulFromVal (rval);
+ else
+ SPEC_CVAL (val->type).v_int = (TYPE_TARGET_INT) ulFromVal (lval) ^ (TYPE_TARGET_INT) ulFromVal (rval);
+ }
+ break;
+ }
+
+ return cheapestVal (val);
+}
+
+/*------------------------------------------------------------------*/
+/* valAndOr - Generates code for and / or operation */
+/*------------------------------------------------------------------*/
+value *
+valLogicAndOr (value * lval, value * rval, int op)
+{
+ value *val;
+
+ /* create a new value */
+ val = newValue ();
+ val->type = val->etype = newCharLink ();
+ val->type->xclass = SPECIFIER;
+ SPEC_SCLS (val->type) = S_LITERAL; /* will remain literal */
+ SPEC_USIGN (val->type) = 1;
+
+ switch (op)
+ {
+ case AND_OP:
+ SPEC_CVAL (val->type).v_int = !isEqualVal (lval, 0) && !isEqualVal (rval, 0);
+ break;
+
+ case OR_OP:
+ SPEC_CVAL (val->type).v_int = !isEqualVal (lval, 0) || !isEqualVal (rval, 0);
+ break;
+ }
+
+ return val;
+}
+
+/*------------------------------------------------------------------*/
+/* valCastLiteral - casts a literal value to another type */
+/*------------------------------------------------------------------*/
+value *
+valCastLiteral (sym_link * dtype, double fval, TYPE_TARGET_ULONGLONG llval)
+{
+ value *val;
+ unsigned long l = double2ul (fval);
+
+ if (!dtype)
+ return NULL;
+
+ val = newValue ();
+ if (dtype)
+ val->etype = getSpec (val->type = copyLinkChain (dtype));
+ else
+ {
+ val->etype = val->type = newLink (SPECIFIER);
+ SPEC_NOUN (val->etype) = V_VOID;
+ }
+ SPEC_SCLS (val->etype) = S_LITERAL;
+
+ /* if it is not a specifier then we can assume that */
+ /* it will be an unsigned long */
+ if (!IS_SPEC (val->type))
+ {
+ SPEC_CVAL (val->etype).v_ulong = (TYPE_TARGET_ULONG) l;
+ return val;
+ }
+
+ switch (SPEC_NOUN (val->etype))
+ {
+ case V_FLOAT:
+ SPEC_CVAL (val->etype).v_float = fval;
+ break;
+
+ case V_FIXED16X16:
+ SPEC_CVAL (val->etype).v_fixed16x16 = fixed16x16FromDouble (fval);
+ break;
+
+ case V_BOOL:
+ case V_BIT:
+ case V_SBIT:
+ SPEC_CVAL (val->etype).v_uint = fval ? 1 : 0;
+ break;
+
+ case V_BITFIELD:
+ l &= (0xffffffffu >> (32 - SPEC_BLEN (val->etype)));
+ if (SPEC_USIGN (val->etype))
+ SPEC_CVAL (val->etype).v_uint = (TYPE_TARGET_UINT) l;
+ else
+ SPEC_CVAL (val->etype).v_int = (TYPE_TARGET_INT) l;
+ break;
+
+ case V_CHAR:
+ if (SPEC_USIGN (val->etype))
+ SPEC_CVAL (val->etype).v_uint = (TYPE_TARGET_UCHAR) l;
+ else
+ SPEC_CVAL (val->etype).v_int = (TYPE_TARGET_CHAR) l;
+ break;
+
+ default:
+ if (SPEC_LONGLONG (val->etype))
+ {
+ if (SPEC_USIGN (val->etype))
+ SPEC_CVAL (val->etype).v_ulonglong = (TYPE_TARGET_ULONGLONG) llval;
+ else
+ SPEC_CVAL (val->etype).v_longlong = (TYPE_TARGET_LONGLONG) llval;
+ }
+ else if (SPEC_LONG (val->etype))
+ {
+ if (SPEC_USIGN (val->etype))
+ SPEC_CVAL (val->etype).v_ulong = (TYPE_TARGET_ULONG) l;
+ else
+ SPEC_CVAL (val->etype).v_long = (TYPE_TARGET_LONG) l;
+ }
+ else
+ {
+ if (SPEC_USIGN (val->etype))
+ SPEC_CVAL (val->etype).v_uint = (TYPE_TARGET_UINT) l;
+ else
+ SPEC_CVAL (val->etype).v_int = (TYPE_TARGET_INT) l;
+ }
+ }
+
+ return val;
+}
+
+/*-------------------------------------------------------------------*/
+/* valRecastLitVal - changes type of a literal value to another type */
+/*-------------------------------------------------------------------*/
+value *
+valRecastLitVal (sym_link * dtype, value * val)
+{
+ sym_link * otype = val->type;
+ double fval;
+ TYPE_TARGET_ULONGLONG ull;
+
+ if (IS_SPEC (otype) && (SPEC_NOUN (otype) == V_FIXED16X16 || SPEC_NOUN (otype) == V_FLOAT))
+ {
+ fval = floatFromVal (val);
+ ull = (TYPE_TARGET_ULONGLONG)fval;
+ }
+ else
+ {
+ ull = (TYPE_TARGET_ULONGLONG) ullFromVal (val);
+ fval = (double)ull;
+ }
+
+ if (dtype)
+ val->etype = getSpec (val->type = copyLinkChain (dtype));
+ else
+ {
+ val->etype = val->type = newLink (SPECIFIER);
+ SPEC_NOUN (val->etype) = V_VOID;
+ }
+ SPEC_SCLS (val->etype) = S_LITERAL;
+
+ /* if it is not a specifier then we can assume that */
+ /* it will be an unsigned long */
+ if (!IS_SPEC (val->type))
+ {
+ SPEC_CVAL (val->etype).v_ulong = (TYPE_TARGET_ULONG) ull;
+ return val;
+ }
+
+ switch (SPEC_NOUN (val->etype))
+ {
+ case V_FLOAT:
+ SPEC_CVAL (val->etype).v_float = fval;
+ break;
+
+ case V_FIXED16X16:
+ SPEC_CVAL (val->etype).v_fixed16x16 = fixed16x16FromDouble (fval);
+ break;
+
+ case V_BOOL:
+ case V_BIT:
+ case V_SBIT:
+ SPEC_CVAL (val->etype).v_uint = fval ? 1 : 0;
+ break;
+
+ case V_BITFIELD:
+ ull &= (0xffffffffu >> (32 - SPEC_BLEN (val->etype)));
+ if (SPEC_USIGN (val->etype))
+ SPEC_CVAL (val->etype).v_uint = (TYPE_TARGET_UINT) ull;
+ else
+ SPEC_CVAL (val->etype).v_int = (TYPE_TARGET_INT) ull;
+ break;
+
+ case V_CHAR:
+ if (SPEC_USIGN (val->etype))
+ SPEC_CVAL (val->etype).v_uint = (TYPE_TARGET_UCHAR) ull;
+ else
+ SPEC_CVAL (val->etype).v_int = (TYPE_TARGET_CHAR) ull;
+ break;
+
+ default:
+ if (SPEC_LONGLONG (val->etype))
+ {
+ if (SPEC_USIGN (val->etype))
+ SPEC_CVAL (val->etype).v_ulonglong = (TYPE_TARGET_ULONGLONG) ull;
+ else
+ SPEC_CVAL (val->etype).v_longlong = (TYPE_TARGET_LONGLONG) ull;
+ }
+ else if (SPEC_LONG (val->etype))
+ {
+ if (SPEC_USIGN (val->etype))
+ SPEC_CVAL (val->etype).v_ulong = (TYPE_TARGET_ULONG) ull;
+ else
+ SPEC_CVAL (val->etype).v_long = (TYPE_TARGET_LONG) ull;
+ }
+ else
+ {
+ if (SPEC_USIGN (val->etype))
+ SPEC_CVAL (val->etype).v_uint = (TYPE_TARGET_UINT) ull;
+ else
+ SPEC_CVAL (val->etype).v_int = (TYPE_TARGET_INT) ull;
+ }
+ }
+
+ return val;
+}
+
+/*------------------------------------------------------------------*/
+/* getNelements - determines # of elements from init list */
+/*------------------------------------------------------------------*/
+int
+getNelements (sym_link * type, initList * ilist)
+{
+ int i, size;
+
+ if (!ilist)
+ return 0;
+
+ if (ilist->type == INIT_DEEP)
+ ilist = ilist->init.deep;
+
+ /* if type is a character array and there is only one
+ (string) initialiser then get the length of the string */
+ if (IS_ARRAY (type) && (IS_CHAR (type->next) || IS_INT (type->next) && IS_UNSIGNED (type->next)) && !ilist->next)
+ {
+ ast *iast = ilist->init.node;
+ value *v = (iast->type == EX_VALUE ? iast->opval.val : NULL);
+
+ if (v && IS_ARRAY (v->type) && (IS_CHAR (v->etype) || IS_INT (v->etype) && IS_UNSIGNED (v->etype) && IS_LONG (type->next) == IS_LONG (v->etype)))
+ /* yep, it's a string */
+ {
+ return DCL_ELEM (v->type);
+ }
+ }
+
+ size = 0;
+ i = 0;
+ while (ilist)
+ {
+ if (ilist->designation)
+ {
+ if (ilist->designation->type != DESIGNATOR_ARRAY)
+ {
+ // structure designator for array, boo.
+ werrorfl (ilist->filename, ilist->lineno, E_BAD_DESIGNATOR);
+ }
+ else
+ {
+ i = ilist->designation->designator.elemno;
+ }
+ }
+ if (size <= i)
+ {
+ size = i + 1; /* array size is one larger than array init element */
+ }
+ i++;
+ ilist = ilist->next;
+ }
+ return size;
+}
+
+/*-----------------------------------------------------------------*/
+/* valForArray - returns a value with name of array index */
+/*-----------------------------------------------------------------*/
+value *
+valForArray (ast * arrExpr)
+{
+ value *val, *lval = NULL;
+ int size = getSize (arrExpr->left->ftype->next);
+
+ /* if the right or left is an array
+ resolve it first */
+ if (IS_AST_OP (arrExpr->left))
+ {
+ if (arrExpr->left->opval.op == '[')
+ lval = valForArray (arrExpr->left);
+ else if (arrExpr->left->opval.op == '.')
+ lval = valForStructElem (arrExpr->left->left, arrExpr->left->right);
+ else if (arrExpr->left->opval.op == PTR_OP)
+ {
+ if (IS_ADDRESS_OF_OP (arrExpr->left->left))
+ lval = valForStructElem (arrExpr->left->left->left, arrExpr->left->right);
+ else if (IS_AST_VALUE (arrExpr->left->left) && IS_PTR (arrExpr->left->left->ftype))
+ lval = valForStructElem (arrExpr->left->left, arrExpr->left->right);
+ }
+ else
+ return NULL;
+ }
+ else if (!IS_AST_SYM_VALUE (arrExpr->left))
+ return NULL;
+
+ if (!IS_AST_LIT_VALUE (arrExpr->right))
+ return NULL;
+
+ val = newValue ();
+ val->type = newLink (DECLARATOR);
+ if (IS_AST_LIT_VALUE (arrExpr->left) && IS_PTR (arrExpr->left->ftype))
+ {
+ SNPRINTF (val->name, sizeof (val->name), "0x%X",
+ AST_ULONG_VALUE (arrExpr->left) + AST_ULONG_VALUE (arrExpr->right) * size);
+ memcpy (val->type, arrExpr->left->ftype, sizeof (sym_link));
+ }
+ else if (lval)
+ {
+ SNPRINTF (val->name, sizeof (val->name), "(%s + %d)", lval->name, AST_ULONG_VALUE (arrExpr->right) * size);
+ memcpy (val->type, lval->type, sizeof (sym_link));
+ }
+ else
+ {
+ SNPRINTF (val->name, sizeof (val->name), "(%s + %d)",
+ AST_SYMBOL (arrExpr->left)->rname, AST_ULONG_VALUE (arrExpr->right) * size);
+ if (SPEC_SCLS (arrExpr->left->etype) == S_CODE)
+ DCL_TYPE (val->type) = CPOINTER;
+ else if (SPEC_SCLS (arrExpr->left->etype) == S_XDATA)
+ DCL_TYPE (val->type) = FPOINTER;
+ else if (SPEC_SCLS (arrExpr->left->etype) == S_XSTACK)
+ DCL_TYPE (val->type) = PPOINTER;
+ else if (SPEC_SCLS (arrExpr->left->etype) == S_IDATA)
+ DCL_TYPE (val->type) = IPOINTER;
+ else if (SPEC_SCLS (arrExpr->left->etype) == S_EEPROM)
+ DCL_TYPE (val->type) = EEPPOINTER;
+ else
+ DCL_TYPE (val->type) = POINTER;
+ }
+
+ val->type->next = arrExpr->left->ftype->next;
+ val->etype = getSpec (val->type);
+ return val;
+}
+
+/*-----------------------------------------------------------------*/
+/* valForStructElem - returns value with name of struct element */
+/*-----------------------------------------------------------------*/
+value *
+valForStructElem (ast * structT, ast * elemT)
+{
+ value *val, *lval = NULL;
+ symbol *sym;
+ int idxoff = 0;
+ ast *sast = NULL;
+
+ /* left could be further derefed */
+ if (IS_AST_OP (structT))
+ {
+ if (structT->opval.op == '[')
+ lval = valForArray (structT);
+ else if (structT->opval.op == '+')
+ {
+ if (IS_AST_LIT_VALUE (structT->right) && !IS_AST_OP (structT->left))
+ {
+ idxoff = (int) (AST_ULONG_VALUE (structT->right) * getSize (structT->left->ftype->next));
+ sast = structT->left;
+ }
+ else if (IS_AST_LIT_VALUE (structT->left) && !IS_AST_OP (structT->right))
+ {
+ idxoff = (int) (AST_ULONG_VALUE (structT->left) * getSize (structT->right->ftype->next));
+ sast = structT->right;
+ }
+ else
+ return NULL;
+ }
+ else if (structT->opval.op == '-')
+ {
+ if (IS_AST_LIT_VALUE (structT->right) && !IS_AST_OP (structT->left))
+ {
+ idxoff = 0 - (int) (AST_ULONG_VALUE (structT->right) * getSize (structT->left->ftype->next));
+ sast = structT->left;
+ }
+ else
+ return NULL;
+ }
+ else if (structT->opval.op == '.')
+ lval = valForStructElem (structT->left, structT->right);
+ else if (structT->opval.op == PTR_OP)
+ {
+ if (IS_ADDRESS_OF_OP (structT->left))
+ lval = valForStructElem (structT->left->left, structT->right);
+ else if (IS_AST_VALUE (structT->left) && IS_PTR (structT->left->ftype))
+ lval = valForStructElem (structT->left, structT->right);
+ }
+ else
+ return NULL;
+ }
+
+ if (!IS_AST_SYM_VALUE (elemT))
+ return NULL;
+
+ if (!structT || !IS_STRUCT (structT->etype))
+ return NULL;
+
+ if ((sym = getStructElement (SPEC_STRUCT (structT->etype), AST_SYMBOL (elemT))) == NULL)
+ {
+ return NULL;
+ }
+
+ val = newValue ();
+ val->type = newLink (DECLARATOR);
+ if (IS_AST_LIT_VALUE (structT) && IS_PTR (structT->ftype))
+ {
+ SNPRINTF (val->name, sizeof (val->name), "0x%X", AST_ULONG_VALUE (structT) + (int) sym->offset);
+ memcpy (val->type, structT->ftype, sizeof (sym_link));
+ }
+ else if (lval)
+ {
+ SNPRINTF (val->name, sizeof (val->name), "(%s + %d)", lval->name, (int) sym->offset);
+ memcpy (val->type, lval->type, sizeof (sym_link));
+ }
+ else
+ {
+ if (sast)
+ SNPRINTF (val->name, sizeof (val->name), "(%s + (%d))", AST_SYMBOL (sast)->rname, ((int) sym->offset) + idxoff);
+ else
+ SNPRINTF (val->name, sizeof (val->name), "(%s + %d)", AST_SYMBOL (structT)->rname, (int) sym->offset);
+
+ if (SPEC_SCLS (structT->etype) == S_CODE)
+ DCL_TYPE (val->type) = CPOINTER;
+ else if (SPEC_SCLS (structT->etype) == S_XDATA)
+ DCL_TYPE (val->type) = FPOINTER;
+ else if (SPEC_SCLS (structT->etype) == S_XSTACK)
+ DCL_TYPE (val->type) = PPOINTER;
+ else if (SPEC_SCLS (structT->etype) == S_IDATA)
+ DCL_TYPE (val->type) = IPOINTER;
+ else if (SPEC_SCLS (structT->etype) == S_EEPROM)
+ DCL_TYPE (val->type) = EEPPOINTER;
+ else
+ DCL_TYPE (val->type) = POINTER;
+ }
+
+ val->type->next = sym->type;
+ val->etype = getSpec (val->type);
+ return val;
+}
+
+/*-----------------------------------------------------------------*/
+/* valForCastAggr - will return value for a cast of an aggregate */
+/* plus minus a constant */
+/*-----------------------------------------------------------------*/
+value *
+valForCastAggr (ast * aexpr, sym_link * type, ast * cnst, int op)
+{
+ value *val;
+
+ if (!IS_AST_SYM_VALUE (aexpr))
+ return NULL;
+ if (!IS_AST_LIT_VALUE (cnst))
+ return NULL;
+
+ val = newValue ();
+
+ SNPRINTF (val->name, sizeof (val->name), "(%s %c %d)",
+ AST_SYMBOL (aexpr)->rname, op, getSize (type->next) * AST_ULONG_VALUE (cnst));
+
+ val->type = type;
+ val->etype = getSpec (val->type);
+ return val;
+}
+
+/*-----------------------------------------------------------------*/
+/* valForCastArr - will return value for a cast of an aggregate */
+/* with no constant */
+/*-----------------------------------------------------------------*/
+value *
+valForCastArr (ast * aexpr, sym_link * type)
+{
+ value *val;
+
+ if (!IS_AST_SYM_VALUE (aexpr))
+ return NULL;
+
+ val = newValue ();
+
+ SNPRINTF (val->name, sizeof (val->name), "(%s)", AST_SYMBOL (aexpr)->rname);
+
+ val->type = type;
+ val->etype = getSpec (val->type);
+ return val;
+}