gbdk-releases/sdcc/src/SDCCval.c
2015-01-10 16:25:09 +01:00

1667 lines
41 KiB
C

/*----------------------------------------------------------------------
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 "newalloc.h"
int cNestLevel;
/*-----------------------------------------------------------------*/
/* newValue - allocates and returns a new value */
/*-----------------------------------------------------------------*/
value *
newValue ()
{
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->lineno = yylineno;
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)
{
initList *iLoop;
literalList *head, *last, *newL;
head = last = NULL;
if (!src || src->type != INIT_DEEP)
{
return FALSE;
}
iLoop = src->init.deep;
while (iLoop)
{
if (iLoop->type != INIT_NODE)
{
return FALSE;
}
if (!IS_AST_LIT_VALUE(decorateType(resolveSymbols(iLoop->init.node))))
{
return FALSE;
}
iLoop = iLoop->next;
}
// We've now established that the initializer list contains only literal values.
iLoop = src->init.deep;
while (iLoop)
{
double val = AST_LIT_VALUE(iLoop->init.node);
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->next;
}
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->next)
dest->next = copyIlist (src->next);
return dest;
}
/*------------------------------------------------------------------*/
/* list2int - converts the first element of the list to value */
/*------------------------------------------------------------------*/
double
list2int (initList * val)
{
initList *i = val;
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)
{
if (!val)
return NULL;
if (val->type == INIT_DEEP)
return list2val (val->init.deep);
return constExprValue (val->init.node, TRUE);
}
/*------------------------------------------------------------------*/
/* list2expr - returns the first expression in the initializer list */
/*------------------------------------------------------------------*/
ast *
list2expr (initList * ilist)
{
if (ilist->type == INIT_DEEP)
return list2expr (ilist->init.deep);
return ilist->init.node;
}
/*------------------------------------------------------------------*/
/* resolveIvalSym - resolve symbols in initial values */
/*------------------------------------------------------------------*/
void
resolveIvalSym (initList * ilist)
{
if (!ilist)
return;
if (ilist->type == INIT_NODE)
ilist->init.node = decorateType (resolveSymbols (ilist->init.node));
if (ilist->type == INIT_DEEP)
resolveIvalSym (ilist->init.deep);
resolveIvalSym (ilist->next);
}
/*-----------------------------------------------------------------*/
/* 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)
sprintf (val->name, "%s", sym->rname);
else
sprintf (val->name, "_%s", sym->name);
return val;
}
/*--------------------------------------------------------------------*/
/* cheapestVal - convert a val to the cheapest as possible value */
/*--------------------------------------------------------------------*/
value *cheapestVal (value *val) {
long sval=0;
unsigned long uval=0;
if (IS_FLOAT(val->type) || IS_CHAR(val->type))
return val;
if (SPEC_LONG(val->type)) {
if (SPEC_USIGN(val->type)) {
uval=SPEC_CVAL(val->type).v_ulong;
} else {
sval=SPEC_CVAL(val->type).v_long;
}
} else {
if (SPEC_USIGN(val->type)) {
uval=SPEC_CVAL(val->type).v_uint;
} else {
sval=SPEC_CVAL(val->type).v_int;
}
}
if (SPEC_USIGN(val->type)) {
if (uval<=0xffff) {
SPEC_LONG(val->type)=0;
SPEC_CVAL(val->type).v_uint = uval;
}
if (uval<=0xff) {
SPEC_NOUN(val->type)=V_CHAR;
}
} else { // not unsigned
if (sval<0) {
if (sval>=-32768) {
SPEC_LONG(val->type)=0;
SPEC_CVAL(val->type).v_int = sval & 0xffff;
}
if (sval>=-128) {
SPEC_NOUN(val->type)=V_CHAR;
SPEC_CVAL(val->type).v_int &= 0xff;
}
} else { // sval>=0
SPEC_USIGN(val->type)=1;
if (sval<=65535) {
SPEC_LONG(val->type)=0;
SPEC_CVAL(val->type).v_int = sval;
}
if (sval<=255) {
SPEC_NOUN(val->type)=V_CHAR;
}
}
}
return val;
}
/*-----------------------------------------------------------------*/
/* valueFromLit - creates a value from a literal */
/*-----------------------------------------------------------------*/
value *
valueFromLit (double lit)
{
char buffer[50];
if ((((long) lit) - lit) == 0)
{
sprintf (buffer, "%ld", (long) lit);
return constVal (buffer);
}
sprintf (buffer, "%f", lit);
return constFloatVal (buffer);
}
/*-----------------------------------------------------------------*/
/* constFloatVal - converts a FLOAT constant to value */
/*-----------------------------------------------------------------*/
value *
constFloatVal (char *s)
{
value *val = newValue ();
double sval;
if (sscanf (s, "%lf", &sval) != 1)
{
werror (E_INVALID_FLOAT_CONST, s);
return constVal ("0");
}
val->type = val->etype = newLink ();
val->type->class = SPECIFIER;
SPEC_NOUN (val->type) = V_FLOAT;
SPEC_SCLS (val->type) = S_LITERAL;
SPEC_CVAL (val->type).v_float = sval;
return val;
}
/*-----------------------------------------------------------------*/
/* constVal - converts an INTEGER constant into a cheapest value */
/*-----------------------------------------------------------------*/
value *constVal (char *s)
{
value *val;
short hex = 0, octal = 0;
char scanFmt[10];
int scI = 0;
double dval;
val = newValue (); /* alloc space for value */
val->type = val->etype = newLink (); /* create the spcifier */
val->type->class = SPECIFIER;
SPEC_SCLS (val->type) = S_LITERAL;
// let's start with an unsigned char
SPEC_NOUN (val->type) = V_CHAR;
SPEC_USIGN (val->type) = 1;
hex = ((strchr (s, 'x') || strchr (s, 'X')) ? 1 : 0);
/* set the octal flag */
if (!hex && *s == '0' && *(s + 1))
octal = 1;
/* create the scan string */
scanFmt[scI++] = '%';
scanFmt[scI++] = 'l';
if (octal)
scanFmt[scI++] = 'o';
else if (hex)
scanFmt[scI++] = 'x';
else
scanFmt[scI++] = 'f';
scanFmt[scI++] = '\0';
if (octal || hex) {
unsigned long sval;
sscanf (s, scanFmt, &sval);
dval=sval;
} else {
sscanf (s, scanFmt, &dval);
}
/* Setup the flags first */
/* set the _long flag if 'lL' is found */
if (strchr (s, 'l') || strchr (s, 'L')) {
SPEC_NOUN (val->type) = V_INT;
SPEC_LONG (val->type) = 1;
}
if (dval<0) { // "-28u" will still be signed and negative
SPEC_USIGN (val->type) = 0;
if (dval<-128) { // check if we have to promote to int
SPEC_NOUN (val->type) = V_INT;
}
if (dval<-32768) { // check if we have to promote to long int
SPEC_LONG (val->type) = 1;
}
} else { // >=0
if (dval>0xff) { // check if we have to promote to int
SPEC_NOUN (val->type) = V_INT;
}
if (dval>0xffff) { // check if we have to promote to long int
SPEC_LONG (val->type) = 1;
}
}
if (SPEC_LONG (val->type))
{
if (SPEC_USIGN (val->type))
{
SPEC_CVAL (val->type).v_ulong = dval;
}
else
{
SPEC_CVAL (val->type).v_long = dval;
}
}
else
{
if (SPEC_USIGN (val->type))
{
SPEC_CVAL (val->type).v_uint = dval;
}
else
{
SPEC_CVAL (val->type).v_int = dval;
}
}
return val;
}
/*! /fn char hexEscape(char **src)
/param src Pointer to 'x' from start of hex character value
*/
unsigned char hexEscape(char **src)
{
char *s ;
unsigned long value ;
(*src)++ ; /* Skip over the 'x' */
s = *src ; /* Save for error detection */
value = strtol (*src, src, 16);
if (s == *src) {
// no valid hex found
werror(E_INVALID_HEX);
} else {
if (value > 255) {
werror(W_ESC_SEQ_OOR_FOR_CHAR);
}
}
return (char) value;
}
/*------------------------------------------------------------------*/
/* octalEscape - process an octal constant of max three digits */
/* return the octal value, throw a warning for illegal octal */
/* adjust src to point at the last proccesed char */
/*------------------------------------------------------------------*/
unsigned char octalEscape (char **str) {
int digits;
unsigned value=0;
for (digits=0; digits<3; digits++) {
if (**str>='0' && **str<='7') {
value = value*8 + (**str-'0');
(*str)++;
} else {
break;
}
}
if (digits) {
if (value > 255 /* || (**str>='0' && **str<='7') */ ) {
werror (W_ESC_SEQ_OOR_FOR_CHAR);
}
}
return value;
}
/*!
/fn int copyStr (char *dest, char *src)
Copies a source string to a dest buffer interpreting escape sequences
and special characters
/param dest Buffer to receive the resultant string
/param src Buffer containing the source string with escape sequecnes
/return Number of characters in output string
*/
int
copyStr (char *dest, char *src)
{
char *OriginalDest = dest ;
while (*src)
{
if (*src == '\"')
src++;
else if (*src == '\\')
{
src++;
switch (*src)
{
case 'n':
*dest++ = '\n';
break;
case 't':
*dest++ = '\t';
break;
case 'v':
*dest++ = '\v';
break;
case 'b':
*dest++ = '\b';
break;
case 'r':
*dest++ = '\r';
break;
case 'f':
*dest++ = '\f';
break;
case 'a':
*dest++ = '\a';
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
*dest++ = octalEscape(&src);
src-- ;
break;
case 'x':
*dest++ = hexEscape(&src) ;
src-- ;
break ;
case '\\':
*dest++ = '\\';
break;
case '\?':
*dest++ = '\?';
break;
case '\'':
*dest++ = '\'';
break;
case '\"':
*dest++ = '\"';
break;
default:
*dest++ = *src;
}
src++;
}
else
*dest++ = *src++;
}
*dest++ = '\0';
return dest - OriginalDest ;
}
/*------------------------------------------------------------------*/
/* strVal - converts a string constant to a value */
/*------------------------------------------------------------------*/
value *
strVal (char *s)
{
value *val;
val = newValue (); /* get a new one */
/* get a declarator */
val->type = newLink ();
DCL_TYPE (val->type) = ARRAY;
val->type->next = val->etype = newLink ();
val->etype->class = SPECIFIER;
SPEC_NOUN (val->etype) = V_CHAR;
SPEC_SCLS (val->etype) = S_LITERAL;
SPEC_CVAL (val->etype).v_char = Safe_alloc (strlen (s) + 1);
DCL_ELEM (val->type) = copyStr (SPEC_CVAL (val->etype).v_char, s);
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);
strcpy (dest->name, src->name);
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 (char *s)
{
value *val;
// unsigned uValue ;
val = newValue ();
val->type = val->etype = newLink ();
val->type->class = SPECIFIER;
SPEC_NOUN (val->type) = V_CHAR;
SPEC_USIGN(val->type) = 1;
SPEC_SCLS (val->type) = S_LITERAL;
s++; /* get rid of quotation */
/* if \ then special processing */
if (*s == '\\')
{
s++; /* go beyond the backslash */
switch (*s)
{
case 'n':
SPEC_CVAL (val->type).v_int = '\n';
break;
case 't':
SPEC_CVAL (val->type).v_int = '\t';
break;
case 'v':
SPEC_CVAL (val->type).v_int = '\v';
break;
case 'b':
SPEC_CVAL (val->type).v_int = '\b';
break;
case 'r':
SPEC_CVAL (val->type).v_int = '\r';
break;
case 'f':
SPEC_CVAL (val->type).v_int = '\f';
break;
case 'a':
SPEC_CVAL (val->type).v_int = '\a';
break;
case '\\':
SPEC_CVAL (val->type).v_int = '\\';
break;
case '\?':
SPEC_CVAL (val->type).v_int = '\?';
break;
case '\'':
SPEC_CVAL (val->type).v_int = '\'';
break;
case '\"':
SPEC_CVAL (val->type).v_int = '\"';
break;
case '0' :
case '1' :
case '2' :
case '3' :
case '4' :
case '5' :
case '6' :
case '7' :
SPEC_CVAL (val->type).v_uint = octalEscape(&s);
break;
case 'x':
SPEC_CVAL (val->type).v_uint = hexEscape(&s) ;
break;
default:
SPEC_CVAL (val->type).v_uint = (unsigned char)*s;
break;
}
}
else /* not a backslash */
SPEC_CVAL (val->type).v_uint = (unsigned char)*s;
return val;
}
/*------------------------------------------------------------------*/
/* 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 unsinged integer 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 (double) SPEC_CVAL (val->etype).v_ulong;
if (SPEC_NOUN (val->etype) == V_FLOAT)
return (double) SPEC_CVAL (val->etype).v_float;
if (SPEC_LONG (val->etype))
{
if (SPEC_USIGN (val->etype))
return (double) SPEC_CVAL (val->etype).v_ulong;
else
return (double) SPEC_CVAL (val->etype).v_long;
}
if (SPEC_NOUN(val->etype)==V_INT) {
if (SPEC_USIGN (val->etype))
return (double) SPEC_CVAL (val->etype).v_uint;
else
return (double) SPEC_CVAL (val->etype).v_int;
} else { // SPEC_NOUN==V_CHAR
if (SPEC_USIGN (val->etype))
return (double) ((unsigned char)SPEC_CVAL (val->etype).v_uint);
else
return (double) ((signed char)SPEC_CVAL (val->etype).v_int);
}
}
/*------------------------------------------------------------------*/
/* 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_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) {
SPEC_CVAL (val->etype).v_uint &= 0xff;
}
}
}
// -(unsigned 3) now really is signed
SPEC_USIGN(val->etype)=0;
return val;
}
/*------------------------------------------------------------------*/
/* valueComplement - complements a constant */
/*------------------------------------------------------------------*/
value *
valComplement (value * val)
{
/* depending on type */
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) {
SPEC_CVAL (val->etype).v_uint &= 0xff;
}
}
return val;
}
/*------------------------------------------------------------------*/
/* valueNot - complements a constant */
/*------------------------------------------------------------------*/
value *
valNot (value * val)
{
/* depending on type */
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) {
SPEC_CVAL (val->etype).v_uint &= 0xff;
}
}
return val;
}
/*------------------------------------------------------------------*/
/* valMult - multiply constants */
/*------------------------------------------------------------------*/
value *
valMult (value * lval, value * rval)
{
value *val;
/* create a new value */
val = newValue ();
val->type = val->etype = newLink ();
val->type->class = SPECIFIER;
SPEC_NOUN (val->type) = (IS_FLOAT (lval->etype) ||
IS_FLOAT (rval->etype) ? V_FLOAT : V_INT);
SPEC_SCLS (val->type) = S_LITERAL; /* will remain literal */
SPEC_USIGN (val->type) = (SPEC_USIGN (lval->etype) & SPEC_USIGN (rval->etype));
SPEC_LONG (val->type) = 1;
if (IS_FLOAT (val->type))
SPEC_CVAL (val->type).v_float = floatFromVal (lval) * floatFromVal (rval);
else
{
if (SPEC_LONG (val->type))
{
if (SPEC_USIGN (val->type))
SPEC_CVAL (val->type).v_ulong = (unsigned long) floatFromVal (lval) *
(unsigned long) floatFromVal (rval);
else
SPEC_CVAL (val->type).v_long = (long) floatFromVal (lval) *
(long) floatFromVal (rval);
}
}
return cheapestVal(val);
}
/*------------------------------------------------------------------*/
/* valDiv - Divide constants */
/*------------------------------------------------------------------*/
value *
valDiv (value * lval, value * rval)
{
value *val;
if (floatFromVal (rval) == 0)
{
werror (E_DIVIDE_BY_ZERO);
return rval;
}
/* create a new value */
val = newValue ();
val->type = val->etype = newLink();
val->type->class = SPECIFIER;
SPEC_NOUN (val->type) = (IS_FLOAT (lval->etype) ||
IS_FLOAT (rval->etype) ? V_FLOAT : V_INT);
SPEC_SCLS (val->etype) = S_LITERAL;
SPEC_USIGN (val->type) = (SPEC_USIGN (lval->etype) & SPEC_USIGN (rval->etype));
SPEC_LONG (val->type) = (SPEC_LONG (lval->etype) | SPEC_LONG (rval->etype));
if (IS_FLOAT (val->type))
SPEC_CVAL (val->type).v_float = floatFromVal (lval) / floatFromVal (rval);
else
{
if (SPEC_LONG (val->type))
{
if (SPEC_USIGN (val->type))
SPEC_CVAL (val->type).v_ulong =
(unsigned long) floatFromVal (lval) /
(unsigned long) floatFromVal (rval);
else
SPEC_CVAL (val->type).v_long = (long) floatFromVal (lval) /
(long) floatFromVal (rval);
}
else
{
if (SPEC_USIGN (val->type)) {
SPEC_CVAL (val->type).v_uint = (unsigned) floatFromVal (lval) /
(unsigned) floatFromVal (rval);
} else {
SPEC_CVAL (val->type).v_int = (int) floatFromVal (lval) /
(int) floatFromVal (rval);
}
}
}
return cheapestVal(val);
}
/*------------------------------------------------------------------*/
/* valMod - Modulus constants */
/*------------------------------------------------------------------*/
value *
valMod (value * lval, value * rval)
{
value *val;
/* create a new value */
val = newValue ();
val->type = val->etype = newLink ();
val->type->class = SPECIFIER;
SPEC_NOUN (val->type) = V_INT; /* type is int */
SPEC_SCLS (val->type) = S_LITERAL; /* will remain literal */
SPEC_USIGN (val->type) = (SPEC_USIGN (lval->etype) & SPEC_USIGN (rval->etype));
SPEC_LONG (val->type) = (SPEC_LONG (lval->etype) | SPEC_LONG (rval->etype));
if (SPEC_LONG (val->type))
{
if (SPEC_USIGN (val->type))
SPEC_CVAL (val->type).v_ulong = (unsigned long) floatFromVal (lval) %
(unsigned long) floatFromVal (rval);
else
SPEC_CVAL (val->type).v_long = (unsigned long) floatFromVal (lval) %
(unsigned long) floatFromVal (rval);
}
else
{
if (SPEC_USIGN (val->type)) {
SPEC_CVAL (val->type).v_uint = (unsigned) floatFromVal (lval) %
(unsigned) floatFromVal (rval);
} else {
SPEC_CVAL (val->type).v_int = (unsigned) floatFromVal (lval) %
(unsigned) floatFromVal (rval);
}
}
return cheapestVal(val);
}
/*------------------------------------------------------------------*/
/* valPlus - Addition constants */
/*------------------------------------------------------------------*/
value *
valPlus (value * lval, value * rval)
{
value *val;
/* create a new value */
val = newValue ();
val->type = val->etype = newLink ();
val->type->class = SPECIFIER;
SPEC_NOUN (val->type) = (IS_FLOAT (lval->etype) ||
IS_FLOAT (rval->etype) ? V_FLOAT : V_INT);
SPEC_SCLS (val->type) = S_LITERAL; /* will remain literal */
SPEC_USIGN (val->type) =
SPEC_USIGN (lval->etype) &&
SPEC_USIGN (rval->etype) &&
(floatFromVal(lval)+floatFromVal(rval))>=0;
SPEC_LONG (val->type) = 1;
if (IS_FLOAT (val->type))
SPEC_CVAL (val->type).v_float = floatFromVal (lval) + floatFromVal (rval);
else
{
if (SPEC_LONG (val->type))
{
if (SPEC_USIGN (val->type))
SPEC_CVAL (val->type).v_ulong = (unsigned long) floatFromVal (lval) +
(unsigned long) floatFromVal (rval);
else
SPEC_CVAL (val->type).v_long = (long) floatFromVal (lval) +
(long) floatFromVal (rval);
}
}
return cheapestVal(val);
}
/*------------------------------------------------------------------*/
/* valMinus - Addition constants */
/*------------------------------------------------------------------*/
value *
valMinus (value * lval, value * rval)
{
value *val;
/* create a new value */
val = newValue ();
val->type = val->etype = newLink ();
val->type->class = SPECIFIER;
SPEC_NOUN (val->type) = (IS_FLOAT (lval->etype) ||
IS_FLOAT (rval->etype) ? V_FLOAT : V_INT);
SPEC_SCLS (val->type) = S_LITERAL; /* will remain literal */
SPEC_USIGN (val->type) =
SPEC_USIGN (lval->etype) &&
SPEC_USIGN (rval->etype) &&
(floatFromVal(lval)-floatFromVal(rval))>=0;
SPEC_LONG (val->type) = (SPEC_LONG (lval->etype) | SPEC_LONG (rval->etype));
if (IS_FLOAT (val->type))
SPEC_CVAL (val->type).v_float = floatFromVal (lval) - floatFromVal (rval);
else
{
if (SPEC_LONG (val->type))
{
if (SPEC_USIGN (val->type)) {
SPEC_CVAL (val->type).v_ulong =
(unsigned long) floatFromVal (lval) -
(unsigned long) floatFromVal (rval);
} else {
SPEC_CVAL (val->type).v_long = (long) floatFromVal (lval) -
(long) floatFromVal (rval);
}
}
else
{
if (SPEC_USIGN (val->type)) {
SPEC_CVAL (val->type).v_uint = (unsigned) floatFromVal (lval) -
(unsigned) floatFromVal (rval);
} else {
SPEC_CVAL (val->type).v_int = (int) floatFromVal (lval) -
(int) floatFromVal (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 = newIntLink ();
SPEC_SCLS (val->type) = S_LITERAL; /* will remain literal */
SPEC_USIGN (val->type) = (SPEC_USIGN (lval->etype) & SPEC_USIGN (rval->etype));
SPEC_LONG (val->type) = 1;
if (SPEC_LONG (val->type))
{
if (SPEC_USIGN (val->type))
SPEC_CVAL (val->type).v_ulong = lr ?
(unsigned long) floatFromVal (lval) << (unsigned long) floatFromVal (rval) : \
(unsigned long) floatFromVal (lval) >> (unsigned long) floatFromVal (rval);
else
SPEC_CVAL (val->type).v_long = lr ?
(long) floatFromVal (lval) << (long) floatFromVal (rval) : \
(long) floatFromVal (lval) >> (long) floatFromVal (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->class = 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)
{
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:
SPEC_CVAL (val->type).v_int = floatFromVal (lval) == floatFromVal (rval);
break;
case NE_OP:
SPEC_CVAL (val->type).v_int = floatFromVal (lval) != floatFromVal (rval);
break;
}
return val;
}
/*------------------------------------------------------------------*/
/* valBitwise - Bitwise operation */
/*------------------------------------------------------------------*/
value *
valBitwise (value * lval, value * rval, int op)
{
value *val;
/* create a new value */
val = newValue ();
val->type = copyLinkChain (lval->type);
val->etype = getSpec (val->type);
switch (op)
{
case '&':
if (SPEC_LONG (val->type))
{
if (SPEC_USIGN (val->type))
SPEC_CVAL (val->type).v_ulong = (unsigned long) floatFromVal (lval) &
(unsigned long) floatFromVal (rval);
else
SPEC_CVAL (val->type).v_long = (long) floatFromVal (lval) &
(long) floatFromVal (rval);
}
else
{
if (SPEC_USIGN (val->type))
SPEC_CVAL (val->type).v_uint = (unsigned) floatFromVal (lval) &
(unsigned) floatFromVal (rval);
else
SPEC_CVAL (val->type).v_int = (int) floatFromVal (lval) & (int) floatFromVal (rval);
}
break;
case '|':
if (SPEC_LONG (val->type))
{
if (SPEC_USIGN (val->type))
SPEC_CVAL (val->type).v_ulong = (unsigned long) floatFromVal (lval) |
(unsigned long) floatFromVal (rval);
else
SPEC_CVAL (val->type).v_long = (long) floatFromVal (lval) |
(long) floatFromVal (rval);
}
else
{
if (SPEC_USIGN (val->type))
SPEC_CVAL (val->type).v_uint = (unsigned) floatFromVal (lval) |
(unsigned) floatFromVal (rval);
else
SPEC_CVAL (val->type).v_int =
(int) floatFromVal (lval) | (int) floatFromVal (rval);
}
break;
case '^':
if (SPEC_LONG (val->type))
{
if (SPEC_USIGN (val->type))
SPEC_CVAL (val->type).v_ulong = (unsigned long) floatFromVal (lval) ^
(unsigned long) floatFromVal (rval);
else
SPEC_CVAL (val->type).v_long = (long) floatFromVal (lval) ^
(long) floatFromVal (rval);
}
else
{
if (SPEC_USIGN (val->type))
SPEC_CVAL (val->type).v_uint = (unsigned) floatFromVal (lval) ^
(unsigned) floatFromVal (rval);
else
SPEC_CVAL (val->type).v_int =
(int) floatFromVal (lval) ^ (int) floatFromVal (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->class = SPECIFIER;
SPEC_SCLS (val->type) = S_LITERAL; /* will remain literal */
SPEC_USIGN (val->type) = 0;
switch (op)
{
case AND_OP:
SPEC_CVAL (val->type).v_int = floatFromVal (lval) && floatFromVal (rval);
break;
case OR_OP:
SPEC_CVAL (val->type).v_int = floatFromVal (lval) || floatFromVal (rval);
break;
}
return val;
}
/*------------------------------------------------------------------*/
/* valCastLiteral - casts a literal value to another type */
/*------------------------------------------------------------------*/
value *
valCastLiteral (sym_link * dtype, double fval)
{
value *val;
if (!dtype)
return NULL;
val = newValue ();
val->etype = getSpec (val->type = copyLinkChain (dtype));
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 = (unsigned long) fval;
return val;
}
if (SPEC_NOUN (val->etype) == V_FLOAT)
SPEC_CVAL (val->etype).v_float = fval;
else
{
if (SPEC_LONG (val->etype))
{
if (SPEC_USIGN (val->etype))
SPEC_CVAL (val->etype).v_ulong = (unsigned long) fval;
else
SPEC_CVAL (val->etype).v_long = (long) fval;
}
else
{
if (SPEC_USIGN (val->etype))
SPEC_CVAL (val->etype).v_uint = (unsigned short)fval;
else
SPEC_CVAL (val->etype).v_int = (short)fval;
if (SPEC_NOUN (val->etype)==V_CHAR) {
SPEC_CVAL (val->etype).v_uint &= 0xff;
}
}
}
return val;
}
/*------------------------------------------------------------------*/
/* getNelements - determines # of elements from init list */
/*------------------------------------------------------------------*/
int
getNelements (sym_link * type, initList * ilist)
{
sym_link *etype = getSpec (type);
int i;
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 (etype) && !ilist->next)
{
ast *iast = ilist->init.node;
value *v = (iast->type == EX_VALUE ? iast->opval.val : NULL);
if (!v)
{
werror (W_INIT_WRONG);
return 0;
}
if (IS_ARRAY (v->type) && IS_CHAR (v->etype))
// yep, it's a string
{
return DCL_ELEM (v->type);
}
}
i = 0;
while (ilist)
{
i++;
ilist = ilist->next;
}
return i;
}
/*-----------------------------------------------------------------*/
/* valForArray - returns a value with name of array index */
/*-----------------------------------------------------------------*/
value *
valForArray (ast * arrExpr)
{
value *val, *lval = NULL;
char buffer[128];
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 &&
IS_ADDRESS_OF_OP (arrExpr->left->left))
lval = valForStructElem (arrExpr->left->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 ();
if (!lval)
sprintf (buffer, "%s", AST_SYMBOL (arrExpr->left)->rname);
else
sprintf (buffer, "%s", lval->name);
sprintf (val->name, "(%s + %d)", buffer,
(int) AST_LIT_VALUE (arrExpr->right) * size);
val->type = newLink ();
if (SPEC_SCLS (arrExpr->left->etype) == S_CODE)
{
DCL_TYPE (val->type) = CPOINTER;
DCL_PTR_CONST (val->type) = port->mem.code_ro;
}
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;
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;
char buffer[128];
symbol *sym;
/* left could be furthur derefed */
if (IS_AST_OP (structT))
{
if (structT->opval.op == '[')
lval = valForArray (structT);
else if (structT->opval.op == '.')
lval = valForStructElem (structT->left, structT->right);
else if (structT->opval.op == PTR_OP &&
IS_ADDRESS_OF_OP (structT->left))
lval = valForStructElem (structT->left->left,
structT->right);
else
return NULL;
}
if (!IS_AST_SYM_VALUE (elemT))
return NULL;
if (!IS_STRUCT (structT->etype))
return NULL;
if ((sym = getStructElement (SPEC_STRUCT (structT->etype),
AST_SYMBOL (elemT))) == NULL)
{
return NULL;
}
val = newValue ();
if (!lval)
sprintf (buffer, "%s", AST_SYMBOL (structT)->rname);
else
sprintf (buffer, "%s", lval->name);
sprintf (val->name, "(%s + %d)", buffer,
(int) sym->offset);
val->type = newLink ();
if (SPEC_SCLS (structT->etype) == S_CODE)
{
DCL_TYPE (val->type) = CPOINTER;
DCL_PTR_CONST (val->type) = port->mem.code_ro;
}
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 ();
sprintf (val->name, "(%s %c %d)",
AST_SYMBOL (aexpr)->rname, op,
getSize (type->next) * (int) AST_LIT_VALUE (cnst));
val->type = type;
val->etype = getSpec (val->type);
return val;
}
/*-----------------------------------------------------------------*/
/* valForCastAggr - 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 ();
sprintf (val->name, "(%s)",
AST_SYMBOL (aexpr)->rname);
val->type = type;
val->etype = getSpec (val->type);
return val;
}