diff options
Diffstat (limited to 'src/SDCCval.c')
| -rw-r--r-- | src/SDCCval.c | 3295 |
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; +} |
