summaryrefslogtreecommitdiff
path: root/src/SDCCsymt.c
diff options
context:
space:
mode:
authorXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
committerXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
commit268a53de823a6750d6256ee1fb1e7707b4b45740 (patch)
tree42c1799a9a82b2f7d9790ee9fe181d72a7274751 /src/SDCCsymt.c
downloadsdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'src/SDCCsymt.c')
-rw-r--r--src/SDCCsymt.c4587
1 files changed, 4587 insertions, 0 deletions
diff --git a/src/SDCCsymt.c b/src/SDCCsymt.c
new file mode 100644
index 0000000..ec45d1a
--- /dev/null
+++ b/src/SDCCsymt.c
@@ -0,0 +1,4587 @@
+/*-------------------------------------------------------------------------
+ SDCCsymt.c - Code file for Symbols table related structures and MACRO's.
+ 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 "newalloc.h"
+#include "dbuf_string.h"
+
+#include "SDCCsymt.h"
+
+value *aggregateToPointer (value * val);
+void printTypeChainRaw (sym_link * start, FILE * of);
+
+void
+printFromToType (sym_link * from, sym_link * to)
+{
+ struct dbuf_s dbuf;
+ dbuf_init (&dbuf, 1024);
+ dbuf_append_str (&dbuf, "from type '");
+ dbuf_printTypeChain (from, &dbuf);
+ dbuf_append_str (&dbuf, "'\n to type '");
+ dbuf_printTypeChain (to, &dbuf);
+ dbuf_append_str (&dbuf, "'\n");
+ dbuf_write_and_destroy (&dbuf, stderr);
+}
+
+/* noun strings */
+char *
+nounName (sym_link * sl)
+{
+ switch (SPEC_NOUN (sl))
+ {
+ case V_INT:
+ {
+ if (SPEC_LONGLONG (sl))
+ return "long long";
+ if (SPEC_LONG (sl))
+ return "long";
+ if (SPEC_SHORT (sl))
+ return "short";
+ return "int";
+ }
+ case V_FLOAT:
+ return "float";
+ case V_FIXED16X16:
+ return "fixed16x16";
+ case V_BOOL:
+ return "_Bool";
+ case V_CHAR:
+ return "char";
+ case V_VOID:
+ return "void";
+ case V_STRUCT:
+ return "struct";
+ case V_LABEL:
+ return "label";
+ case V_BITFIELD:
+ return "bitfield";
+ case V_BBITFIELD:
+ return "_Boolbitfield";
+ case V_BIT:
+ return "bit";
+ case V_SBIT:
+ return "sbit";
+ case V_DOUBLE:
+ return "double";
+ }
+ return "unknown";
+}
+
+bucket *SymbolTab[256]; /* the symbol table */
+bucket *StructTab[256]; /* the structure table */
+bucket *TypedefTab[256]; /* the typedef table */
+bucket *LabelTab[256]; /* the Label table */
+bucket *enumTab[256]; /* enumerated table */
+bucket *AddrspaceTab[256]; /* the named address space table */
+
+/*------------------------------------------------------------------*/
+/* initSymt () - initialises symbol table related stuff */
+/*------------------------------------------------------------------*/
+void
+initSymt (void)
+{
+ int i = 0;
+
+ for (i = 0; i < 256; i++)
+ SymbolTab[i] = StructTab[i] = (void *) NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* newBucket - allocates & returns a new bucket */
+/*-----------------------------------------------------------------*/
+bucket *
+newBucket (void)
+{
+ bucket *bp;
+
+ bp = Safe_alloc (sizeof (bucket));
+
+ return bp;
+}
+
+/*-----------------------------------------------------------------*/
+/* hashKey - computes the hashkey given a symbol name */
+/*-----------------------------------------------------------------*/
+int
+hashKey (const char *s)
+{
+ unsigned long key = 0;
+
+ while (*s)
+ key += *s++;
+ return key % 256;
+}
+
+/*-----------------------------------------------------------------*/
+/* addSym - adds a symbol to the hash Table */
+/*-----------------------------------------------------------------*/
+void
+addSym (bucket ** stab, void *sym, char *sname, long level, int block, int checkType)
+{
+ int i; /* index into the hash Table */
+ bucket *bp; /* temp bucket * */
+
+ if (checkType)
+ {
+ symbol *csym = (symbol *) sym;
+
+ if (getenv ("DEBUG_SANITY"))
+ {
+ fprintf (stderr, "addSym: %s ", sname);
+ }
+ /* make sure the type is complete and sane */
+ checkTypeSanity (csym->etype, csym->name);
+ }
+
+ /* prevent overflow of the (r)name buffers */
+ if (strlen (sname) > SDCC_SYMNAME_MAX)
+ {
+ werror (W_SYMBOL_NAME_TOO_LONG, SDCC_SYMNAME_MAX);
+ sname[SDCC_SYMNAME_MAX] = '\0';
+ }
+
+ /* the symbols are always added at the head of the list */
+ i = hashKey (sname);
+ /* get a free entry */
+ bp = Safe_alloc (sizeof (bucket));
+
+ bp->sym = sym; /* update the symbol pointer */
+ bp->level = level; /* update the nest level */
+ bp->block = block;
+ strncpyz (bp->name, sname, sizeof (bp->name)); /* copy the name into place */
+
+ /* if this is the first entry */
+ if (stab[i] == NULL)
+ {
+ bp->prev = bp->next = (void *) NULL; /* point to nothing */
+ stab[i] = bp;
+ }
+ /* not first entry then add @ head of list */
+ else
+ {
+ bp->prev = NULL;
+ stab[i]->prev = bp;
+ bp->next = stab[i];
+ stab[i] = bp;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* deleteSym - deletes a symbol from the hash Table entry */
+/*-----------------------------------------------------------------*/
+void
+deleteSym (bucket ** stab, void *sym, const char *sname)
+{
+ int i = 0;
+ bucket *bp;
+
+ i = hashKey (sname);
+
+ bp = stab[i];
+ /* find the symbol */
+ while (bp)
+ {
+ if (bp->sym == sym) /* found it then break out */
+ break; /* of the loop */
+ bp = bp->next;
+ }
+
+ if (!bp) /* did not find it */
+ return;
+
+ /* if this is the first one in the chain */
+ if (!bp->prev)
+ {
+ stab[i] = bp->next;
+ if (stab[i]) /* if chain ! empty */
+ stab[i]->prev = (void *) NULL;
+ }
+ /* middle || end of chain */
+ else
+ {
+ if (bp->next) /* if not end of chain */
+ bp->next->prev = bp->prev;
+
+ bp->prev->next = bp->next;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* findSym - finds a symbol in a table */
+/*-----------------------------------------------------------------*/
+void *
+findSym (bucket ** stab, void *sym, const char *sname)
+{
+ bucket *bp;
+
+ bp = stab[hashKey (sname)];
+ while (bp)
+ {
+ if (bp->sym == sym || strcmp (bp->name, sname) == 0)
+ break;
+ bp = bp->next;
+ }
+
+ return (bp ? bp->sym : (void *) NULL);
+}
+
+/*-----------------------------------------------------------------*/
+/* findSymWithLevel - finds a symbol with a name & level */
+/*-----------------------------------------------------------------*/
+void *
+findSymWithLevel (bucket ** stab, symbol * sym)
+{
+ bucket *bp;
+
+ if (!sym)
+ return sym;
+
+ bp = stab[hashKey (sym->name)];
+
+ /**
+ ** do the search from the head of the list since the
+ ** elements are added at the head it is ensured that
+ ** we will find the deeper definitions before we find
+ ** the global ones. we need to check for symbols with
+ ** level <= to the level given, if levels match then block
+ ** numbers need to match as well
+ **/
+ while (bp)
+ {
+ if (strcmp (bp->name, sym->name) == 0 && bp->level <= sym->level)
+ {
+ /* if this is parameter then nothing else need to be checked */
+ if (((symbol *) (bp->sym))->_isparm)
+ return (bp->sym);
+ /* if levels match then block numbers should also match */
+ if (bp->level && bp->level == sym->level && bp->block == sym->block
+ && ((symbol *)(bp->sym))->seqPoint <= sym->seqPoint)
+ return (bp->sym);
+ /* if levels don't match then we are okay if the symbol is in scope */
+ if (bp->level && bp->level != sym->level && bp->block <= sym->block
+ && ((symbol *) (bp->sym))->isinscope
+ && (stab == LabelTab || ((symbol *)(bp->sym))->seqPoint <= sym->seqPoint))
+ return (bp->sym);
+ /* if this is a global variable then we are ok too */
+ if (bp->level == 0)
+ return (bp->sym);
+ }
+
+ bp = bp->next;
+ }
+
+ return (void *) NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* findSymWithBlock - finds a symbol with name in a block */
+/*-----------------------------------------------------------------*/
+void *
+findSymWithBlock (bucket ** stab, symbol * sym, int block, long level)
+{
+ bucket *bp;
+
+ if (!sym)
+ return sym;
+
+ bp = stab[hashKey (sym->name)];
+ while (bp)
+ {
+ if (strcmp (bp->name, sym->name) == 0 && (bp->block == block || (bp->block < block && bp->level < level)))
+ break;
+ bp = bp->next;
+ }
+
+ return (bp ? bp->sym : (void *) NULL);
+}
+
+/*------------------------------------------------------------------*/
+/* newSymbol () - returns a new pointer to a symbol */
+/*------------------------------------------------------------------*/
+symbol *
+newSymbol (const char *name, long scope)
+{
+ symbol *sym;
+
+ sym = Safe_alloc (sizeof (symbol));
+
+ strncpyz (sym->name, name, sizeof (sym->name)); /* copy the name */
+ sym->level = scope; /* set the level */
+ sym->block = currBlockno;
+ sym->seqPoint = seqPointNo;
+ sym->lineDef = lexLineno; /* set the line number */
+ sym->fileDef = lexFilename;
+ sym->for_newralloc = 0;
+ sym->isinscope = 1;
+ sym->usl.spillLoc = 0;
+ sym->funcDivFlagSafe = 0;
+ sym->funcUsesVolatile = 1;
+
+ return sym;
+}
+
+/*------------------------------------------------------------------*/
+/* newLink - creates a new link (declarator,specifier) */
+/*------------------------------------------------------------------*/
+sym_link *
+newLink (SYM_LINK_CLASS select)
+{
+ sym_link *p;
+
+ p = Safe_alloc (sizeof (sym_link));
+ p->xclass = select;
+ p->funcAttrs.z88dk_params_offset = 0;
+
+ return p;
+}
+
+/*------------------------------------------------------------------*/
+/* newStruct - creats a new structdef from the free list */
+/*------------------------------------------------------------------*/
+structdef *
+newStruct (const char *tag)
+{
+ structdef *s;
+
+ s = Safe_alloc (sizeof (structdef));
+
+ strncpyz (s->tag, tag, sizeof (s->tag)); /* copy the tag */
+ return s;
+}
+
+/*------------------------------------------------------------------*/
+/* sclsFromPtr - Return the storage class a pointer points into. */
+/* S_FIXED is returned for generic pointers or other */
+/* unexpected cases */
+/*------------------------------------------------------------------*/
+STORAGE_CLASS
+sclsFromPtr (sym_link * ptr)
+{
+ switch (DCL_TYPE (ptr))
+ {
+ case POINTER:
+ return S_DATA;
+ case GPOINTER:
+ return S_FIXED;
+ case FPOINTER:
+ return S_XDATA;
+ case CPOINTER:
+ return S_CODE;
+ case IPOINTER:
+ return S_IDATA;
+ case PPOINTER:
+ return S_PDATA;
+ case EEPPOINTER:
+ return S_EEPROM;
+ case FUNCTION:
+ return S_CODE;
+ default:
+ return S_FIXED;
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* pointerTypes - do the computation for the pointer types */
+/*------------------------------------------------------------------*/
+void
+pointerTypes (sym_link * ptr, sym_link * type)
+{
+ sym_link *p;
+ sym_link *etype;
+
+ if (IS_SPEC (ptr))
+ return;
+
+ /* find the last unknown pointer type */
+ p = ptr;
+ while (p)
+ {
+ if (IS_PTR (p) && DCL_TYPE (p) == UPOINTER)
+ ptr = p;
+ p = p->next;
+ }
+
+ /* could not find it */
+ if (!ptr || IS_SPEC (ptr) || !IS_PTR (ptr))
+ return;
+
+ if (IS_PTR (ptr) && DCL_TYPE (ptr) != UPOINTER)
+ {
+ pointerTypes (ptr->next, type);
+ return;
+ }
+
+ /* change the pointer type depending on the
+ storage class of the etype */
+ etype = getSpec (type);
+ if (IS_SPEC (etype))
+ {
+ switch (SPEC_SCLS (etype))
+ {
+ case S_XDATA:
+ DCL_TYPE (ptr) = FPOINTER;
+ break;
+ case S_IDATA:
+ DCL_TYPE (ptr) = IPOINTER;
+ break;
+ case S_PDATA:
+ DCL_TYPE (ptr) = PPOINTER;
+ break;
+ case S_DATA:
+ DCL_TYPE (ptr) = POINTER;
+ break;
+ case S_CODE:
+ DCL_TYPE (ptr) = CPOINTER;
+ break;
+ case S_EEPROM:
+ DCL_TYPE (ptr) = EEPPOINTER;
+ break;
+ default:
+ DCL_TYPE (ptr) = port->unqualified_pointer;
+ break;
+ }
+ /* the storage class of etype ends here */
+ SPEC_SCLS (etype) = 0;
+ }
+
+ /* now change all the remaining unknown pointers
+ to generic pointers */
+ while (ptr)
+ {
+ if (!IS_SPEC (ptr) && DCL_TYPE (ptr) == UPOINTER)
+ DCL_TYPE (ptr) = port->unqualified_pointer;
+ ptr = ptr->next;
+ }
+
+ /* same for the type although it is highly unlikely that
+ type will have a pointer */
+ while (type)
+ {
+ if (!IS_SPEC (type) && DCL_TYPE (type) == UPOINTER)
+ DCL_TYPE (type) = port->unqualified_pointer;
+ type = type->next;
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* addDecl - adds a declarator @ the end of a chain */
+/*------------------------------------------------------------------*/
+void
+addDecl (symbol * sym, int type, sym_link * p)
+{
+ static sym_link *empty = NULL;
+ sym_link *head;
+ sym_link *tail;
+ sym_link *t;
+
+ if (getenv ("SDCC_DEBUG_FUNCTION_POINTERS"))
+ fprintf (stderr, "SDCCsymt.c:addDecl(%s,%d,%p)\n", sym->name, type, (void *)p);
+
+ if (empty == NULL)
+ empty = newLink (SPECIFIER);
+
+ /* if we are passed a link then set head & tail */
+ if (p)
+ {
+ tail = head = p;
+ while (tail->next)
+ tail = tail->next;
+ }
+ else
+ {
+ head = tail = newLink (DECLARATOR);
+ DCL_TYPE (head) = type;
+ }
+
+ /* if this is the first entry */
+ if (!sym->type)
+ {
+ sym->type = head;
+ sym->etype = tail;
+ }
+ else if (IS_SPEC (sym->etype) && IS_SPEC (head) && head == tail)
+ {
+ sym->etype = mergeSpec (sym->etype, head, sym->name);
+ }
+ else if (IS_SPEC (sym->etype) && !IS_SPEC (head) && head == tail)
+ {
+ t = sym->type;
+ while (t->next != sym->etype)
+ t = t->next;
+ t->next = head;
+ tail->next = sym->etype;
+ }
+ else if (IS_FUNC (sym->type) && IS_SPEC (sym->type->next) && !memcmp (sym->type->next, empty, sizeof (sym_link)))
+ {
+ sym->type->next = head;
+ sym->etype = tail;
+ }
+ else
+ {
+ sym->etype->next = head;
+ sym->etype = tail;
+ }
+
+ /* if the type is an unknown pointer and has
+ a tspec then take the storage class const & volatile
+ attribute from the tspec & make it those of this
+ symbol */
+ if (p && !IS_SPEC (p) &&
+ //DCL_TYPE (p) == UPOINTER &&
+ DCL_TSPEC (p))
+ {
+ if (!IS_SPEC (sym->etype))
+ {
+ sym->etype = sym->etype->next = newLink (SPECIFIER);
+ }
+ SPEC_SCLS (sym->etype) = SPEC_SCLS (DCL_TSPEC (p));
+ SPEC_ABSA (sym->etype) |= SPEC_ABSA (DCL_TSPEC (p));
+ SPEC_ADDR (sym->etype) |= SPEC_ADDR (DCL_TSPEC (p));
+ DCL_TSPEC (p) = NULL;
+ }
+
+ // if there is a function in this type chain
+ if (p && funcInChain (sym->type))
+ {
+ processFuncArgs (sym);
+ }
+
+ return;
+}
+
+/*------------------------------------------------------------------
+ checkTypeSanity: prevent the user from doing e.g.:
+ unsigned float uf;
+ ------------------------------------------------------------------*/
+void
+checkTypeSanity (sym_link *etype, const char *name)
+{
+ char *noun;
+
+ if (!etype)
+ {
+ if (getenv ("DEBUG_SANITY"))
+ {
+ fprintf (stderr, "sanity check skipped for %s (etype==0)\n", name);
+ }
+ return;
+ }
+
+ if (!IS_SPEC (etype))
+ {
+ if (getenv ("DEBUG_SANITY"))
+ {
+ fprintf (stderr, "sanity check skipped for %s (!IS_SPEC)\n", name);
+ }
+ return;
+ }
+
+ noun = nounName (etype);
+
+ if (getenv ("DEBUG_SANITY"))
+ {
+ fprintf (stderr, "checking sanity for %s %p\n", name, (void *)etype);
+ }
+
+ if ((SPEC_NOUN (etype) == V_BOOL ||
+ SPEC_NOUN (etype) == V_CHAR ||
+ SPEC_NOUN (etype) == V_FLOAT ||
+ SPEC_NOUN (etype) == V_FIXED16X16 ||
+ SPEC_NOUN (etype) == V_DOUBLE || SPEC_NOUN (etype) == V_VOID) && (SPEC_SHORT (etype) || SPEC_LONG (etype) || SPEC_LONGLONG (etype)))
+ { // long or short for char float double or void
+ werror (E_LONG_OR_SHORT_INVALID, noun, name);
+ }
+ if ((SPEC_NOUN (etype) == V_BOOL ||
+ SPEC_NOUN (etype) == V_FLOAT ||
+ SPEC_NOUN (etype) == V_FIXED16X16 ||
+ SPEC_NOUN (etype) == V_DOUBLE || SPEC_NOUN (etype) == V_VOID) && (etype->select.s.b_signed || SPEC_USIGN (etype)))
+ { // signed or unsigned for float double or void
+ werror (E_SIGNED_OR_UNSIGNED_INVALID, noun, name);
+ }
+
+ // special case for "short"
+ if (SPEC_SHORT (etype))
+ {
+ SPEC_NOUN (etype) = V_INT;
+ SPEC_SHORT (etype) = 0;
+ }
+
+ /* if no noun e.g.
+ "const a;" or "data b;" or "signed s" or "long l"
+ assume an int */
+ if (!SPEC_NOUN (etype))
+ {
+ SPEC_NOUN (etype) = V_INT;
+ if (!(SPEC_SHORT (etype) || SPEC_LONG (etype) || SPEC_LONGLONG (etype) || SPEC_SIGN (etype) || SPEC_USIGN (etype)))
+ werror (options.std_c99 ? E_NO_TYPE_SPECIFIER : W_NO_TYPE_SPECIFIER, name);
+ }
+
+ /* ISO/IEC 9899 J.3.9 implementation defined behaviour: */
+ /* a "plain" int bitfield is unsigned */
+ if (SPEC_NOUN (etype) == V_BIT || SPEC_NOUN (etype) == V_SBIT)
+ {
+ if (!etype->select.s.b_signed)
+ SPEC_USIGN (etype) = 1;
+ }
+
+ if (etype->select.s.b_signed && SPEC_USIGN (etype))
+ { // signed AND unsigned
+ werror (E_SIGNED_AND_UNSIGNED_INVALID, noun, name);
+ }
+ if (SPEC_SHORT (etype) && SPEC_LONG (etype))
+ { // short AND long
+ werror (E_LONG_AND_SHORT_INVALID, noun, name);
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* finalizeSpec */
+/* currently just a V_CHAR is forced to be unsigned */
+/* when it's neither signed nor unsigned */
+/* unless the --fsigned-char command line switch is active */
+/*------------------------------------------------------------------*/
+sym_link *
+finalizeSpec (sym_link * lnk)
+{
+ sym_link *p = lnk;
+ while (p && !IS_SPEC (p))
+ p = p->next;
+ if (SPEC_NOUN (p) == V_CHAR && !SPEC_USIGN (p) && !p->select.s.b_signed)
+ {
+ SPEC_USIGN (p) = !options.signed_char;
+ p->select.s.b_implicit_sign = true;
+ }
+ return lnk;
+}
+
+/*------------------------------------------------------------------*/
+/* mergeSpec - merges two specifiers and returns the new one */
+/*------------------------------------------------------------------*/
+sym_link *
+mergeSpec (sym_link * dest, sym_link * src, const char *name)
+{
+ unsigned int i;
+
+ if (!IS_SPEC (dest) || !IS_SPEC (src))
+ {
+#if 0
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "cannot merge declarator");
+ exit (1);
+#else
+ werror (E_SYNTAX_ERROR, yytext);
+ // the show must go on
+ return newIntLink ();
+#endif
+ }
+
+ if (!options.std_c11 && !options.std_c99)
+ {
+ if (SPEC_SIGN (dest) && SPEC_SIGN (src))
+ werror (W_REPEAT_QUALIFIER, "signed");
+ if (SPEC_USIGN (dest) && SPEC_USIGN (src))
+ werror (W_REPEAT_QUALIFIER, "unsigned");
+ if (SPEC_CONST (dest) && SPEC_CONST (src))
+ werror (W_REPEAT_QUALIFIER, "const");
+ if (SPEC_VOLATILE (dest) && SPEC_VOLATILE (src))
+ werror (W_REPEAT_QUALIFIER, "volatile");
+ if (SPEC_STAT (dest) && SPEC_STAT (src))
+ werror (W_REPEAT_QUALIFIER, "static");
+ if (SPEC_EXTR (dest) && SPEC_EXTR (src))
+ werror (W_REPEAT_QUALIFIER, "extern");
+ if (SPEC_TYPEDEF (dest) && SPEC_TYPEDEF (src))
+ werror (W_REPEAT_QUALIFIER, "typedef");
+ if (SPEC_SCLS (dest) == S_REGISTER && SPEC_SCLS (src) == S_REGISTER)
+ werror (W_REPEAT_QUALIFIER, "register");
+ if (SPEC_SCLS (dest) == S_AUTO && SPEC_SCLS (src) == S_AUTO)
+ werror (W_REPEAT_QUALIFIER, "auto");
+ }
+
+ if (SPEC_NOUN (src))
+ {
+ if (!SPEC_NOUN (dest))
+ {
+ SPEC_NOUN (dest) = SPEC_NOUN (src);
+ }
+ else
+ {
+ /* we shouldn't redeclare the type */
+ if (getenv ("DEBUG_SANITY"))
+ {
+ fprintf (stderr, "mergeSpec: ");
+ }
+ werror (E_TWO_OR_MORE_DATA_TYPES, name);
+ }
+ }
+
+ if ((SPEC_SHORT (src) || SPEC_LONG (src) || SPEC_LONGLONG (src)) &&
+ (SPEC_SHORT (dest) || SPEC_LONG (dest) || SPEC_LONGLONG (dest)))
+ {
+ if (!(options.std_c99 && SPEC_LONG (src) && SPEC_LONG (dest) && !TARGET_PIC_LIKE)) /* C99 has long long */
+ werror (E_SHORTLONG, name);
+ }
+
+ if (SPEC_SCLS (src))
+ {
+ /* if destination has no storage class */
+ if (!SPEC_SCLS (dest))
+ {
+ SPEC_SCLS (dest) = SPEC_SCLS (src);
+ }
+ else if (SPEC_SCLS (dest) == S_REGISTER && SPEC_SCLS (src) != S_AUTO)
+ {
+ SPEC_SCLS (dest) = SPEC_SCLS (src);
+ }
+ else
+ {
+ if (getenv ("DEBUG_SANITY"))
+ {
+ fprintf (stderr, "mergeSpec: ");
+ }
+ werror (E_TWO_OR_MORE_STORAGE_CLASSES, name);
+ }
+ }
+
+ /* copy all the specifications */
+
+ // we really should do:
+#if 0
+ if (SPEC_what (src))
+ {
+ if (SPEC_what (dest))
+ {
+ werror (W_DUPLICATE_SPEC, "what");
+ }
+ SPEC_what (dst) |= SPEC_what (src);
+ }
+#endif
+ // but there are more important thing right now
+
+ if (options.std_c99 && SPEC_LONG (src) && SPEC_LONG (dest))
+ {
+ SPEC_LONG (dest) = 0;
+ SPEC_LONGLONG (dest) = 1;
+ }
+ else
+ SPEC_LONG (dest) |= SPEC_LONG (src);
+ SPEC_LONGLONG (dest) |= SPEC_LONGLONG (src);
+ SPEC_SHORT (dest) |= SPEC_SHORT (src);
+ SPEC_USIGN (dest) |= SPEC_USIGN (src);
+ dest->select.s.b_signed |= src->select.s.b_signed;
+ SPEC_STAT (dest) |= SPEC_STAT (src);
+ SPEC_EXTR (dest) |= SPEC_EXTR (src);
+ SPEC_INLINE (dest) |= SPEC_INLINE (src);
+ SPEC_NORETURN (dest) |= SPEC_NORETURN(src);
+ SPEC_CONST (dest) |= SPEC_CONST (src);
+ SPEC_ABSA (dest) |= SPEC_ABSA (src);
+ SPEC_VOLATILE (dest) |= SPEC_VOLATILE (src);
+ SPEC_RESTRICT (dest) |= SPEC_RESTRICT (src);
+ SPEC_ADDR (dest) |= SPEC_ADDR (src);
+ SPEC_OCLS (dest) = SPEC_OCLS (src);
+ SPEC_BLEN (dest) |= SPEC_BLEN (src);
+ SPEC_BSTR (dest) |= SPEC_BSTR (src);
+ SPEC_TYPEDEF (dest) |= SPEC_TYPEDEF (src);
+ SPEC_ENUM (dest) |= SPEC_ENUM (src);
+ if (SPEC_ARGREG (src) && !SPEC_ARGREG (dest))
+ SPEC_ARGREG (dest) = SPEC_ARGREG (src);
+
+ if (SPEC_STAT (dest) && SPEC_EXTR (dest))
+ werror (E_TWO_OR_MORE_STORAGE_CLASSES, name);
+
+ if (IS_STRUCT (dest) && SPEC_STRUCT (dest) == NULL)
+ SPEC_STRUCT (dest) = SPEC_STRUCT (src);
+
+ if (FUNC_ISISR (dest) && FUNC_ISISR (src))
+ werror (E_INT_MULTIPLE, name);
+
+ /* these are the only function attributes that will be set
+ in a specifier while parsing */
+ FUNC_NONBANKED (dest) |= FUNC_NONBANKED (src);
+ FUNC_BANKED (dest) |= FUNC_BANKED (src);
+ FUNC_ISCRITICAL (dest) |= FUNC_ISCRITICAL (src);
+ FUNC_ISREENT (dest) |= FUNC_ISREENT (src);
+ FUNC_ISNAKED (dest) |= FUNC_ISNAKED (src);
+ FUNC_ISISR (dest) |= FUNC_ISISR (src);
+ FUNC_ISJAVANATIVE (dest) |= FUNC_ISJAVANATIVE (src);
+ FUNC_ISBUILTIN (dest) |= FUNC_ISBUILTIN (src);
+ FUNC_ISOVERLAY (dest) |= FUNC_ISOVERLAY (src);
+ FUNC_INTNO (dest) |= FUNC_INTNO (src);
+ FUNC_REGBANK (dest) |= FUNC_REGBANK (src);
+ FUNC_ISINLINE (dest) |= FUNC_ISINLINE (src);
+ FUNC_ISNORETURN (dest) |= FUNC_ISNORETURN (src);
+ FUNC_ISSMALLC (dest) |= FUNC_ISSMALLC (src);
+ FUNC_ISZ88DK_FASTCALL (dest) |= FUNC_ISZ88DK_FASTCALL (src);
+ FUNC_ISZ88DK_CALLEE (dest) |= FUNC_ISZ88DK_CALLEE (src);
+ for (i = 0; i < 9; i++)
+ dest->funcAttrs.preserved_regs[i] |= src->funcAttrs.preserved_regs[i];
+
+ if (SPEC_ADDRSPACE (src) && SPEC_ADDRSPACE (dest))
+ werror (E_TWO_OR_MORE_STORAGE_CLASSES, name);
+ if (SPEC_ADDRSPACE (src))
+ SPEC_ADDRSPACE (dest) = SPEC_ADDRSPACE (src);
+
+ if (SPEC_ALIGNAS (src) > SPEC_ALIGNAS (dest))
+ SPEC_ALIGNAS (dest) = SPEC_ALIGNAS (src);
+ if (SPEC_SCLS (dest) == S_REGISTER && SPEC_ALIGNAS (dest))
+ werror (E_ALIGNAS, SPEC_ALIGNAS (dest));
+
+ return dest;
+}
+
+/*------------------------------------------------------------------*/
+/* mergeDeclSpec - merges a specifier and a declarator */
+/*------------------------------------------------------------------*/
+sym_link *
+mergeDeclSpec (sym_link * dest, sym_link * src, const char *name)
+{
+ sym_link *decl, *spec, *lnk;
+
+ if (IS_SPEC (src))
+ {
+ if (IS_SPEC (dest))
+ {
+ return mergeSpec (dest, src, name);
+ }
+ else
+ {
+ decl = dest;
+ spec = src;
+ }
+ }
+ else
+ {
+ if (IS_SPEC (dest))
+ {
+ decl = src;
+ spec = dest;
+ }
+ else
+ {
+ werror (E_SYNTAX_ERROR, yytext);
+ // the show must go on
+ return newIntLink ();
+ }
+ }
+
+ DCL_PTR_CONST (decl) |= SPEC_CONST (spec);
+ DCL_PTR_VOLATILE (decl) |= SPEC_VOLATILE (spec);
+ DCL_PTR_RESTRICT (decl) |= SPEC_RESTRICT (spec);
+ if (DCL_PTR_ADDRSPACE (decl) && SPEC_ADDRSPACE (spec) &&
+ strcmp (DCL_PTR_ADDRSPACE (decl)->name, SPEC_ADDRSPACE (spec)->name))
+ werror (E_SYNTAX_ERROR, yytext);
+ if (SPEC_ADDRSPACE (spec))
+ DCL_PTR_ADDRSPACE (decl) = SPEC_ADDRSPACE (spec);
+
+ lnk = decl;
+ while (lnk && !IS_SPEC (lnk->next))
+ lnk = lnk->next;
+ lnk->next = mergeSpec (spec, lnk->next, name);
+ return decl;
+}
+
+/*-------------------------------------------------------------------*/
+/* genSymName - generates and returns a name used for anonymous vars */
+/*-------------------------------------------------------------------*/
+char *
+genSymName (long level)
+{
+ static int gCount = 0;
+ static char gname[SDCC_NAME_MAX + 1];
+
+ SNPRINTF (gname, sizeof (gname), "__%04d%04d", level, gCount++);
+ return gname;
+}
+
+/*------------------------------------------------------------------*/
+/* getSpec - returns the specifier part from a declaration chain */
+/*------------------------------------------------------------------*/
+sym_link *
+getSpec (sym_link * p)
+{
+ while (p && !(IS_SPEC (p)))
+ p = p->next;
+
+ return p;
+}
+
+/*------------------------------------------------------------------*/
+/* newCharLink() - creates an char type */
+/*------------------------------------------------------------------*/
+sym_link *
+newCharLink ()
+{
+ sym_link *p;
+
+ p = newLink (SPECIFIER);
+ SPEC_NOUN (p) = V_CHAR;
+ SPEC_USIGN (p) = 1;
+
+ return p;
+}
+
+/*------------------------------------------------------------------*/
+/* newFloatLink - a new Float type */
+/*------------------------------------------------------------------*/
+sym_link *
+newFloatLink ()
+{
+ sym_link *p;
+
+ p = newLink (SPECIFIER);
+ SPEC_NOUN (p) = V_FLOAT;
+
+ return p;
+}
+
+/*------------------------------------------------------------------*/
+/* newFixed16x16Link - a new Float type */
+/*------------------------------------------------------------------*/
+sym_link *
+newFixed16x16Link ()
+{
+ sym_link *p;
+
+ p = newLink (SPECIFIER);
+ SPEC_NOUN (p) = V_FIXED16X16;
+
+ return p;
+}
+
+/*------------------------------------------------------------------*/
+/* newLongLink() - new long type */
+/*------------------------------------------------------------------*/
+sym_link *
+newLongLink ()
+{
+ sym_link *p;
+
+ p = newLink (SPECIFIER);
+ SPEC_NOUN (p) = V_INT;
+ SPEC_LONG (p) = 1;
+
+ return p;
+}
+
+/*------------------------------------------------------------------*/
+/* newLongLongLink() - new long long type */
+/*------------------------------------------------------------------*/
+sym_link *
+newLongLongLink ()
+{
+ sym_link *p;
+
+ p = newLink (SPECIFIER);
+ SPEC_NOUN (p) = V_INT;
+ SPEC_LONGLONG (p) = 1;
+
+ return p;
+}
+
+/*------------------------------------------------------------------*/
+/* newIntLink() - creates an int type */
+/*------------------------------------------------------------------*/
+sym_link *
+newIntLink ()
+{
+ sym_link *p;
+
+ p = newLink (SPECIFIER);
+ SPEC_NOUN (p) = V_INT;
+
+ return p;
+}
+
+/*------------------------------------------------------------------*/
+/* newBoolLink() - creates an bool type */
+/*------------------------------------------------------------------*/
+sym_link *
+newBoolLink ()
+{
+ sym_link *p;
+
+ p = newLink (SPECIFIER);
+ if (bit)
+ SPEC_NOUN (p) = V_BIT;
+ else
+ SPEC_NOUN (p) = V_BOOL;
+
+ return p;
+}
+
+/*------------------------------------------------------------------*/
+/* newVoidLink() - creates an void type */
+/*------------------------------------------------------------------*/
+sym_link *
+newVoidLink ()
+{
+ sym_link *p;
+
+ p = newLink (SPECIFIER);
+ SPEC_NOUN (p) = V_VOID;
+
+ return p;
+}
+
+/*------------------------------------------------------------------*/
+/* getSize - returns size of a type chain in bytes */
+/*------------------------------------------------------------------*/
+unsigned int
+getSize (sym_link * p)
+{
+ /* if nothing return 0 */
+ if (!p)
+ return 0;
+ if (IS_SPEC (p))
+ { /* if this is the specifier then */
+ switch (SPEC_NOUN (p))
+ { /* depending on the specifier type */
+ case V_INT:
+ return (IS_LONGLONG (p) ? LONGLONGSIZE : (IS_LONG (p) ? LONGSIZE : INTSIZE));
+ case V_FLOAT:
+ return FLOATSIZE;
+ case V_FIXED16X16:
+ return (4);
+ case V_BOOL:
+ return BOOLSIZE;
+ case V_CHAR:
+ return CHARSIZE;
+ case V_VOID:
+ return 0;
+ case V_STRUCT:
+ return SPEC_STRUCT (p)->size;
+ case V_LABEL:
+ return 0;
+ case V_SBIT:
+ case V_BIT:
+ return BITSIZE;
+ case V_BITFIELD:
+ case V_BBITFIELD:
+ return ((SPEC_BLEN (p) / 8) + (SPEC_BLEN (p) % 8 ? 1 : 0));
+ default:
+ return 0;
+ }
+ }
+
+ /* this is a declarator */
+ switch (DCL_TYPE (p))
+ {
+ case ARRAY:
+ if (DCL_ELEM (p))
+ {
+ return DCL_ELEM (p) * getSize (p->next);
+ }
+ else
+ {
+ return 0;
+ }
+ case IPOINTER:
+ case PPOINTER:
+ case POINTER:
+ return (NEARPTRSIZE);
+ case EEPPOINTER:
+ case FPOINTER:
+ case CPOINTER:
+ case FUNCTION:
+ return (IFFUNC_ISBANKEDCALL (p) ? BFUNCPTRSIZE : FUNCPTRSIZE);
+ case GPOINTER:
+ return (GPTRSIZE);
+
+ default:
+ return 0;
+ }
+}
+
+#define FLEXARRAY 1
+#define INCOMPLETE 2
+
+/*------------------------------------------------------------------*/
+/* checkStructFlexArray - check tree behind a struct */
+/*------------------------------------------------------------------*/
+static int
+checkStructFlexArray (symbol * sym, sym_link * p)
+{
+ /* if nothing return FALSE */
+ if (!p)
+ return 0;
+
+ if (IS_SPEC (p))
+ {
+ /* (nested) struct with flexible array member? */
+ if (IS_STRUCT (p) && SPEC_STRUCT (p)->b_flexArrayMember)
+ {
+ werror (W_INVALID_FLEXARRAY);
+ return INCOMPLETE;
+ }
+ /* or otherwise incomplete (nested) struct? */
+ if (IS_STRUCT (p) && ((SPEC_STRUCT (p)->size == 0) || !SPEC_STRUCT (p)->fields))
+ {
+ return INCOMPLETE;
+ }
+ return 0;
+ }
+
+ /* this is a declarator */
+ if (IS_ARRAY (p))
+ {
+ /* flexible array member? */
+ if (!DCL_ELEM (p))
+ {
+ if (!options.std_c99)
+ werror (W_C89_NO_FLEXARRAY);
+ if (checkStructFlexArray (sym, p->next) == INCOMPLETE)
+ werror (E_INCOMPLETE_FIELD, sym->name);
+ return FLEXARRAY;
+ }
+ /* walk tree */
+ return checkStructFlexArray (sym, p->next);
+ }
+ return 0;
+}
+
+/*------------------------------------------------------------------*/
+/* bitsForType - returns # of bits required to store this type */
+/*------------------------------------------------------------------*/
+unsigned int
+bitsForType (sym_link * p)
+{
+ /* if nothing return 0 */
+ if (!p)
+ return 0;
+
+ if (IS_SPEC (p))
+ { /* if this is the specifier then */
+ switch (SPEC_NOUN (p))
+ { /* depending on the specifier type */
+ case V_INT:
+ if (IS_LONGLONG (p))
+ return LONGLONGSIZE * 8;
+ if (IS_LONG (p))
+ return LONGSIZE * 8;
+ return INTSIZE * 8;
+ case V_FLOAT:
+ return FLOATSIZE * 8;
+ case V_FIXED16X16:
+ return (32);
+ case V_BOOL:
+ return BOOLSIZE * 8;
+ case V_CHAR:
+ return CHARSIZE * 8;
+ case V_VOID:
+ return 0;
+ case V_STRUCT:
+ return SPEC_STRUCT (p)->size * 8;
+ case V_LABEL:
+ return 0;
+ case V_SBIT:
+ case V_BIT:
+ return 1;
+ case V_BITFIELD:
+ case V_BBITFIELD:
+ return SPEC_BLEN (p);
+ default:
+ return 0;
+ }
+ }
+
+ /* this is a specifier */
+ switch (DCL_TYPE (p))
+ {
+ case ARRAY:
+ return DCL_ELEM (p) * getSize (p->next) * 8;
+ case IPOINTER:
+ case PPOINTER:
+ case POINTER:
+ return (NEARPTRSIZE * 8);
+ case EEPPOINTER:
+ case FPOINTER:
+ case CPOINTER:
+ case FUNCTION:
+ return (FARPTRSIZE * 8);
+ case GPOINTER:
+ return (GPTRSIZE * 8);
+ default:
+ return 0;
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* copySymbolChain - copies a symbol chain */
+/*------------------------------------------------------------------*/
+symbol *
+copySymbolChain (const symbol * src)
+{
+ symbol *dest;
+
+ if (!src)
+ return NULL;
+
+ dest = copySymbol (src);
+ dest->next = copySymbolChain (src->next);
+ return dest;
+}
+
+/*------------------------------------------------------------------*/
+/* copySymbol - makes a copy of a symbol */
+/*------------------------------------------------------------------*/
+symbol *
+copySymbol (const symbol * src)
+{
+ symbol *dest;
+
+ if (!src)
+ return NULL;
+
+ dest = newSymbol (src->name, src->level);
+ memcpy (dest, src, sizeof (symbol));
+ dest->level = src->level;
+ dest->block = src->block;
+ dest->ival = copyIlist (src->ival);
+ dest->type = copyLinkChain (src->type);
+ dest->etype = getSpec (dest->type);
+ dest->next = NULL;
+ dest->key = src->key;
+ dest->allocreq = src->allocreq;
+ return dest;
+}
+
+/*------------------------------------------------------------------*/
+/* reverseSyms - reverses the links for a symbol chain */
+/*------------------------------------------------------------------*/
+symbol *
+reverseSyms (symbol * sym)
+{
+ symbol *prev, *curr, *next;
+
+ if (!sym)
+ return NULL;
+
+ prev = sym;
+ curr = sym->next;
+
+ while (curr)
+ {
+ next = curr->next;
+ curr->next = prev;
+ prev = curr;
+ curr = next;
+ }
+ sym->next = (void *) NULL;
+ return prev;
+}
+
+/*------------------------------------------------------------------*/
+/* reverseLink - reverses the links for a type chain */
+/*------------------------------------------------------------------*/
+sym_link *
+reverseLink (sym_link * type)
+{
+ sym_link *prev, *curr, *next;
+
+ if (!type)
+ return NULL;
+
+ prev = type;
+ curr = type->next;
+
+ while (curr)
+ {
+ next = curr->next;
+ curr->next = prev;
+ prev = curr;
+ curr = next;
+ }
+ type->next = (void *) NULL;
+ return prev;
+}
+
+/*------------------------------------------------------------------*/
+/* addSymChain - adds a symbol chain to the symboltable */
+/*------------------------------------------------------------------*/
+void
+addSymChain (symbol ** symHead)
+{
+ symbol *sym;
+ symbol *csym = NULL;
+ symbol **symPtrPtr;
+ int error = 0;
+ int elemsFromIval = 0;
+
+ for (sym = *symHead; sym != NULL; sym = sym->next)
+ {
+ changePointer (sym->type);
+ checkTypeSanity (sym->etype, sym->name);
+
+ if (IS_NORETURN (sym->etype))
+ {
+ SPEC_NORETURN (sym->etype) = 0;
+ FUNC_ISNORETURN (sym->type) = 1;
+ }
+
+ if (!sym->level && !(IS_SPEC (sym->etype) && IS_TYPEDEF (sym->etype)))
+ elemsFromIval = checkDecl (sym, 0);
+ else
+ {
+ /* if this is an array without any dimension
+ then update the dimension from the initial value */
+ if (IS_ARRAY (sym->type) && !DCL_ELEM (sym->type))
+ elemsFromIval = DCL_ELEM (sym->type) = getNelements (sym->type, sym->ival);
+ }
+
+ /* if already exists in the symbol table on the same level, ignoring sublevels */
+ if ((csym = findSymWithLevel (SymbolTab, sym)) && csym->level / LEVEL_UNIT == sym->level / LEVEL_UNIT)
+ {
+ /* if not formal parameter and not in file scope
+ then show symbol redefined error
+ else check if symbols have compatible types */
+ if (!sym->_isparm && sym->level > 0)
+ error = 1;
+ else
+ {
+ /* If the previous definition was for an array with incomplete
+ type, and the new definition has completed the type, update
+ the original type to match */
+ if (IS_ARRAY (csym->type) && IS_ARRAY (sym->type))
+ {
+ if (!DCL_ELEM (csym->type) && DCL_ELEM (sym->type))
+ DCL_ELEM (csym->type) = DCL_ELEM (sym->type);
+ if ((DCL_ELEM (csym->type) > DCL_ELEM (sym->type)) && elemsFromIval)
+ DCL_ELEM (sym->type) = DCL_ELEM (csym->type);
+ }
+
+#if 0
+ /* If only one of the definitions used the "at" keyword, copy */
+ /* the address to the other. */
+ if (IS_SPEC (csym->etype) && SPEC_ABSA (csym->etype) && IS_SPEC (sym->etype) && !SPEC_ABSA (sym->etype))
+ {
+ SPEC_ABSA (sym->etype) = 1;
+ SPEC_ADDR (sym->etype) = SPEC_ADDR (csym->etype);
+ }
+ if (IS_SPEC (csym->etype) && !SPEC_ABSA (csym->etype) && IS_SPEC (sym->etype) && SPEC_ABSA (sym->etype))
+ {
+ SPEC_ABSA (csym->etype) = 1;
+ SPEC_ADDR (csym->etype) = SPEC_ADDR (sym->etype);
+ }
+#endif
+
+ error = 0;
+ if (csym->ival && sym->ival)
+ error = 1;
+ if (compareTypeExact (csym->type, sym->type, sym->level) != 1)
+ error = 1;
+ }
+
+ if (error)
+ {
+ /* one definition extern ? */
+ if (IS_EXTERN (csym->etype) || IS_EXTERN (sym->etype))
+ werror (E_EXTERN_MISMATCH, sym->name);
+ else
+ werror (E_DUPLICATE, sym->name);
+ werrorfl (csym->fileDef, csym->lineDef, E_PREVIOUS_DEF);
+#if 0
+ fprintf (stderr, "from type '");
+ printTypeChain (csym->type, stderr);
+ if (IS_SPEC (csym->etype) && SPEC_ABSA (csym->etype))
+ fprintf (stderr, " at 0x%x", SPEC_ADDR (csym->etype));
+ fprintf (stderr, "'\nto type '");
+ printTypeChain (sym->type, stderr);
+ if (IS_SPEC (sym->etype) && SPEC_ABSA (sym->etype))
+ fprintf (stderr, " at 0x%x", SPEC_ADDR (sym->etype));
+ fprintf (stderr, "'\n");
+#endif
+ continue;
+ }
+
+ if (FUNC_BANKED (csym->type) || FUNC_BANKED (sym->type))
+ {
+ if (FUNC_NONBANKED (csym->type) || FUNC_NONBANKED (sym->type))
+ {
+ werror (W_BANKED_WITH_NONBANKED);
+ FUNC_BANKED (sym->type) = 0;
+ FUNC_NONBANKED (sym->type) = 1;
+ }
+ else
+ {
+ FUNC_BANKED (sym->type) = 1;
+ }
+ }
+ else
+ {
+ if (FUNC_NONBANKED (csym->type) || FUNC_NONBANKED (sym->type))
+ {
+ FUNC_NONBANKED (sym->type) = 1;
+ }
+ }
+
+ if (csym->ival && !sym->ival)
+ sym->ival = csym->ival;
+
+ if (!csym->cdef && !sym->cdef && IS_EXTERN (sym->etype))
+ {
+ /* if none of symbols is a compiler defined function
+ and at least one is not extern
+ then set the new symbol to non extern */
+ SPEC_EXTR (sym->etype) = SPEC_EXTR (csym->etype);
+ }
+
+ /* delete current entry */
+ deleteSym (SymbolTab, csym, csym->name);
+ deleteFromSeg (csym);
+
+ symPtrPtr = symHead;
+ while (*symPtrPtr && *symPtrPtr != csym)
+ symPtrPtr = &(*symPtrPtr)->next;
+ if (*symPtrPtr == csym)
+ *symPtrPtr = csym->next;
+ }
+
+ /* add new entry */
+ addSym (SymbolTab, sym, sym->name, sym->level, sym->block, 1);
+ }
+}
+
+
+/*------------------------------------------------------------------*/
+/* funcInChain - DCL Type 'FUNCTION' found in type chain */
+/*------------------------------------------------------------------*/
+int
+funcInChain (sym_link * lnk)
+{
+ while (lnk)
+ {
+ if (IS_FUNC (lnk))
+ return 1;
+ lnk = lnk->next;
+ }
+ return 0;
+}
+
+/*------------------------------------------------------------------*/
+/* structElemType - returns the type info of a struct member */
+/*------------------------------------------------------------------*/
+sym_link *
+structElemType (sym_link * stype, value * id)
+{
+ symbol *fields = (SPEC_STRUCT (stype) ? SPEC_STRUCT (stype)->fields : NULL);
+ sym_link *type, *etype;
+ sym_link *petype = getSpec (stype);
+
+ if (fields && id)
+ {
+ /* look for the id */
+ while (fields)
+ {
+ if (strcmp (fields->rname, id->name) == 0)
+ {
+ sym_link *t;
+ type = copyLinkChain (fields->type);
+ etype = getSpec (type);
+ SPEC_SCLS (etype) = (SPEC_SCLS (petype) == S_REGISTER ? SPEC_SCLS (etype) : SPEC_SCLS (petype));
+ SPEC_OCLS (etype) = (SPEC_SCLS (petype) == S_REGISTER ? SPEC_OCLS (etype) : SPEC_OCLS (petype));
+ /* find the first non-array link */
+ t = type;
+ while (IS_ARRAY (t))
+ t = t->next;
+ if (IS_SPEC (t))
+ SPEC_CONST (t) |= SPEC_CONST (stype);
+ else
+ DCL_PTR_CONST (t) |= SPEC_CONST (stype);
+ return type;
+ }
+ fields = fields->next;
+ }
+ }
+
+ werror (E_NOT_MEMBER, id->name);
+
+ // the show must go on
+ return newIntLink ();
+}
+
+/*------------------------------------------------------------------*/
+/* getStructElement - returns element of a tructure definition */
+/*------------------------------------------------------------------*/
+symbol *
+getStructElement (structdef * sdef, symbol * sym)
+{
+ symbol *field;
+
+ for (field = sdef->fields; field; field = field->next)
+ if (strcmp (field->name, sym->name) == 0)
+ return field;
+
+ werror (E_NOT_MEMBER, sym->name);
+
+ return sdef->fields;
+}
+
+/*------------------------------------------------------------------*/
+/* compStructSize - computes the size of a structure */
+/*------------------------------------------------------------------*/
+int
+compStructSize (int su, structdef * sdef)
+{
+ int sum = 0, usum = 0;
+ int bitOffset = 0;
+ symbol *loop;
+ const int oldlineno = lineno;
+
+ if (!sdef->fields)
+ {
+ werror (E_UNKNOWN_SIZE, sdef->tag);
+ }
+
+ /* for the identifiers */
+ loop = sdef->fields;
+ while (loop)
+ {
+ lineno = loop->lineDef;
+
+ /* create the internal name for this variable */
+ SNPRINTF (loop->rname, sizeof (loop->rname), "_%s", loop->name);
+ if (su == UNION)
+ {
+ sum = 0;
+ bitOffset = 0;
+ }
+ SPEC_VOLATILE (loop->etype) |= (su == UNION ? 1 : 0);
+
+ /* if this is a bit field */
+ if (loop->bitVar)
+ {
+ SPEC_BUNNAMED (loop->etype) = loop->bitUnnamed;
+
+ /* change it to a unsigned bit */
+ switch (SPEC_NOUN (loop->etype))
+ {
+ case V_BOOL:
+ SPEC_NOUN( loop->etype) = V_BBITFIELD;
+ if (loop->bitVar > 1)
+ werror (E_BITFLD_SIZE, 1);
+ break;
+ case V_CHAR:
+ SPEC_NOUN (loop->etype) = V_BITFIELD;
+ if (loop->bitVar > 8)
+ werror (E_BITFLD_SIZE , 8);
+ break;
+ case V_INT:
+ SPEC_NOUN (loop->etype) = V_BITFIELD;
+ if (loop->bitVar > port->s.int_size * 8)
+ werror (E_BITFLD_SIZE , port->s.int_size * 8);
+ break;
+ default:
+ werror (E_BITFLD_TYPE);
+ }
+
+ /* ISO/IEC 9899 J.3.9 implementation defined behaviour: */
+ /* a "plain" int bitfield is unsigned */
+ if (!loop->etype->select.s.b_signed)
+ SPEC_USIGN (loop->etype) = 1;
+
+ if (loop->bitVar == BITVAR_PAD)
+ {
+ /* A zero length bitfield forces padding */
+ SPEC_BLEN (loop->etype) = 0;
+ SPEC_BSTR (loop->etype) = bitOffset;
+ if (bitOffset > 0)
+ bitOffset = 8; /* padding is not needed when at bit 0 */
+ loop->offset = sum;
+ }
+ else
+ {
+ SPEC_BLEN (loop->etype) = loop->bitVar;
+
+ if (bitOffset == 8)
+ {
+ bitOffset = 0;
+ sum++;
+ }
+ /* check if this fit into the remaining */
+ /* bits of this byte else align it to the */
+ /* next byte boundary */
+ if (loop->bitVar <= (8 - bitOffset))
+ {
+ /* fits into current byte */
+ loop->offset = sum;
+ SPEC_BSTR (loop->etype) = bitOffset;
+ bitOffset += loop->bitVar;
+ }
+ else if (!bitOffset)
+ {
+ /* does not fit, but is already byte aligned */
+ loop->offset = sum;
+ SPEC_BSTR (loop->etype) = bitOffset;
+ bitOffset += loop->bitVar;
+ }
+ else
+ {
+ if (TARGET_IS_PIC16 && getenv ("PIC16_PACKED_BITFIELDS"))
+ {
+ /* if PIC16 && enviroment variable is set, then
+ * tightly pack bitfields, this means that when a
+ * bitfield goes beyond byte alignment, do not
+ * automatically start allocatint from next byte,
+ * but also use the available bits first */
+ fprintf (stderr, ": packing bitfields in structures\n");
+ SPEC_BSTR (loop->etype) = bitOffset;
+ bitOffset += loop->bitVar;
+ loop->offset = (su == UNION ? sum = 0 : sum);
+ }
+ else
+ {
+ /* does not fit; need to realign first */
+ sum++;
+ loop->offset = (su == UNION ? sum = 0 : sum);
+ bitOffset = 0;
+ SPEC_BSTR (loop->etype) = bitOffset;
+ bitOffset += loop->bitVar;
+ }
+ }
+ while (bitOffset > 8)
+ {
+ bitOffset -= 8;
+ sum++;
+ }
+ }
+ }
+ else
+ {
+ /* This is a non-bit field. Make sure we are */
+ /* byte aligned first */
+ if (bitOffset)
+ {
+ sum++;
+ loop->offset = (su == UNION ? sum = 0 : sum);
+ bitOffset = 0;
+ }
+ loop->offset = sum;
+ checkDecl (loop, 1);
+ sum += getSize (loop->type);
+
+ /* search for "flexible array members" */
+ /* and do some syntax checks */
+ if (su == STRUCT)
+ {
+ int ret = checkStructFlexArray (loop, loop->type);
+ if (ret == FLEXARRAY)
+ {
+ /* found a "flexible array member" */
+ sdef->b_flexArrayMember = TRUE;
+ /* is another struct-member following? */
+ if (loop->next)
+ werror (E_FLEXARRAY_NOTATEND, loop->name);
+ /* is it the first struct-member? */
+ else if (loop == sdef->fields)
+ werror (E_FLEXARRAY_INEMPTYSTRCT, loop->name);
+ }
+ else if (ret == INCOMPLETE)
+ {
+ werror (E_INCOMPLETE_FIELD, loop->name);
+ }
+ }
+ }
+
+ loop = loop->next;
+
+ /* if union then size = sizeof largest field */
+ if (su == UNION)
+ {
+ /* For UNION, round up after each field */
+ sum += ((bitOffset + 7) / 8);
+ usum = max (usum, sum);
+ }
+ }
+
+ /* For STRUCT, round up after all fields processed */
+ if (su != UNION)
+ sum += ((bitOffset + 7) / 8);
+
+ lineno = oldlineno;
+
+ return (su == UNION ? usum : sum);
+}
+
+/*-------------------------------------------------------------------*/
+/* promoteAnonStructs - promote anonymous struct/union's fields into */
+/* an enclosing struct/union */
+/*-------------------------------------------------------------------*/
+void
+promoteAnonStructs (int su, structdef * sdef)
+{
+ symbol *field;
+ symbol *subfield;
+ symbol **tofield;
+ symbol *nextfield;
+ symbol *dupfield;
+ int base;
+
+ tofield = &sdef->fields;
+ field = sdef->fields;
+ while (field)
+ {
+ nextfield = field->next;
+ if (!*field->name && IS_STRUCT (field->type))
+ {
+ /* Found an anonymous struct/union. Replace it */
+ /* with the fields it contains and adjust all */
+ /* the offsets */
+
+ /* tagged anonymous struct/union is rejected here, though gcc allow it */
+ if (SPEC_STRUCT (field->type)->tagsym != NULL)
+ werrorfl (field->fileDef, field->lineDef, E_ANONYMOUS_STRUCT_TAG, SPEC_STRUCT (field->type)->tag);
+
+ base = field->offset;
+ subfield = copySymbolChain (SPEC_STRUCT (field->type)->fields);
+ if (!subfield)
+ continue; /* just in case it's empty */
+
+ *tofield = subfield;
+ for (;;)
+ {
+ /* check for field name conflicts resulting from promotion */
+ dupfield = sdef->fields;
+ while (dupfield && dupfield != subfield)
+ {
+ if (*subfield->name && !strcmp (dupfield->name, subfield->name))
+ {
+ werrorfl (subfield->fileDef, subfield->lineDef,
+ E_DUPLICATE_MEMBER, su == STRUCT ? "struct" : "union", subfield->name);
+ werrorfl (dupfield->fileDef, dupfield->lineDef, E_PREVIOUS_DEF);
+ }
+ dupfield = dupfield->next;
+ }
+
+ subfield->offset += base;
+ if (subfield->next)
+ subfield = subfield->next;
+ else
+ break;
+ }
+ subfield->next = nextfield;
+ tofield = &subfield->next;
+ }
+ else
+ tofield = &field->next;
+ field = nextfield;
+ }
+}
+
+
+/*------------------------------------------------------------------*/
+/* checkSClass - check the storage class specification */
+/*------------------------------------------------------------------*/
+static void
+checkSClass (symbol *sym, int isProto)
+{
+ sym_link *t;
+
+ if (getenv ("DEBUG_SANITY"))
+ {
+ fprintf (stderr, "checkSClass: %s \n", sym->name);
+ }
+
+ /* type is literal can happen for enums change to auto */
+ if (SPEC_SCLS (sym->etype) == S_LITERAL && !SPEC_ENUM (sym->etype))
+ SPEC_SCLS (sym->etype) = S_AUTO;
+
+ /* if sfr or sbit then must also be volatile */
+ if (SPEC_SCLS (sym->etype) == S_SBIT || SPEC_SCLS (sym->etype) == S_SFR)
+ {
+ SPEC_VOLATILE (sym->etype) = 1;
+ }
+
+ if (SPEC_NEEDSPAR (sym->etype))
+ {
+ werrorfl (sym->fileDef, sym->lineDef, E_QUALIFIED_ARRAY_NOPARAM);
+ SPEC_NEEDSPAR (sym->etype) = 0;
+ }
+
+ /* make sure restrict is only used with pointers */
+ if (SPEC_RESTRICT (sym->etype))
+ {
+ werrorfl (sym->fileDef, sym->lineDef, E_BAD_RESTRICT);
+ SPEC_RESTRICT (sym->etype) = 0;
+ }
+
+ t = sym->type;
+ while (t)
+ {
+ if (IS_DECL (t) && DCL_PTR_RESTRICT (t) && !(IS_PTR (t) && !IS_FUNCPTR(t)))
+ {
+ werrorfl (sym->fileDef, sym->lineDef, E_BAD_RESTRICT);
+ DCL_PTR_RESTRICT (t) = 0;
+ break;
+ }
+ t = t->next;
+ }
+
+ /* if absolute address given then it mark it as
+ volatile -- except in the PIC port */
+
+#if !OPT_DISABLE_PIC14 || !OPT_DISABLE_PIC16
+ /* The PIC port uses a different peep hole optimizer based on "pCode" */
+ if (!TARGET_PIC_LIKE)
+#endif
+
+ if (IS_ABSOLUTE (sym->etype))
+ SPEC_VOLATILE (sym->etype) = 1;
+
+ if (TARGET_IS_MCS51 && IS_ABSOLUTE (sym->etype) && SPEC_SCLS (sym->etype) == S_SFR)
+ {
+ int n, size;
+ unsigned addr;
+
+ if (SPEC_NOUN (sym->etype) == V_CHAR)
+ size = 8;
+ else if (SPEC_LONG (sym->etype) == 0)
+ size = 16;
+ else if (SPEC_LONGLONG (sym->etype) == 0)
+ size = 32;
+ else
+ size = 64;
+
+ addr = SPEC_ADDR (sym->etype);
+ for (n = 0; n < size; n += 8)
+ if (((addr >> n) & 0xFF) < 0x80)
+ werror (W_SFR_ABSRANGE, sym->name);
+ }
+ else if (TARGET_Z80_LIKE && IS_ABSOLUTE (sym->etype) && SPEC_SCLS (sym->etype) == S_SFR)
+ {
+ if (SPEC_ADDR (sym->etype) > (FUNC_REGBANK (sym->type) ? 0xffff : 0xff))
+ werror (W_SFR_ABSRANGE, sym->name);
+ }
+ else if (TARGET_IS_PDK13 && IS_ABSOLUTE (sym->etype) && SPEC_SCLS (sym->etype) == S_SFR)
+ {
+ if (SPEC_ADDR (sym->etype) > 0x1f)
+ werror (W_SFR_ABSRANGE, sym->name);
+ }
+ else if (TARGET_IS_PDK14 && IS_ABSOLUTE (sym->etype) && SPEC_SCLS (sym->etype) == S_SFR)
+ {
+ if (SPEC_ADDR (sym->etype) > 0x3f)
+ werror (W_SFR_ABSRANGE, sym->name);
+ }
+ else if (TARGET_IS_PDK15 && IS_ABSOLUTE (sym->etype) && SPEC_SCLS (sym->etype) == S_SFR)
+ {
+ if (SPEC_ADDR (sym->etype) > 0x7f)
+ werror (W_SFR_ABSRANGE, sym->name);
+ }
+ else if (TARGET_IS_PDK16 && IS_ABSOLUTE (sym->etype) && SPEC_SCLS (sym->etype) == S_SFR)
+ {
+ if (SPEC_ADDR (sym->etype) > 0x1f)
+ werror (W_SFR_ABSRANGE, sym->name);
+ }
+
+ /* If code memory is read only, then pointers to code memory */
+ /* implicitly point to constants -- make this explicit */
+ CodePtrPointsToConst (sym->type);
+
+ /* global variables declared const put into code */
+ /* if no other storage class specified */
+ if ((sym->level == 0 || SPEC_STAT(sym->etype)) && SPEC_SCLS (sym->etype) == S_FIXED && !IS_FUNC (sym->type))
+ {
+ /* find the first non-array link */
+ t = sym->type;
+ while (IS_ARRAY (t))
+ t = t->next;
+ if (IS_CONSTANT (t))
+ SPEC_SCLS (sym->etype) = S_CODE;
+ }
+
+ /* global variable in code space is a constant */
+ if ((sym->level == 0 || SPEC_STAT(sym->etype)) && SPEC_SCLS (sym->etype) == S_CODE && port->mem.code_ro)
+ {
+ /* find the first non-array link */
+ t = sym->type;
+ while (IS_ARRAY (t))
+ t = t->next;
+ if (IS_SPEC (t))
+ SPEC_CONST (t) = 1;
+ else
+ DCL_PTR_CONST (t) = 1;
+ }
+
+ /* if bit variable then no storage class can be */
+ /* specified since bit is already a storage */
+ if (IS_BITVAR (sym->etype) &&
+ (SPEC_SCLS (sym->etype) != S_FIXED && SPEC_SCLS (sym->etype) != S_SBIT && SPEC_SCLS (sym->etype) != S_BIT))
+ {
+ /* find out if this is the return type of a function */
+ t = sym->type;
+ while (t && t->next != sym->etype)
+ t = t->next;
+ if (!t || t->next != sym->etype || !IS_FUNC (t))
+ {
+ werror (E_BITVAR_STORAGE, sym->name);
+ SPEC_SCLS (sym->etype) = S_FIXED;
+ }
+ }
+
+ /* if this is an automatic symbol */
+ if (sym->level && (options.stackAuto || reentrant))
+ {
+ if (SPEC_SCLS (sym->etype) != S_BIT &&
+ SPEC_SCLS (sym->etype) != S_REGISTER)
+ {
+ if ((SPEC_SCLS (sym->etype) == S_AUTO ||
+ SPEC_SCLS (sym->etype) == S_FIXED ||
+ SPEC_SCLS (sym->etype) == S_STACK ||
+ SPEC_SCLS (sym->etype) == S_XSTACK))
+ {
+ SPEC_SCLS (sym->etype) = S_AUTO;
+ }
+ else
+ {
+ /* storage class may only be specified for statics */
+ if (!IS_STATIC (sym->etype))
+ {
+ werror (E_AUTO_ASSUMED, sym->name);
+ }
+ }
+ }
+ }
+
+ /* automatic symbols cannot be given */
+ /* an absolute address ignore it */
+ if (sym->level && !IS_STATIC (sym->etype) && SPEC_ABSA (sym->etype) && (options.stackAuto || reentrant))
+ {
+ werror (E_AUTO_ABSA, sym->name);
+ SPEC_ABSA (sym->etype) = 0;
+ }
+
+ if (sym->level && !IS_STATIC (sym->etype) && (IS_DECL (sym->type) ? DCL_PTR_ADDRSPACE (sym->type) : SPEC_ADDRSPACE (sym->type)) && (options.stackAuto || reentrant))
+ {
+ werror (E_AUTO_ADDRSPACE, sym->name);
+ if (IS_DECL (sym->type))
+ DCL_PTR_ADDRSPACE (sym->type) = 0;
+ else
+ SPEC_ADDRSPACE (sym->type) = 0;
+ }
+
+ /* arrays & pointers cannot be defined for bits */
+ /* SBITS or SFRs or BIT */
+ if ((IS_ARRAY (sym->type) || IS_PTR (sym->type)) &&
+ (SPEC_NOUN (sym->etype) == V_BIT || SPEC_NOUN (sym->etype) == V_SBIT ||
+ SPEC_NOUN (sym->etype) == V_BITFIELD || SPEC_NOUN (sym->etype) == V_BBITFIELD ||
+ SPEC_SCLS (sym->etype) == S_SFR))
+ {
+ /* find out if this is the return type of a function */
+ t = sym->type;
+ while (t && t->next != sym->etype)
+ t = t->next;
+ if (t->next != sym->etype || !IS_FUNC (t))
+ {
+ werror (E_BIT_ARRAY, sym->name);
+ }
+ }
+
+ /* if this is a bit|sbit then set length & start */
+ if (SPEC_NOUN (sym->etype) == V_BIT || SPEC_NOUN (sym->etype) == V_SBIT)
+ {
+ SPEC_BLEN (sym->etype) = 1;
+ SPEC_BSTR (sym->etype) = 0;
+ }
+
+ if (!isProto)
+ {
+ /* variables declared in CODE space must have */
+ /* initializers if not an extern, a global or a static */
+ if (SPEC_SCLS (sym->etype) == S_CODE && sym->ival == NULL && !sym->_isparm &&
+ IS_AUTO(sym) &&
+ port->mem.code_ro && !SPEC_ABSA (sym->etype) && !funcInChain (sym->type))
+ werror (E_CODE_NO_INIT, sym->name);
+ }
+
+ /* if parameter or local variable then change */
+ /* the storage class to reflect where the var will go */
+ if (sym->level && SPEC_SCLS (sym->etype) == S_FIXED && !IS_STATIC (sym->etype))
+ {
+ if (options.stackAuto || (currFunc && IFFUNC_ISREENT (currFunc->type)))
+ {
+ SPEC_SCLS (sym->etype) = (options.useXstack ? S_XSTACK : S_STACK);
+ }
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* changePointer - change pointer to functions */
+/*------------------------------------------------------------------*/
+void
+changePointer (sym_link * p)
+{
+ /* go thru the chain of declarations */
+ /* if we find a pointer to a function */
+ /* change it to a ptr to code area */
+ /* unless the function is banked. */
+ for (; p; p = p->next)
+ {
+ if (IS_DECL (p) && DCL_TYPE (p) == UPOINTER)
+ DCL_TYPE (p) = port->unqualified_pointer;
+ if (IS_PTR (p) && IS_FUNC (p->next))
+ if (!IFFUNC_ISBANKEDCALL (p->next))
+ DCL_TYPE (p) = CPOINTER;
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* checkDecl - does semantic validation of a declaration */
+/*------------------------------------------------------------------*/
+int
+checkDecl (symbol * sym, int isProto)
+{
+ checkSClass (sym, isProto); /* check the storage class */
+ changePointer (sym->type); /* change pointers if required */
+
+ /* if this is an array without any dimension
+ then update the dimension from the initial value */
+ if (IS_ARRAY (sym->type) && !DCL_ELEM (sym->type))
+ return DCL_ELEM (sym->type) = getNelements (sym->type, sym->ival);
+
+ return 0;
+}
+
+/*------------------------------------------------------------------*/
+/* copyLinkChain - makes a copy of the link chain & rets ptr 2 head */
+/*------------------------------------------------------------------*/
+sym_link *
+copyLinkChain (const sym_link *p)
+{
+ sym_link *head, *loop;
+ const sym_link *curr;
+
+ /* note: v_struct and v_struct->fields are not copied! */
+ curr = p;
+ head = loop = (curr ? newLink (p->xclass) : (void *) NULL);
+ while (curr)
+ {
+ memcpy (loop, curr, sizeof (sym_link)); /* copy it */
+ loop->next = (curr->next ? newLink (curr->next->xclass) : (void *) NULL);
+ loop = loop->next;
+ curr = curr->next;
+ }
+
+ return head;
+}
+
+/*------------------------------------------------------------------*/
+/* cleanUpBlock - cleansup the symbol table specified for all the */
+/* symbols in the given block */
+/*------------------------------------------------------------------*/
+void
+cleanUpBlock (bucket ** table, int block)
+{
+ int i;
+ bucket *chain;
+
+ /* go thru the entire table */
+ for (i = 0; i < 256; i++)
+ {
+ for (chain = table[i]; chain; chain = chain->next)
+ {
+ if (chain->block >= block)
+ {
+ deleteSym (table, chain->sym, chain->name);
+ }
+ }
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* cleanUpLevel - cleans up the symbol table specified for all the */
+/* symbols in the given level */
+/*------------------------------------------------------------------*/
+void
+cleanUpLevel (bucket ** table, long level)
+{
+ int i;
+ bucket *chain;
+
+ /* go thru the entire table */
+ for (i = 0; i < 256; i++)
+ {
+ for (chain = table[i]; chain; chain = chain->next)
+ {
+ if (chain->level >= level)
+ {
+ deleteSym (table, chain->sym, chain->name);
+ }
+ }
+ }
+}
+
+symbol *
+getAddrspace (sym_link *type)
+{
+ if (IS_DECL (type))
+ return (DCL_PTR_ADDRSPACE (type));
+ return (SPEC_ADDRSPACE (type));
+}
+
+/*------------------------------------------------------------------*/
+/* computeTypeOr - computes the resultant type from two types */
+/*------------------------------------------------------------------*/
+static sym_link *
+computeTypeOr (sym_link * etype1, sym_link * etype2, sym_link * reType)
+{
+ /* sanity check */
+ assert ((IS_CHAR (etype1) || IS_BOOLEAN (etype1)) &&
+ (IS_CHAR (etype2) || IS_BOOLEAN (etype2)));
+
+ if (SPEC_USIGN (etype1) == SPEC_USIGN (etype2))
+ {
+ SPEC_USIGN (reType) = SPEC_USIGN (etype1);
+ return reType;
+ }
+
+ if (SPEC_USIGN (etype1))
+ {
+ if (IS_LITERAL (etype2) && floatFromVal (valFromType (etype2)) >= 0)
+ SPEC_USIGN (reType) = 1;
+ else
+ {
+ /* promote to int */
+ SPEC_USIGN (reType) = 0;
+ SPEC_NOUN (reType) = V_INT;
+ }
+ }
+ else /* etype1 signed */
+ {
+ if (IS_LITERAL (etype2) && floatFromVal (valFromType (etype2)) <= 127)
+ SPEC_USIGN (reType) = 0;
+ else
+ {
+ /* promote to int */
+ SPEC_USIGN (reType) = 0;
+ SPEC_NOUN (reType) = V_INT;
+ }
+ }
+
+ if (SPEC_USIGN (etype2))
+ {
+ if (IS_LITERAL (etype1) && floatFromVal (valFromType (etype1)) >= 0)
+ SPEC_USIGN (reType) = 1;
+ else
+ {
+ /* promote to int */
+ SPEC_USIGN (reType) = 0;
+ SPEC_NOUN (reType) = V_INT;
+ }
+ }
+ else /* etype2 signed */
+ {
+ if (IS_LITERAL (etype1) && floatFromVal (valFromType (etype1)) <= 127)
+ SPEC_USIGN (reType) = 0;
+ else
+ {
+ /* promote to int */
+ SPEC_USIGN (reType) = 0;
+ SPEC_NOUN (reType) = V_INT;
+ }
+ }
+ return reType;
+}
+
+/*------------------------------------------------------------------*/
+/* computeType - computes the resultant type from two types */
+/*------------------------------------------------------------------*/
+sym_link *
+computeType (sym_link * type1, sym_link * type2, RESULT_TYPE resultType, int op)
+{
+ sym_link *rType;
+ sym_link *reType;
+ sym_link *etype1 = getSpec (type1);
+ sym_link *etype2;
+
+ etype2 = type2 ? getSpec (type2) : type1;
+
+ /* Conditional operator has some special type conversion rules */
+ if (op == ':')
+ {
+ /* If either type is an array, convert to pointer */
+ if (IS_ARRAY(type1))
+ {
+ value * val = aggregateToPointer (valFromType (type1));
+ type1 = val->type;
+ Safe_free (val);
+ etype1 = getSpec (type1);
+ }
+ if (IS_ARRAY(type2))
+ {
+ value * val = aggregateToPointer (valFromType (type2));
+ type2 = val->type;
+ Safe_free (val);
+ etype2 = getSpec (type2);
+ }
+
+ /* If NULL and another pointer, use the non-NULL pointer type. */
+ /* Note that NULL can be defined as either 0 or (void *)0. */
+ if (IS_LITERAL (etype1) &&
+ ((IS_PTR (type1) && IS_VOID (type1->next)) || IS_INTEGRAL (type1)) &&
+ (floatFromVal (valFromType (etype1)) == 0) &&
+ IS_PTR (type2))
+ return copyLinkChain (type2);
+ else if (IS_LITERAL (etype2) &&
+ ((IS_PTR (type2) && IS_VOID (type2->next)) || IS_INTEGRAL (type2)) &&
+ (floatFromVal (valFromType (etype2)) == 0) &&
+ IS_PTR (type1))
+ return copyLinkChain (type1);
+
+ /* If a void pointer, use the void pointer type */
+ else if (IS_PTR(type1) && IS_VOID(type1->next))
+ return copyLinkChain (type1);
+ else if (IS_PTR(type2) && IS_VOID(type2->next))
+ return copyLinkChain (type2);
+
+ /* Otherwise fall through to the general case */
+ }
+
+ /* shift operators have the important type in the left operand */
+ if (op == LEFT_OP || op == RIGHT_OP)
+ rType = copyLinkChain(type1);
+
+ /* if one of them is a pointer or array then that prevails */
+ else if (IS_PTR (type1) || IS_ARRAY (type1))
+ rType = copyLinkChain (type1);
+ else if (IS_PTR (type2) || IS_ARRAY (type2))
+ rType = copyLinkChain (type2);
+
+ /* if one of them is a float then result is a float */
+ /* here we assume that the types passed are okay */
+ /* and can be cast to one another */
+ /* which ever is greater in size */
+ else if (IS_FLOAT (etype1) || IS_FLOAT (etype2))
+ rType = newFloatLink ();
+ /* if both are fixed16x16 then result is float */
+ else if (IS_FIXED16X16 (etype1) && IS_FIXED16X16 (etype2))
+ rType = newFixed16x16Link ();
+ else if (IS_FIXED16X16 (etype1) && IS_FLOAT (etype2))
+ rType = newFloatLink ();
+ else if (IS_FLOAT (etype1) && IS_FIXED16X16 (etype2))
+ rType = newFloatLink ();
+
+ /* if only one of them is a bool variable then the other one prevails */
+ else if (IS_BOOLEAN (etype1) && !IS_BOOLEAN (etype2))
+ {
+ rType = copyLinkChain (type2);
+ }
+ else if (IS_BOOLEAN (etype2) && !IS_BOOLEAN (etype1))
+ {
+ rType = copyLinkChain (type1);
+ }
+
+ /* if both are bitvars choose the larger one */
+ else if (IS_BITVAR (etype1) && IS_BITVAR (etype2))
+ rType = SPEC_BLEN (etype1) >= SPEC_BLEN (etype2) ? copyLinkChain (type1) : copyLinkChain (type2);
+
+ /* if only one of them is a bit variable then the other one prevails */
+ else if (IS_BITVAR (etype1) && !IS_BITVAR (etype2))
+ {
+ rType = copyLinkChain (type2);
+ /* bitfield can have up to 16 bits */
+ if (getSize (etype1) > 1)
+ SPEC_NOUN (getSpec (rType)) = V_INT;
+ }
+ else if (IS_BITVAR (etype2) && !IS_BITVAR (etype1))
+ {
+ rType = copyLinkChain (type1);
+ /* bitfield can have up to 16 bits */
+ if (getSize (etype2) > 1)
+ SPEC_NOUN (getSpec (rType)) = V_INT;
+ }
+
+ else if (bitsForType (type1) > bitsForType (type2))
+ rType = copyLinkChain (type1);
+ else
+ rType = copyLinkChain (type2);
+
+ reType = getSpec (rType);
+
+ /* avoid conflicting types */
+ reType->select.s.b_signed = 0;
+
+ /* if result is a literal then make not so */
+ if (IS_LITERAL (reType))
+ {
+ SPEC_SCLS (reType) = S_REGISTER;
+ SPEC_CONST (reType) = 0;
+ }
+
+ switch (resultType)
+ {
+ case RESULT_TYPE_IFX:
+ if (TARGET_HC08_LIKE)
+ break;
+ //fallthrough
+ case RESULT_TYPE_BOOL:
+ if (op == ':')
+ {
+ SPEC_NOUN (reType) = V_BIT;
+ return rType;
+ }
+ break;
+ case RESULT_TYPE_CHAR:
+ if (IS_BOOL (reType) || IS_BITVAR (reType))
+ {
+ SPEC_NOUN (reType) = V_CHAR;
+ SPEC_SCLS (reType) = 0;
+ SPEC_USIGN (reType) = 0;
+ return rType;
+ }
+ break;
+ case RESULT_TYPE_INT:
+ case RESULT_TYPE_NONE:
+ case RESULT_TYPE_OTHER:
+ case RESULT_TYPE_GPTR:
+ if (!IS_SPEC (rType))
+ {
+ return rType;
+ }
+ if (IS_BOOLEAN (reType))
+ {
+ SPEC_NOUN (reType) = V_CHAR;
+ SPEC_SCLS (reType) = 0;
+ SPEC_USIGN (reType) = 0;
+ return rType;
+ }
+ else if (IS_BITFIELD (reType))
+ {
+ /* could be smarter, but it depends on the op */
+ /* this is for the worst case: a multiplication of 4 * 4 bit */
+ SPEC_NOUN (reType) = SPEC_BLEN (reType) <= 4 ? V_CHAR : V_INT;
+ SPEC_SCLS (reType) = 0;
+ SPEC_USIGN (reType) = 0;
+ return rType;
+ }
+ else if (IS_CHAR (reType))
+ {
+ /* promotion of some special cases */
+ switch (op)
+ {
+ case '|':
+ case '^':
+ return computeTypeOr (etype1, etype2, reType);
+ case '&':
+ case BITWISEAND:
+ if (SPEC_USIGN (etype1) != SPEC_USIGN (etype2))
+ {
+ SPEC_USIGN (reType) = 1;
+ return rType;
+ }
+ break;
+ case '*':
+ SPEC_NOUN (reType) = V_INT;
+ SPEC_USIGN (reType) = 0;
+ return rType;
+ case '/':
+ /* if both are unsigned char then no promotion required */
+ if (!(SPEC_USIGN (etype1) && SPEC_USIGN (etype2)))
+ {
+ SPEC_NOUN (reType) = V_INT;
+ SPEC_USIGN (reType) = 0;
+ return rType;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* SDCC's sign promotion:
+ - if one or both operands are unsigned, the resultant type will be unsigned
+ (except char, see below)
+ - if an operand is promoted to a larger type (char -> int, int -> long),
+ the larger type will be signed
+
+ SDCC tries hard to avoid promotion to int and does 8 bit calculation as
+ much as possible. We're leaving ISO IEC 9899 here and have to extrapolate
+ the standard. The standard demands, that the result has to be the same
+ "as if" the promotion would have been performed:
+
+ - if the result of an operation with two char's is promoted to a
+ larger type, the result will be signed.
+
+ More sophisticated are these:
+ - if the result of an operation with two char's is a char again,
+ the result will only then be unsigned, if both operands are
+ unsigned. In all other cases the result will be signed.
+
+ This seems to be contradictionary to the first two rules, but it makes
+ real sense (all types are char's):
+
+ A signed char can be negative; this must be preserved in the result
+ -1 * 100 = -100;
+
+ Only if both operands are unsigned it's safe to make the result
+ unsigned; this helps to avoid overflow:
+ 2 * 100 = 200;
+
+ - ToDo: document '|', '^' and '&'
+
+ Homework: - why is (200 * 200 < 0) true?
+ - why is { char l = 200, r = 200; (r * l > 0) } true?
+ */
+
+ if (!IS_FLOAT (reType) && ((SPEC_USIGN (etype1)
+ /* if this operand is promoted to a larger type,
+ then it will be promoted to a signed type */
+ && !(bitsForType (etype1) < bitsForType (reType))
+ /* char require special handling */
+ && !IS_CHAR (etype1)) || /* same for 2nd operand */
+ (SPEC_USIGN (etype2) && !(bitsForType (etype2) < bitsForType (reType)) && !IS_CHAR (etype2)) || /* if both are 'unsigned char' and not promoted
+ let the result be unsigned too */
+ (SPEC_USIGN (etype1)
+ && SPEC_USIGN (etype2) && IS_CHAR (etype1) && IS_CHAR (etype2) && IS_CHAR (reType))))
+ SPEC_USIGN (reType) = 1;
+ else
+ SPEC_USIGN (reType) = 0;
+
+ return rType;
+}
+
+/*------------------------------------------------------------------*/
+/* compareFuncType - compare function prototypes */
+/*------------------------------------------------------------------*/
+int
+compareFuncType (sym_link * dest, sym_link * src)
+{
+ value *exargs, *acargs;
+ value *checkValue;
+ int argCnt = 0;
+ int i;
+
+ /* if not type then some kind of error */
+ if (!dest || !src)
+ return 0;
+
+ /* check the return value type */
+ if (compareType (dest->next, src->next) <= 0)
+ return 0;
+
+ /* Really, reentrant should match regardless of argCnt, but */
+ /* this breaks some existing code (the fp lib functions). If */
+ /* the first argument is always passed the same way, this */
+ /* lax checking is ok (but may not be true for in future ports) */
+ if (IFFUNC_ISREENT (dest) != IFFUNC_ISREENT (src) && argCnt > 1)
+ {
+ //printf("argCnt = %d\n",argCnt);
+ return 0;
+ }
+
+ if (IFFUNC_ISWPARAM (dest) != IFFUNC_ISWPARAM (src))
+ {
+ return 0;
+ }
+
+ if (IFFUNC_ISSHADOWREGS (dest) != IFFUNC_ISSHADOWREGS (src))
+ {
+ return 0;
+ }
+
+ if (IFFUNC_ISZ88DK_FASTCALL (dest) != IFFUNC_ISZ88DK_FASTCALL (src) ||
+ IFFUNC_ISZ88DK_CALLEE (dest) != IFFUNC_ISZ88DK_CALLEE (src))
+ return 0;
+
+ for (i = 0; i < 9; i++)
+ if (dest->funcAttrs.preserved_regs[i] > src->funcAttrs.preserved_regs[i])
+ return 0;
+
+ /* compare register bank */
+ if (FUNC_REGBANK (dest) != FUNC_REGBANK (src))
+ { /* except for ISR's whose prototype need not match
+ since they are the top of a call-tree and
+ the prototype is only necessary for its vector in main */
+ if (!IFFUNC_ISISR (dest) || !IFFUNC_ISISR (src))
+ {
+ return 0;
+ }
+ }
+
+ /* compare expected args with actual args */
+ exargs = FUNC_ARGS (dest);
+ acargs = FUNC_ARGS (src);
+
+ /* for all the expected args do */
+ for (argCnt = 1; exargs && acargs; exargs = exargs->next, acargs = acargs->next, argCnt++)
+ {
+ /* If the actual argument is an array, any prototype
+ * will have modified it to a pointer. Duplicate that
+ * change here.
+ */
+ if (IS_AGGREGATE (acargs->type))
+ {
+ checkValue = copyValue (acargs);
+ aggregateToPointer (checkValue);
+ }
+ else
+ {
+ checkValue = acargs;
+ }
+ if (IFFUNC_ISREENT (dest) && compareType (exargs->type, checkValue->type) <= 0)
+ {
+ return 0;
+ }
+ if (!IFFUNC_ISREENT (dest) && compareTypeExact (exargs->type, checkValue->type, 1) <= 0)
+ {
+ return 0;
+ }
+ }
+
+ /* if one them ended we have a problem */
+ if ((exargs && !acargs && !IS_VOID (exargs->type)) || (!exargs && acargs && !IS_VOID (acargs->type)))
+ {
+ return 0;
+ }
+
+ return 1;
+}
+
+int
+comparePtrType (sym_link *dest, sym_link *src, bool bMustCast)
+{
+ int res;
+
+ if (getAddrspace (src->next) != getAddrspace (dest->next))
+ bMustCast = 1;
+
+ if (IS_VOID (src->next) && IS_VOID (dest->next))
+ return bMustCast ? -1 : 1;
+ if ((IS_VOID (src->next) && !IS_VOID (dest->next)) || (!IS_VOID (src->next) && IS_VOID (dest->next)))
+ return -1;
+ res = compareType (dest->next, src->next);
+
+ /* All function pointers can be cast (6.6 in the ISO C11 standard) TODO: What about address spaces? */
+ if (res == 0 && !bMustCast && IS_DECL (src) && IS_FUNC (src->next) && IS_DECL (dest) && IS_FUNC (dest->next))
+ return -1;
+ else if (res == 1)
+ return bMustCast ? -1 : 1;
+ else if (res == -2)
+ return bMustCast ? -1 : -2;
+ else
+ return res;
+}
+
+/*--------------------------------------------------------------------*/
+/* compareType - will do type check return 1 if match, 0 if no match, */
+/* -1 if castable, -2 if only signedness differs */
+/*--------------------------------------------------------------------*/
+int
+compareType (sym_link *dest, sym_link *src)
+{
+ if (!dest && !src)
+ return 1;
+
+ if (dest && !src)
+ return 0;
+
+ if (src && !dest)
+ return 0;
+
+ /* if dest is a declarator then */
+ if (IS_DECL (dest))
+ {
+ if (IS_DECL (src))
+ {
+ if (IS_GENPTR (dest) && IS_GENPTR (src))
+ {
+ /* banked function pointer */
+ if (IS_FUNC (src->next) && IS_VOID (dest->next))
+ return -1;
+ if (IS_FUNC (dest->next) && IS_VOID (src->next))
+ return -1;
+ return comparePtrType (dest, src, FALSE);
+ }
+
+ if (DCL_TYPE (src) == DCL_TYPE (dest))
+ {
+ if (IS_FUNC (src))
+ {
+ return compareFuncType (dest, src);
+ }
+ return comparePtrType (dest, src, FALSE);
+ }
+ if (IS_PTR (dest) && IS_GENPTR (src) && IS_VOID (src->next))
+ {
+ return -1;
+ }
+ if (IS_PTR (src) && (IS_GENPTR (dest) || ((DCL_TYPE (src) == POINTER) && (DCL_TYPE (dest) == IPOINTER))))
+ {
+ return comparePtrType (dest, src, TRUE);
+ }
+ if (IS_PTR (dest) && IS_ARRAY (src))
+ {
+ value *val = aggregateToPointer (valFromType (src));
+ int res = compareType (dest, val->type);
+ Safe_free (val->type);
+ Safe_free (val);
+ return res;
+ }
+ if (IS_PTR (dest) && IS_FUNC (dest->next) && IS_FUNC (src))
+ {
+ return compareType (dest->next, src);
+ }
+ if (IS_PTR (dest) && IS_VOID (dest->next) && IS_FUNC (src))
+ return -1;
+
+ return 0;
+ }
+ else if (IS_PTR (dest) && IS_INTEGRAL (src))
+ return -1;
+ else
+ return 0;
+ }
+
+ if (IS_PTR (src) && IS_VOID (dest))
+ return -1;
+
+ /* if one is a specifier and the other is not */
+ if ((IS_SPEC (src) && !IS_SPEC (dest)) || (IS_SPEC (dest) && !IS_SPEC (src)))
+ return 0;
+
+ /* if one of them is a void then ok */
+ if (SPEC_NOUN (dest) == V_VOID && SPEC_NOUN (src) != V_VOID)
+ return -1;
+
+ if (SPEC_NOUN (dest) != V_VOID && SPEC_NOUN (src) == V_VOID)
+ return -1;
+
+ if (SPEC_NOUN (src) == V_BBITFIELD && SPEC_NOUN (dest) != V_BBITFIELD || SPEC_NOUN (src) != V_BBITFIELD && SPEC_NOUN (dest) == V_BBITFIELD)
+ return -1;
+
+ /* if they are both bitfields then if the lengths
+ and starts don't match */
+ if (IS_BITFIELD (dest) && IS_BITFIELD (src) && (SPEC_BLEN (dest) != SPEC_BLEN (src) || SPEC_BSTR (dest) != SPEC_BSTR (src)))
+ return -1;
+
+ /* it is a specifier */
+ if (SPEC_NOUN (dest) != SPEC_NOUN (src))
+ {
+ if ((SPEC_USIGN (dest) == SPEC_USIGN (src)) &&
+ IS_INTEGRAL (dest) && IS_INTEGRAL (src) &&
+ /* I would prefer
+ bitsForType (dest) == bitsForType (src))
+ instead of the next two lines, but the regression tests fail with
+ them; I guess it's a problem with replaceCheaperOp */
+ (getSize (dest) == getSize (src)) &&
+ (IS_BOOLEAN (dest) == IS_BOOLEAN (src)))
+ return 1;
+ else if (IS_ARITHMETIC (dest) && IS_ARITHMETIC (src))
+ return -1;
+ else
+ return 0;
+ }
+ else if (IS_STRUCT (dest))
+ {
+ if (SPEC_STRUCT (dest) != SPEC_STRUCT (src))
+ return 0;
+ else
+ return 1;
+ }
+ if (SPEC_LONG (dest) != SPEC_LONG (src))
+ return -1;
+
+ if (SPEC_LONGLONG (dest) != SPEC_LONGLONG (src))
+ return -1;
+
+ if (SPEC_USIGN (dest) != SPEC_USIGN (src))
+ return -2;
+
+ return 1;
+}
+
+/*--------------------------------------------------------------------*/
+/* compareTypeExact - will do type check return 1 if match exactly */
+/*--------------------------------------------------------------------*/
+int
+compareTypeExact (sym_link * dest, sym_link * src, long level)
+{
+ STORAGE_CLASS srcScls, destScls;
+
+ if (!dest && !src)
+ return 1;
+
+ if (dest && !src)
+ return 0;
+
+ if (src && !dest)
+ return 0;
+
+ /* if dest is a declarator then */
+ if (IS_DECL (dest))
+ {
+ if (IS_DECL (src))
+ {
+ if (DCL_TYPE (src) == DCL_TYPE (dest))
+ {
+ if ((DCL_TYPE (src) == ARRAY) && (DCL_ELEM (src) != DCL_ELEM (dest)))
+ return 0;
+ if (DCL_PTR_CONST (src) != DCL_PTR_CONST (dest))
+ return 0;
+ if (DCL_PTR_VOLATILE (src) != DCL_PTR_VOLATILE (dest))
+ return 0;
+ if (IS_FUNC (src))
+ {
+ value *exargs, *acargs, *checkValue;
+
+ /* verify function return type */
+ if (!compareTypeExact (dest->next, src->next, -1))
+ return 0;
+ if (FUNC_ISISR (dest) != FUNC_ISISR (src))
+ return 0;
+ if (FUNC_REGBANK (dest) != FUNC_REGBANK (src))
+ return 0;
+ if (IFFUNC_ISNAKED (dest) != IFFUNC_ISNAKED (src))
+ return 0;
+#if 0
+ if (IFFUNC_ISREENT (dest) != IFFUNC_ISREENT (src) && argCnt > 1)
+ return 0;
+#endif
+
+ /* compare expected args with actual args */
+ exargs = FUNC_ARGS (dest);
+ acargs = FUNC_ARGS (src);
+
+ /* for all the expected args do */
+ for (; exargs && acargs; exargs = exargs->next, acargs = acargs->next)
+ {
+ //checkTypeSanity(acargs->etype, acargs->name);
+
+ if (IS_AGGREGATE (acargs->type))
+ {
+ checkValue = copyValue (acargs);
+ aggregateToPointer (checkValue);
+ }
+ else
+ checkValue = acargs;
+
+#if 0
+ if (!compareTypeExact (exargs->type, checkValue->type, -1))
+ return 0;
+#endif
+ }
+
+ /* if one them ended we have a problem */
+ if ((exargs && !acargs && !IS_VOID (exargs->type)) || (!exargs && acargs && !IS_VOID (acargs->type)))
+ return 0;
+ return 1;
+ }
+ return compareTypeExact (dest->next, src->next, level);
+ }
+ return 0;
+ }
+ return 0;
+ }
+
+ /* if one is a specifier and the other is not */
+ if ((IS_SPEC (src) && !IS_SPEC (dest)) || (IS_SPEC (dest) && !IS_SPEC (src)))
+ return 0;
+
+ /* if they have a different noun */
+ if (SPEC_NOUN (dest) != SPEC_NOUN (src))
+ return 0;
+
+ /* if they are both bitfields then if the lengths
+ and starts don't match */
+ if (IS_BITFIELD (dest) && IS_BITFIELD (src) && (SPEC_BLEN (dest) != SPEC_BLEN (src) || SPEC_BSTR (dest) != SPEC_BSTR (src)))
+ return 0;
+
+ if (IS_INTEGRAL (dest))
+ {
+ /* signedness must match */
+ if (SPEC_USIGN (dest) != SPEC_USIGN (src))
+ return 0;
+ /* size must match */
+ if (SPEC_SHORT (dest) != SPEC_SHORT (src))
+ return 0;
+ if (SPEC_LONG (dest) != SPEC_LONG (src))
+ return 0;
+ if (SPEC_LONGLONG (dest) != SPEC_LONGLONG (src))
+ return 0;
+ }
+
+ if (IS_STRUCT (dest))
+ {
+ if (SPEC_STRUCT (dest) != SPEC_STRUCT (src))
+ return 0;
+ }
+
+ if (SPEC_CONST (dest) != SPEC_CONST (src))
+ return 0;
+ if (SPEC_VOLATILE (dest) != SPEC_VOLATILE (src))
+ return 0;
+ if (SPEC_STAT (dest) != SPEC_STAT (src))
+ return 0;
+ if (SPEC_ABSA (dest) != SPEC_ABSA (src))
+ return 0;
+ if (SPEC_ABSA (dest) && SPEC_ADDR (dest) != SPEC_ADDR (src))
+ return 0;
+
+ destScls = SPEC_SCLS (dest);
+ srcScls = SPEC_SCLS (src);
+
+ /* Compensate for const to const code change in checkSClass() */
+ if (((!level) & port->mem.code_ro) && SPEC_CONST (dest))
+ {
+ if (srcScls == S_CODE && destScls == S_FIXED)
+ destScls = S_CODE;
+ if (destScls == S_CODE && srcScls == S_FIXED)
+ srcScls = S_CODE;
+ }
+
+ /* compensate for allocGlobal() */
+ if ((srcScls == S_FIXED || srcScls == S_AUTO) &&
+ (port->mem.default_globl_map == xdata) && (destScls == S_XDATA) && (level <= 0))
+ {
+ srcScls = S_XDATA;
+ }
+
+ if ((level > 0) && !SPEC_STAT (dest))
+ {
+ /* Compensate for hack-o-matic in checkSClass() */
+ if (options.stackAuto || (currFunc && IFFUNC_ISREENT (currFunc->type)))
+ {
+ if (destScls == S_FIXED)
+ destScls = (options.useXstack ? S_XSTACK : S_STACK);
+ if (srcScls == S_FIXED)
+ srcScls = (options.useXstack ? S_XSTACK : S_STACK);
+ }
+ else if (TARGET_IS_DS390 || TARGET_IS_DS400 || options.useXstack || TARGET_IS_HC08 || TARGET_IS_S08)
+ {
+ if (destScls == S_FIXED)
+ destScls = S_XDATA;
+ if (srcScls == S_FIXED)
+ srcScls = S_XDATA;
+ }
+ }
+
+ if (srcScls != destScls)
+ {
+#if 0
+ printf ("level = %ld:%ld\n", level / LEVEL_UNIT, level % LEVEL_UNIT);
+ printf ("SPEC_SCLS (src) = %d, SPEC_SCLS (dest) = %d\n", SPEC_SCLS (src), SPEC_SCLS (dest));
+ printf ("srcScls = %d, destScls = %d\n", srcScls, destScls);
+#endif
+ return 0;
+ }
+
+ return 1;
+}
+
+/*---------------------------------------------------------------------------*/
+/* compareTypeInexact - will do type check return 1 if representation is same. */
+/* Useful for redundancy elimination. */
+/*---------------------------------------------------------------------------*/
+int
+compareTypeInexact (sym_link *dest, sym_link *src)
+{
+ if (!dest && !src)
+ return 1;
+
+ if (dest && !src)
+ return 0;
+
+ if (src && !dest)
+ return 0;
+
+ if (IS_BITFIELD (dest) != IS_BITFIELD (src))
+ return 0;
+
+ if (IS_BITFIELD (dest) && IS_BITFIELD (src) && (SPEC_BLEN (dest) != SPEC_BLEN (src) || SPEC_BSTR (dest) != SPEC_BSTR (src)))
+ return 0;
+
+ if (getSize (dest) != getSize (src))
+ return 0;
+
+ return 1;
+}
+
+/*------------------------------------------------------------------*/
+/* inCalleeSaveList - return 1 if found in callee save list */
+/*------------------------------------------------------------------*/
+static int
+calleeCmp (void *p1, void *p2)
+{
+ return (strcmp ((char *) p1, (char *) (p2)) == 0);
+}
+
+bool
+inCalleeSaveList (char *s)
+{
+ if (options.all_callee_saves)
+ return 1;
+ return isinSetWith (options.calleeSavesSet, s, calleeCmp);
+}
+
+/*-----------------------------------------------------------------*/
+/* aggregateToPointer: change an aggregate type function */
+/* argument to a pointer to that type. */
+/*-----------------------------------------------------------------*/
+value *
+aggregateToPointer (value * val)
+{
+ if (IS_AGGREGATE (val->type))
+ {
+ /* if this is a structure */
+ if (IS_STRUCT (val->type))
+ {
+ werror (E_STRUCT_AS_ARG, val->name);
+ return NULL;
+ }
+
+ /* change to a pointer depending on the */
+ /* storage class specified */
+ switch (SPEC_SCLS (val->etype))
+ {
+ case S_IDATA:
+ DCL_TYPE (val->type) = IPOINTER;
+ break;
+ case S_PDATA:
+ DCL_TYPE (val->type) = PPOINTER;
+ break;
+ case S_FIXED:
+ if (SPEC_OCLS (val->etype))
+ {
+ DCL_TYPE (val->type) = PTR_TYPE (SPEC_OCLS (val->etype));
+ }
+ else
+ { // this happens for (external) function parameters
+ DCL_TYPE (val->type) = port->unqualified_pointer;
+ }
+ break;
+ case S_AUTO:
+ DCL_TYPE (val->type) = PTR_TYPE (SPEC_OCLS (val->etype));
+ break;
+ case S_DATA:
+ case S_REGISTER:
+ DCL_TYPE (val->type) = POINTER;
+ break;
+ case S_CODE:
+ DCL_TYPE (val->type) = CPOINTER;
+ break;
+ case S_XDATA:
+ DCL_TYPE (val->type) = FPOINTER;
+ break;
+ case S_EEPROM:
+ DCL_TYPE (val->type) = EEPPOINTER;
+ break;
+ default:
+ DCL_TYPE (val->type) = port->unqualified_pointer;
+ }
+
+ /* is there is a symbol associated then */
+ /* change the type of the symbol as well */
+ if (val->sym)
+ {
+ val->sym->type = copyLinkChain (val->type);
+ val->sym->etype = getSpec (val->sym->type);
+ }
+ }
+ return val;
+}
+
+/*------------------------------------------------------------------*/
+/* checkFunction - does all kinds of check on a function */
+/*------------------------------------------------------------------*/
+int
+checkFunction (symbol * sym, symbol * csym)
+{
+ value *exargs, *acargs;
+ value *checkValue;
+ int argCnt = 0;
+
+ if (getenv ("DEBUG_SANITY"))
+ {
+ fprintf (stderr, "checkFunction: %s ", sym->name);
+ }
+
+ if (!IS_FUNC (sym->type))
+ {
+ werrorfl (sym->fileDef, sym->lineDef, E_SYNTAX_ERROR, sym->name);
+ return 0;
+ }
+
+ /* move function specifier from return type to function attributes */
+ if (IS_INLINE (sym->etype))
+ {
+ SPEC_INLINE (sym->etype) = 0;
+ FUNC_ISINLINE (sym->type) = 1;
+ }
+ if (IS_NORETURN (sym->etype))
+ {
+ SPEC_NORETURN (sym->etype) = 0;
+ FUNC_ISNORETURN (sym->type) = 1;
+ }
+
+ /* make sure the type is complete and sane */
+ checkTypeSanity (sym->etype, sym->name);
+
+ /* if not type then some kind of error */
+ if (!sym->type)
+ return 0;
+
+ /* if the function has no type then make it return int */
+ if (!sym->type->next)
+ sym->type->next = sym->etype = newIntLink ();
+
+ /* function cannot return aggregate */
+ if (IS_AGGREGATE (sym->type->next))
+ {
+ werrorfl (sym->fileDef, sym->lineDef, E_FUNC_AGGR, sym->name);
+ return 0;
+ }
+
+ /* check if this function is defined as calleeSaves
+ then mark it as such */
+ FUNC_CALLEESAVES (sym->type) = inCalleeSaveList (sym->name);
+
+ /* if interrupt service routine */
+ /* then it cannot have arguments */
+ if (IFFUNC_ARGS (sym->type) && FUNC_ISISR (sym->type))
+ {
+ if (!IS_VOID (FUNC_ARGS (sym->type)->type))
+ {
+ werrorfl (sym->fileDef, sym->lineDef, E_INT_ARGS, sym->name);
+ FUNC_ARGS (sym->type) = NULL;
+ }
+ }
+
+ if (IFFUNC_ISSHADOWREGS (sym->type) && !FUNC_ISISR (sym->type))
+ {
+ werrorfl (sym->fileDef, sym->lineDef, E_SHADOWREGS_NO_ISR, sym->name);
+ }
+
+ for (argCnt = 1, acargs = FUNC_ARGS (sym->type); acargs; acargs = acargs->next, argCnt++)
+ {
+ if (!acargs->sym)
+ {
+ // this can happen for reentrant functions
+ werrorfl (sym->fileDef, sym->lineDef, E_PARAM_NAME_OMITTED, sym->name, argCnt);
+ // the show must go on: synthesize a name and symbol
+ SNPRINTF (acargs->name, sizeof (acargs->name), "_%s_PARM_%d", sym->name, argCnt);
+ acargs->sym = newSymbol (acargs->name, 1);
+ SPEC_OCLS (acargs->etype) = istack;
+ acargs->sym->type = copyLinkChain (acargs->type);
+ acargs->sym->etype = getSpec (acargs->sym->type);
+ acargs->sym->_isparm = 1;
+ strncpyz (acargs->sym->rname, acargs->name, sizeof (acargs->sym->rname));
+ }
+ else if (strcmp (acargs->sym->name, acargs->sym->rname) == 0)
+ {
+ // synthesized name
+ werrorfl (sym->fileDef, sym->lineDef, E_PARAM_NAME_OMITTED, sym->name, argCnt);
+ }
+ }
+ argCnt--;
+
+ /*JCF: Mark the register bank as used */
+ RegBankUsed[FUNC_REGBANK (sym->type)] = 1;
+
+ if (!csym && !(csym = findSymWithLevel (SymbolTab, sym)))
+ return 1; /* not defined nothing more to check */
+
+ /* check if body already present */
+ if (csym && IFFUNC_HASBODY (csym->type))
+ {
+ werrorfl (sym->fileDef, sym->lineDef, E_FUNC_BODY, sym->name);
+ return 0;
+ }
+
+ /* check the return value type */
+ if (compareType (csym->type, sym->type) <= 0)
+ {
+ werrorfl (sym->fileDef, sym->lineDef, E_PREV_DECL_CONFLICT, csym->name, "type", csym->fileDef, csym->lineDef);
+ printFromToType (csym->type, sym->type);
+ return 0;
+ }
+
+ if (FUNC_ISISR (csym->type) != FUNC_ISISR (sym->type))
+ werrorfl (sym->fileDef, sym->lineDef, E_PREV_DECL_CONFLICT, csym->name, "interrupt", csym->fileDef, csym->lineDef);
+
+ /* I don't think this is necessary for interrupts. An isr is a */
+ /* root in the calling tree. */
+ if ((FUNC_REGBANK (csym->type) != FUNC_REGBANK (sym->type)) && (!FUNC_ISISR (sym->type)))
+ werrorfl (sym->fileDef, sym->lineDef, E_PREV_DECL_CONFLICT, csym->name, "using", csym->fileDef, csym->lineDef);
+
+ if (IFFUNC_ISNAKED (csym->type) != IFFUNC_ISNAKED (sym->type))
+ {
+// disabled since __naked has no influence on the calling convention
+// werror (E_PREV_DECL_CONFLICT, csym->name, "__naked", csym->fileDef, csym->lineDef);
+ FUNC_ISNAKED (sym->type) = 1;
+ }
+
+ if (FUNC_BANKED (csym->type) || FUNC_BANKED (sym->type))
+ {
+ if (FUNC_NONBANKED (csym->type) || FUNC_NONBANKED (sym->type))
+ {
+ werrorfl (sym->fileDef, sym->lineDef, W_BANKED_WITH_NONBANKED);
+ FUNC_BANKED (sym->type) = 0;
+ FUNC_NONBANKED (sym->type) = 1;
+ }
+ else
+ {
+ FUNC_BANKED (sym->type) = 1;
+ }
+ }
+ else
+ {
+ if (FUNC_NONBANKED (csym->type) || FUNC_NONBANKED (sym->type))
+ {
+ FUNC_NONBANKED (sym->type) = 1;
+ }
+ }
+
+ /* Really, reentrant should match regardless of argCnt, but */
+ /* this breaks some existing code (the fp lib functions). If */
+ /* the first argument is always passed the same way, this */
+ /* lax checking is ok (but may not be true for in future backends) */
+ if (IFFUNC_ISREENT (csym->type) != IFFUNC_ISREENT (sym->type) && argCnt > 1)
+ {
+ //printf("argCnt = %d\n",argCnt);
+ werrorfl (sym->fileDef, sym->lineDef, E_PREV_DECL_CONFLICT, csym->name, "reentrant", csym->fileDef, csym->lineDef);
+ }
+
+ if (IFFUNC_ISWPARAM (csym->type) != IFFUNC_ISWPARAM (sym->type))
+ werrorfl (sym->fileDef, sym->lineDef, E_PREV_DECL_CONFLICT, csym->name, "wparam", csym->fileDef, csym->lineDef);
+
+ if (IFFUNC_ISSHADOWREGS (csym->type) != IFFUNC_ISSHADOWREGS (sym->type))
+ werrorfl (sym->fileDef, sym->lineDef, E_PREV_DECL_CONFLICT, csym->name, "shadowregs", csym->fileDef, csym->lineDef);
+
+ /* compare expected args with actual args */
+ exargs = FUNC_ARGS (csym->type);
+ acargs = FUNC_ARGS (sym->type);
+
+ /* for all the expected args do */
+ for (argCnt = 1; exargs && acargs; exargs = exargs->next, acargs = acargs->next, argCnt++)
+ {
+ if (getenv ("DEBUG_SANITY"))
+ {
+ fprintf (stderr, "checkFunction: %s ", exargs->name);
+ }
+ /* make sure the type is complete and sane */
+ checkTypeSanity (exargs->etype, exargs->name);
+
+ /* If the actual argument is an array, any prototype
+ * will have modified it to a pointer. Duplicate that
+ * change here.
+ */
+ if (IS_AGGREGATE (acargs->type))
+ {
+ checkValue = copyValue (acargs);
+ aggregateToPointer (checkValue);
+ }
+ else
+ {
+ checkValue = acargs;
+ }
+
+ if (compareType (exargs->type, checkValue->type) <= 0)
+ {
+ werror (E_ARG_TYPE, argCnt);
+ printFromToType (exargs->type, checkValue->type);
+ return 0;
+ }
+ }
+
+ /* if one of them ended we have a problem */
+ if ((exargs && !acargs && !IS_VOID (exargs->type)) || (!exargs && acargs && !IS_VOID (acargs->type)))
+ werror (E_ARG_COUNT);
+
+ /* replace with this definition */
+ sym->cdef = csym->cdef;
+ deleteSym (SymbolTab, csym, csym->name);
+ deleteFromSeg (csym);
+ addSym (SymbolTab, sym, sym->name, sym->level, sym->block, 1);
+ if (IS_EXTERN (csym->etype) && !IS_EXTERN (sym->etype))
+ {
+ SPEC_EXTR (sym->etype) = 1;
+ addSet (&publics, sym);
+ }
+
+ SPEC_STAT (sym->etype) |= SPEC_STAT (csym->etype);
+ if (SPEC_STAT (sym->etype) && SPEC_EXTR (sym->etype))
+ {
+ werrorfl (sym->fileDef, sym->lineDef, E_TWO_OR_MORE_STORAGE_CLASSES, sym->name);
+ }
+
+ return 1;
+}
+
+/*------------------------------------------------------------------*/
+/* cdbStructBlock - calls struct printing for a blocks */
+/*------------------------------------------------------------------*/
+void
+cdbStructBlock (int block)
+{
+ int i;
+ bucket **table = StructTab;
+ bucket *chain;
+
+ /* go thru the entire table */
+ for (i = 0; i < 256; i++)
+ {
+ for (chain = table[i]; chain; chain = chain->next)
+ {
+ if (chain->block >= block)
+ {
+ if (debugFile)
+ debugFile->writeType ((structdef *) chain->sym, chain->block, 0, NULL);
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* processFuncPtrArgs - does some processing with args of func ptrs*/
+/*-----------------------------------------------------------------*/
+void
+processFuncPtrArgs (sym_link * funcType)
+{
+ value *val = FUNC_ARGS (funcType);
+
+ /* if it is void then remove parameters */
+ if (val && IS_VOID (val->type))
+ {
+ FUNC_ARGS (funcType) = NULL;
+ return;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* processFuncArgs - does some processing with function args */
+/*-----------------------------------------------------------------*/
+void
+processFuncArgs (symbol *func)
+{
+ value *val;
+ int pNum = 1;
+ sym_link *funcType = func->type;
+
+ if (getenv ("SDCC_DEBUG_FUNCTION_POINTERS"))
+ fprintf (stderr, "SDCCsymt.c:processFuncArgs(%s)\n", func->name);
+
+ /* find the function declaration within the type */
+ while (funcType && !IS_FUNC (funcType))
+ funcType = funcType->next;
+
+ /* if this function has variable argument list */
+ /* then make the function a reentrant one */
+ if (IFFUNC_HASVARARGS (funcType) || (options.stackAuto && !func->cdef))
+ FUNC_ISREENT (funcType) = 1;
+
+ /* check if this function is defined as calleeSaves
+ then mark it as such */
+ FUNC_CALLEESAVES (funcType) = inCalleeSaveList (func->name);
+
+ /* loop thru all the arguments */
+ val = FUNC_ARGS (funcType);
+
+ /* if it is void then remove parameters */
+ if (val && IS_VOID (val->type))
+ {
+ FUNC_ARGS (funcType) = NULL;
+ return;
+ }
+
+ /* reset regparm for the port */
+ (*port->reset_regparms) (funcType);
+
+ /* if any of the arguments is an aggregate */
+ /* change it to pointer to the same type */
+ while (val)
+ {
+ int argreg = 0;
+ struct dbuf_s dbuf;
+
+ if (val->sym && val->sym->name)
+ for (value *val2 = val->next; val2; val2 = val2->next)
+ if (val2->sym && val2->sym->name && !strcmp (val->sym->name, val2->sym->name))
+ werror (E_DUPLICATE_PARAMTER_NAME, val->sym->name, func->name);
+
+ dbuf_init (&dbuf, 128);
+ dbuf_printf (&dbuf, "%s parameter %d", func->name, pNum);
+ checkTypeSanity (val->etype, dbuf_c_str (&dbuf));
+ dbuf_destroy (&dbuf);
+
+ if (IS_AGGREGATE (val->type))
+ {
+ aggregateToPointer (val);
+ }
+
+ /* mark it as a register parameter if
+ the function does not have VA_ARG
+ and as port dictates */
+ if (!IFFUNC_HASVARARGS (funcType) && (argreg = (*port->reg_parm) (val->type, FUNC_ISREENT (funcType))))
+ {
+ SPEC_REGPARM (val->etype) = 1;
+ SPEC_ARGREG (val->etype) = argreg;
+
+ /* is there is a symbol associated then */
+ /* change the type of the symbol as well */
+ if (val->sym)
+ {
+ SPEC_REGPARM (val->sym->etype) = 1;
+ SPEC_ARGREG (val->sym->etype) = argreg;
+ }
+ }
+ else if (IFFUNC_ISREENT (funcType))
+ {
+ FUNC_HASSTACKPARM (funcType) = 1;
+ }
+
+ val = val->next;
+ pNum++;
+ }
+
+ /* if this is an internal generated function call */
+ if (func->cdef)
+ {
+ /* ignore --stack-auto for this one, we don't know how it is compiled */
+ /* simply trust on --int-long-reent or --float-reent */
+ if (IFFUNC_ISREENT (funcType))
+ {
+ return;
+ }
+ }
+ else
+ {
+ /* if this function is reentrant or */
+ /* automatics r 2b stacked then nothing */
+ if (IFFUNC_ISREENT (funcType) || options.stackAuto)
+ return;
+ }
+
+ val = FUNC_ARGS (funcType);
+ pNum = 1;
+ while (val)
+ {
+ /* if a symbolname is not given */
+ /* synthesize a variable name */
+ if (!val->sym)
+ {
+ SNPRINTF (val->name, sizeof (val->name), "_%s_PARM_%d", func->name, pNum++);
+ val->sym = newSymbol (val->name, 1);
+ val->sym->type = copyLinkChain (val->type);
+ val->sym->etype = getSpec (val->sym->type);
+ val->sym->_isparm = 1;
+ if (!defaultOClass (val->sym))
+ SPEC_OCLS (val->sym->etype) = port->mem.default_local_map;
+ SPEC_OCLS (val->etype) = SPEC_OCLS (val->sym->etype);
+ strncpyz (val->sym->rname, val->name, sizeof (val->sym->rname));
+ addSymChain (&val->sym);
+ }
+ else /* symbol name given create synth name */
+ {
+ SNPRINTF (val->name, sizeof (val->name), "_%s_PARM_%d", func->name, pNum++);
+ strncpyz (val->sym->rname, val->name, sizeof (val->sym->rname));
+ val->sym->_isparm = 1;
+ if (!defaultOClass (val->sym))
+ SPEC_OCLS (val->sym->etype) = port->mem.default_local_map;
+ SPEC_OCLS (val->etype) = SPEC_OCLS (val->sym->etype);
+ }
+ if (SPEC_OCLS (val->sym->etype) == pdata)
+ val->sym->iaccess = 1;
+ if (!isinSet (operKeyReset, val->sym))
+ {
+ addSet (&operKeyReset, val->sym);
+ applyToSet (operKeyReset, resetParmKey);
+ }
+ val = val->next;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* isSymbolEqual - compares two symbols return 1 if they match */
+/*-----------------------------------------------------------------*/
+int
+isSymbolEqual (const symbol * dest, const symbol * src)
+{
+ /* if pointers match then equal */
+ if (dest == src)
+ return 1;
+
+ /* if one of them is null then don't match */
+ if (!dest || !src)
+ return 0;
+
+ /* if both of them have rname match on rname */
+ if (dest->rname[0] && src->rname[0])
+ return (!strcmp (dest->rname, src->rname));
+
+ /* otherwise match on name */
+ return (!strcmp (dest->name, src->name));
+}
+
+void
+PT (sym_link * type)
+{
+ printTypeChain (type, 0);
+}
+
+/*-----------------------------------------------------------------*/
+/* printTypeChain - prints the type chain in human readable form */
+/*-----------------------------------------------------------------*/
+void
+printTypeChain (sym_link * start, FILE * of)
+{
+ struct dbuf_s dbuf;
+ int nlr = 0;
+
+ if (!of)
+ {
+ of = stdout;
+ nlr = 1;
+ }
+
+ dbuf_init (&dbuf, 1024);
+ dbuf_printTypeChain (start, &dbuf);
+ dbuf_write_and_destroy (&dbuf, of);
+
+ if (nlr)
+ putc ('\n', of);
+}
+
+void
+dbuf_printTypeChain (sym_link * start, struct dbuf_s *dbuf)
+{
+ value *args;
+ sym_link *type, *search;
+ STORAGE_CLASS scls;
+ static struct dbuf_s dbuf2;
+
+ if (start == NULL)
+ {
+ dbuf_append_str (dbuf, "void");
+ return;
+ }
+
+ /* Print the chain as it is written in the source: */
+ /* start with the last entry. */
+ /* However, the storage class at the end of the */
+ /* chain really applies to the first in the chain! */
+
+ for (type = start; type && type->next; type = type->next)
+ ;
+ if (IS_SPEC (type))
+ scls = SPEC_SCLS (type);
+ else
+ scls = 0;
+ while (type)
+ {
+ if (IS_DECL (type))
+ {
+ switch (DCL_TYPE (type))
+ {
+ case FUNCTION:
+ dbuf_printf (dbuf, "function %s%s",
+ (IFFUNC_ISBUILTIN (type) ? "__builtin__ " : ""),
+ (IFFUNC_ISJAVANATIVE (type) ? "_JavaNative " : ""));
+ dbuf_append_str (dbuf, "( ");
+ for (args = FUNC_ARGS (type); args; args = args->next)
+ {
+ dbuf_printTypeChain (args->type, dbuf);
+ if (args->next)
+ dbuf_append_str (dbuf, ", ");
+ }
+ dbuf_append_str (dbuf, ")");
+ if (IFFUNC_ISREENT (type) && isTargetKeyword("__reentrant"))
+ dbuf_append_str (dbuf, " __reentrant");
+ if (FUNC_REGBANK (type))
+ {
+ dbuf_set_length (&dbuf2, 0);
+ dbuf_printf (&dbuf2, " __using(%d)", FUNC_REGBANK (type));
+ dbuf_append_str (dbuf, dbuf_c_str (&dbuf2));
+ }
+ if (IFFUNC_ISBANKEDCALL (type))
+ dbuf_append_str (dbuf, " __banked");
+ if (IFFUNC_ISZ88DK_CALLEE (type))
+ dbuf_append_str (dbuf, " __z88dk_callee");
+ if (IFFUNC_ISZ88DK_FASTCALL (type))
+ dbuf_append_str (dbuf, " __z88dk_fastcall");
+ for (unsigned char i = 0; i < 9; i++)
+ if (type->funcAttrs.preserved_regs[i])
+ {
+ dbuf_append_str (dbuf, " __preserves_regs(");
+ for (; i < 9; i++)
+ if (type->funcAttrs.preserved_regs[i])
+ dbuf_printf (dbuf, " %d", i);
+ dbuf_append_str (dbuf, " )");
+ break;
+ }
+ break;
+ case GPOINTER:
+ dbuf_append_str (dbuf, "generic*");
+ break;
+ case CPOINTER:
+ dbuf_append_str (dbuf, "code*");
+ break;
+ case FPOINTER:
+ dbuf_append_str (dbuf, "xdata*");
+ break;
+ case EEPPOINTER:
+ dbuf_append_str (dbuf, "eeprom*");
+ break;
+ case POINTER:
+ dbuf_append_str (dbuf, "near*");
+ break;
+ case IPOINTER:
+ dbuf_append_str (dbuf, "idata*");
+ break;
+ case PPOINTER:
+ dbuf_append_str (dbuf, "pdata*");
+ break;
+ case UPOINTER:
+ dbuf_append_str (dbuf, "unknown*");
+ break;
+ case ARRAY:
+ if (DCL_ELEM (type))
+ {
+ dbuf_printf (dbuf, "[%u]", (unsigned int) DCL_ELEM (type));
+ }
+ else
+ {
+ dbuf_append_str (dbuf, "[]");
+ }
+ break;
+ default:
+ dbuf_append_str (dbuf, "unknown?");
+ break;
+ }
+ if (!IS_FUNC (type))
+ {
+ if (DCL_PTR_VOLATILE (type))
+ {
+ dbuf_append_str (dbuf, " volatile");
+ }
+ if (DCL_PTR_CONST (type))
+ {
+ dbuf_append_str (dbuf, " const");
+ }
+ if (DCL_PTR_RESTRICT (type))
+ {
+ dbuf_append_str (dbuf, " restrict");
+ }
+ }
+ }
+ else
+ {
+ if (SPEC_VOLATILE (type))
+ dbuf_append_str (dbuf, "volatile-");
+ if (SPEC_CONST (type))
+ dbuf_append_str (dbuf, "const-");
+ if (SPEC_USIGN (type))
+ dbuf_append_str (dbuf, "unsigned-");
+ else if (SPEC_NOUN (type) == V_CHAR)
+ dbuf_append_str (dbuf, "signed-");
+ switch (SPEC_NOUN (type))
+ {
+ case V_INT:
+ if (IS_LONGLONG (type))
+ dbuf_append_str (dbuf, "longlong-");
+ else if (IS_LONG (type))
+ dbuf_append_str (dbuf, "long-");
+ dbuf_append_str (dbuf, "int");
+ break;
+
+ case V_BOOL:
+ dbuf_append_str (dbuf, "_Bool");
+ break;
+
+ case V_CHAR:
+ dbuf_append_str (dbuf, "char");
+ break;
+
+ case V_VOID:
+ dbuf_append_str (dbuf, "void");
+ break;
+
+ case V_FLOAT:
+ dbuf_append_str (dbuf, "float");
+ break;
+
+ case V_FIXED16X16:
+ dbuf_append_str (dbuf, "fixed16x16");
+ break;
+
+ case V_STRUCT:
+ dbuf_printf (dbuf, "struct %s", SPEC_STRUCT (type)->tag);
+ break;
+
+ case V_SBIT:
+ dbuf_append_str (dbuf, "sbit");
+ break;
+
+ case V_BIT:
+ dbuf_append_str (dbuf, "bit");
+ break;
+
+ case V_BITFIELD:
+ dbuf_printf (dbuf, "bitfield {%d,%d}", SPEC_BSTR (type), SPEC_BLEN (type));
+ break;
+
+ case V_BBITFIELD:
+ dbuf_printf (dbuf, "_Boolbitfield {%d,%d}", SPEC_BSTR (type), SPEC_BLEN (type));
+ break;
+
+ case V_DOUBLE:
+ dbuf_append_str (dbuf, "double");
+ break;
+
+ default:
+ dbuf_append_str (dbuf, "unknown type");
+ break;
+ }
+ }
+ if (type == start)
+ {
+ switch (scls)
+ {
+ case S_FIXED:
+ dbuf_append_str (dbuf, " fixed");
+ break;
+ case S_AUTO:
+ dbuf_append_str (dbuf, " auto");
+ break;
+ case S_REGISTER:
+ dbuf_append_str (dbuf, " register");
+ break;
+ case S_DATA:
+ dbuf_append_str (dbuf, " data");
+ break;
+ case S_XDATA:
+ dbuf_append_str (dbuf, " xdata");
+ break;
+ case S_SFR:
+ dbuf_append_str (dbuf, " sfr");
+ break;
+ case S_SBIT:
+ dbuf_append_str (dbuf, " sbit");
+ break;
+ case S_CODE:
+ dbuf_append_str (dbuf, " code");
+ break;
+ case S_IDATA:
+ dbuf_append_str (dbuf, " idata");
+ break;
+ case S_PDATA:
+ dbuf_append_str (dbuf, " pdata");
+ break;
+ case S_LITERAL:
+ dbuf_append_str (dbuf, " literal");
+ break;
+ case S_STACK:
+ dbuf_append_str (dbuf, " stack");
+ break;
+ case S_XSTACK:
+ dbuf_append_str (dbuf, " xstack");
+ break;
+ case S_BIT:
+ dbuf_append_str (dbuf, " bit");
+ break;
+ case S_EEPROM:
+ dbuf_append_str (dbuf, " eeprom");
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* search entry in list before "type" */
+ for (search = start; search && search->next != type;)
+ search = search->next;
+ type = search;
+ if (type)
+ dbuf_append_char (dbuf, ' ');
+ }
+}
+
+/*--------------------------------------------------------------------*/
+/* printTypeChainRaw - prints the type chain in human readable form */
+/* in the raw data structure ordering */
+/*--------------------------------------------------------------------*/
+void
+printTypeChainRaw (sym_link * start, FILE * of)
+{
+ int nlr = 0;
+ value *args;
+ sym_link *type;
+
+ if (!of)
+ {
+ of = stdout;
+ nlr = 1;
+ }
+
+ if (start == NULL)
+ {
+ fprintf (of, "void");
+ return;
+ }
+
+ type = start;
+
+ while (type)
+ {
+ if (IS_DECL (type))
+ {
+ if (!IS_FUNC (type))
+ {
+ if (DCL_PTR_VOLATILE (type))
+ {
+ fprintf (of, "volatile-");
+ }
+ if (DCL_PTR_CONST (type))
+ {
+ fprintf (of, "const-");
+ }
+ if (DCL_PTR_RESTRICT (type))
+ {
+ fprintf (of, "restrict-");
+ }
+ }
+ switch (DCL_TYPE (type))
+ {
+ case FUNCTION:
+ if (IFFUNC_ISINLINE (type))
+ {
+ fprintf (of, "inline-");
+ }
+ if (IFFUNC_ISNORETURN (type))
+ {
+ fprintf (of, "_Noreturn-");
+ }
+ fprintf (of, "function %s %s",
+ (IFFUNC_ISBUILTIN (type) ? "__builtin__" : " "), (IFFUNC_ISJAVANATIVE (type) ? "_JavaNative" : " "));
+ fprintf (of, "( ");
+ for (args = FUNC_ARGS (type); args; args = args->next)
+ {
+ printTypeChain (args->type, of);
+ if (args->next)
+ fprintf (of, ", ");
+ }
+ fprintf (of, ") ");
+ break;
+ case GPOINTER:
+ fprintf (of, "generic* ");
+ break;
+ case CPOINTER:
+ fprintf (of, "code* ");
+ break;
+ case FPOINTER:
+ fprintf (of, "xdata* ");
+ break;
+ case EEPPOINTER:
+ fprintf (of, "eeprom* ");
+ break;
+ case POINTER:
+ fprintf (of, "near* ");
+ break;
+ case IPOINTER:
+ fprintf (of, "idata* ");
+ break;
+ case PPOINTER:
+ fprintf (of, "pdata* ");
+ break;
+ case UPOINTER:
+ fprintf (of, "unknown* ");
+ break;
+ case ARRAY:
+ if (DCL_ELEM (type))
+ {
+ fprintf (of, "[%ud] ", (unsigned int) DCL_ELEM (type));
+ }
+ else
+ {
+ fprintf (of, "[] ");
+ }
+ break;
+ }
+ if (DCL_TSPEC (type))
+ {
+ fprintf (of, "{");
+ printTypeChainRaw (DCL_TSPEC (type), of);
+ fprintf (of, "}");
+ }
+ }
+ else if (IS_SPEC (type))
+ {
+ switch (SPEC_SCLS (type))
+ {
+ case S_DATA:
+ fprintf (of, "data-");
+ break;
+ case S_XDATA:
+ fprintf (of, "xdata-");
+ break;
+ case S_SFR:
+ fprintf (of, "sfr-");
+ break;
+ case S_SBIT:
+ fprintf (of, "sbit-");
+ break;
+ case S_CODE:
+ fprintf (of, "code-");
+ break;
+ case S_IDATA:
+ fprintf (of, "idata-");
+ break;
+ case S_PDATA:
+ fprintf (of, "pdata-");
+ break;
+ case S_LITERAL:
+ fprintf (of, "literal-");
+ break;
+ case S_STACK:
+ fprintf (of, "stack-");
+ break;
+ case S_XSTACK:
+ fprintf (of, "xstack-");
+ break;
+ case S_BIT:
+ fprintf (of, "bit-");
+ break;
+ case S_EEPROM:
+ fprintf (of, "eeprom-");
+ break;
+ default:
+ break;
+ }
+ if (SPEC_VOLATILE (type))
+ fprintf (of, "volatile-");
+ if (SPEC_CONST (type))
+ fprintf (of, "const-");
+ if (SPEC_USIGN (type))
+ fprintf (of, "unsigned-");
+ switch (SPEC_NOUN (type))
+ {
+ case V_INT:
+ if (IS_LONGLONG (type))
+ fprintf (of, "longlong-");
+ else if (IS_LONG (type))
+ fprintf (of, "long-");
+ fprintf (of, "int");
+ break;
+
+ case V_BOOL:
+ fprintf (of, "_Bool");
+ break;
+
+ case V_CHAR:
+ fprintf (of, "char");
+ break;
+
+ case V_VOID:
+ fprintf (of, "void");
+ break;
+
+ case V_FLOAT:
+ fprintf (of, "float");
+ break;
+
+ case V_FIXED16X16:
+ fprintf (of, "fixed16x16");
+ break;
+
+ case V_STRUCT:
+ fprintf (of, "struct %s", SPEC_STRUCT (type)->tag);
+ break;
+
+ case V_SBIT:
+ fprintf (of, "sbit");
+ break;
+
+ case V_BIT:
+ fprintf (of, "bit");
+ break;
+
+ case V_BITFIELD:
+ fprintf (of, "bitfield {%d,%d}", SPEC_BSTR (type), SPEC_BLEN (type));
+ break;
+
+ case V_BBITFIELD:
+ fprintf (of, "_Boolbitfield {%d,%d}", SPEC_BSTR (type), SPEC_BLEN (type));
+ break;
+
+ case V_DOUBLE:
+ fprintf (of, "double");
+ break;
+
+ default:
+ fprintf (of, "unknown type");
+ break;
+ }
+ }
+ else
+ fprintf (of, "NOT_SPEC_OR_DECL");
+ type = type->next;
+ if (type)
+ fputc (' ', of);
+ }
+ if (nlr)
+ fprintf (of, "\n");
+}
+
+
+/*-----------------------------------------------------------------*/
+/* powof2 - returns power of two for the number if number is pow 2 */
+/*-----------------------------------------------------------------*/
+int
+powof2 (TYPE_TARGET_ULONG num)
+{
+ int nshifts = 0;
+ int n1s = 0;
+
+ while (num)
+ {
+ if (num & 1)
+ n1s++;
+ num >>= 1;
+ nshifts++;
+ }
+
+ if (n1s > 1 || nshifts == 0)
+ return -1;
+ return nshifts - 1;
+}
+
+symbol *fsadd;
+symbol *fssub;
+symbol *fsmul;
+symbol *fsdiv;
+symbol *fseq;
+symbol *fsneq;
+symbol *fslt;
+
+symbol *fps16x16_add;
+symbol *fps16x16_sub;
+symbol *fps16x16_mul;
+symbol *fps16x16_div;
+symbol *fps16x16_eq;
+symbol *fps16x16_neq;
+symbol *fps16x16_lt;
+symbol *fps16x16_lteq;
+symbol *fps16x16_gt;
+symbol *fps16x16_gteq;
+
+/* Dims: mul/div/mod, BYTE/WORD/DWORD/QWORD, SIGNED/UNSIGNED/BOTH */
+symbol *muldiv[3][4][4];
+symbol *muls16tos32[2];
+/* Dims: BYTE/WORD/DWORD/QWORD SIGNED/UNSIGNED */
+sym_link *multypes[4][2];
+/* Dims: to/from float, BYTE/WORD/DWORD/QWORD, SIGNED/USIGNED */
+symbol *conv[2][4][2];
+/* Dims: to/from fixed16x16, BYTE/WORD/DWORD/QWORD/FLOAT, SIGNED/USIGNED */
+symbol *fp16x16conv[2][5][2];
+/* Dims: shift left/shift right, BYTE/WORD/DWORD/QWORD, SIGNED/UNSIGNED */
+symbol *rlrr[2][4][2];
+
+sym_link *charType;
+sym_link *floatType;
+sym_link *fixed16x16Type;
+
+symbol *memcpy_builtin;
+
+static const char *
+_mangleFunctionName (const char *in)
+{
+ if (port->getMangledFunctionName)
+ {
+ return port->getMangledFunctionName (in);
+ }
+ else
+ {
+ return in;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* typeFromStr - create a typechain from an encoded string */
+/* basic types - 'b' - bool */
+/* 'c' - char */
+/* 's' - short */
+/* 'i' - int */
+/* 'l' - long */
+/* 'L' - long long */
+/* 'f' - float */
+/* 'q' - fixed16x16 */
+/* 'v' - void */
+/* '*' - pointer - default (GPOINTER) */
+/* modifiers - 'S' - signed */
+/* 'U' - unsigned */
+/* 'C' - const */
+/* pointer modifiers - 'g' - generic */
+/* 'x' - xdata */
+/* 'p' - code */
+/* 'd' - data */
+/* 'F' - function */
+/* examples : "ig*" - generic int * */
+/* "cx*" - char xdata * */
+/* "Ui" - unsigned int */
+/* "Sc" - signed char */
+/*-----------------------------------------------------------------*/
+sym_link *
+typeFromStr (const char *s)
+{
+ sym_link *r = newLink (DECLARATOR);
+ int sign = 0;
+ int usign = 0;
+ int constant = 0;
+
+ do
+ {
+ sym_link *nr;
+ switch (*s)
+ {
+ case 'S':
+ sign = 1;
+ break;
+ case 'U':
+ usign = 1;
+ break;
+ case 'C':
+ constant = 1;
+ break;
+ case 'b':
+ r->xclass = SPECIFIER;
+ SPEC_NOUN (r) = V_BOOL;
+ break;
+ case 'c':
+ r->xclass = SPECIFIER;
+ SPEC_NOUN (r) = V_CHAR;
+ if (!sign && !usign)
+ r->select.s.b_implicit_sign = true;
+ if (usign)
+ {
+ SPEC_USIGN (r) = 1;
+ usign = 0;
+ }
+ else if (!sign && !options.signed_char)
+ SPEC_USIGN (r) = 1;
+ break;
+ case 's':
+ case 'i':
+ r->xclass = SPECIFIER;
+ SPEC_NOUN (r) = V_INT;
+ break;
+ case 'l':
+ r->xclass = SPECIFIER;
+ SPEC_NOUN (r) = V_INT;
+ SPEC_LONG (r) = 1;
+ break;
+ case 'L':
+ r->xclass = SPECIFIER;
+ SPEC_NOUN (r) = V_INT;
+ SPEC_LONGLONG (r) = 1;
+ break;
+ case 'f':
+ r->xclass = SPECIFIER;
+ SPEC_NOUN (r) = V_FLOAT;
+ break;
+ case 'q':
+ r->xclass = SPECIFIER;
+ SPEC_NOUN (r) = V_FIXED16X16;
+ break;
+ case 'v':
+ r->xclass = SPECIFIER;
+ SPEC_NOUN (r) = V_VOID;
+ break;
+ case '*':
+ DCL_TYPE (r) = port->unqualified_pointer;
+ break;
+ case 'g':
+ case 'x':
+ case 'p':
+ case 'd':
+ case 'F':
+ assert (*(s + 1) == '*');
+ nr = newLink (DECLARATOR);
+ nr->next = r;
+ r = nr;
+ switch (*s)
+ {
+ case 'g':
+ DCL_TYPE (r) = GPOINTER;
+ break;
+ case 'x':
+ DCL_TYPE (r) = FPOINTER;
+ break;
+ case 'p':
+ DCL_TYPE (r) = CPOINTER;
+ break;
+ case 'd':
+ DCL_TYPE (r) = POINTER;
+ break;
+ case 'F':
+ DCL_TYPE (r) = FUNCTION;
+ nr = newLink (DECLARATOR);
+ nr->next = r;
+ r = nr;
+ DCL_TYPE (r) = CPOINTER;
+ break;
+ }
+ s++;
+ break;
+ default:
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "typeFromStr: unknown type");
+ fprintf(stderr, "unknown: %s\n", s);
+ break;
+ }
+ if (usign && sign)
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "typeFromStr: both signed and unsigned specified");
+ if (IS_SPEC (r) && usign)
+ {
+ SPEC_USIGN (r) = 1;
+ usign = 0;
+ }
+ if (IS_SPEC (r) && constant)
+ {
+ SPEC_CONST (r) = 1;
+ constant = 0;
+ }
+ s++;
+ }
+ while (*s);
+ return r;
+}
+
+/*-----------------------------------------------------------------*/
+/* initCSupport - create functions for C support routines */
+/*-----------------------------------------------------------------*/
+void
+initCSupport (void)
+{
+ const char *smuldivmod[] = {
+ "mul", "div", "mod"
+ };
+ const char *sbwd[] = {
+ "char", "int", "long", "longlong", "fixed16x16",
+ };
+ const char *fp16x16sbwd[] = {
+ "char", "int", "long", "longlong", "float",
+ };
+ const char *ssu[] = {
+ "s", "su", "us", "u"
+ };
+ const char *srlrr[] = {
+ "rl", "rr"
+ };
+ /* type as character codes for typeFromStr() */
+ const char *sbwdCodes[] = {
+ "c", "i", "l", "L",
+ "Uc", "Ui", "Ul", "UL"
+ };
+
+ int bwd, su, muldivmod, tofrom, slsr;
+
+ if (getenv ("SDCC_NO_C_SUPPORT"))
+ {
+ /* for debugging only */
+ return;
+ }
+
+ for (bwd = 0; bwd < 4; bwd++)
+ {
+ sym_link *l = NULL;
+ switch (bwd)
+ {
+ case 0:
+ l = newCharLink ();
+ break;
+ case 1:
+ l = newIntLink ();
+ break;
+ case 2:
+ l = newLongLink ();
+ break;
+ case 3:
+ l = newLongLongLink ();
+ break;
+ default:
+ assert (0);
+ }
+ multypes[bwd][0] = l;
+ multypes[bwd][1] = copyLinkChain (l);
+ SPEC_USIGN (multypes[bwd][0]) = 0;
+ SPEC_USIGN (multypes[bwd][1]) = 1;
+ }
+
+ floatType = newFloatLink ();
+ fixed16x16Type = newFixed16x16Link ();
+ charType = (options.signed_char) ? SCHARTYPE : UCHARTYPE;
+
+ fsadd = funcOfType ("__fsadd", floatType, floatType, 2, options.float_rent);
+ fssub = funcOfType ("__fssub", floatType, floatType, 2, options.float_rent);
+ fsmul = funcOfType ("__fsmul", floatType, floatType, 2, options.float_rent);
+ fsdiv = funcOfType ("__fsdiv", floatType, floatType, 2, options.float_rent);
+ fseq = funcOfType ("__fseq", charType, floatType, 2, options.float_rent);
+ fsneq = funcOfType ("__fsneq", charType, floatType, 2, options.float_rent);
+ fslt = funcOfType ("__fslt", charType, floatType, 2, options.float_rent);
+
+ fps16x16_add = funcOfType ("__fps16x16_add", fixed16x16Type, fixed16x16Type, 2, options.float_rent);
+ fps16x16_sub = funcOfType ("__fps16x16_sub", fixed16x16Type, fixed16x16Type, 2, options.float_rent);
+ fps16x16_mul = funcOfType ("__fps16x16_mul", fixed16x16Type, fixed16x16Type, 2, options.float_rent);
+ fps16x16_div = funcOfType ("__fps16x16_div", fixed16x16Type, fixed16x16Type, 2, options.float_rent);
+ fps16x16_eq = funcOfType ("__fps16x16_eq", charType, fixed16x16Type, 2, options.float_rent);
+ fps16x16_neq = funcOfType ("__fps16x16_neq", charType, fixed16x16Type, 2, options.float_rent);
+ fps16x16_lt = funcOfType ("__fps16x16_lt", charType, fixed16x16Type, 2, options.float_rent);
+ fps16x16_lteq = funcOfType ("__fps16x16_lteq", charType, fixed16x16Type, 2, options.float_rent);
+ fps16x16_gt = funcOfType ("__fps16x16_gt", charType, fixed16x16Type, 2, options.float_rent);
+ fps16x16_gteq = funcOfType ("__fps16x16_gteq", charType, fixed16x16Type, 2, options.float_rent);
+
+ for (tofrom = 0; tofrom < 2; tofrom++)
+ {
+ for (bwd = 0; bwd < 4; bwd++)
+ {
+ for (su = 0; su < 2; su++)
+ {
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, 128);
+ if (tofrom)
+ {
+ dbuf_printf (&dbuf, "__fs2%s%s", ssu[su * 3], sbwd[bwd]);
+ conv[tofrom][bwd][su] = funcOfType (dbuf_c_str (&dbuf), multypes[bwd][su], floatType, 1, options.float_rent);
+ }
+ else
+ {
+ dbuf_printf (&dbuf, "__%s%s2fs", ssu[su * 3], sbwd[bwd]);
+ conv[tofrom][bwd][su] = funcOfType (dbuf_c_str (&dbuf), floatType, multypes[bwd][su], 1, options.float_rent);
+ }
+ dbuf_destroy (&dbuf);
+ }
+ }
+ }
+
+ for (tofrom = 0; tofrom < 2; tofrom++)
+ {
+ for (bwd = 0; bwd < 5; bwd++)
+ {
+ for (su = 0; su < 2; su++)
+ {
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, 128);
+ if (tofrom)
+ {
+ dbuf_printf (&dbuf, "__fps16x162%s%s", ssu[su * 3], fp16x16sbwd[bwd]);
+ if (bwd == 4)
+ fp16x16conv[tofrom][bwd][su] =
+ funcOfType (dbuf_c_str (&dbuf), floatType, fixed16x16Type, 1, options.float_rent);
+ else
+ fp16x16conv[tofrom][bwd][su] =
+ funcOfType (dbuf_c_str (&dbuf), multypes[bwd][su], fixed16x16Type, 1, options.float_rent);
+ }
+ else
+ {
+ dbuf_printf (&dbuf, "__%s%s2fps16x16", ssu[su * 3], fp16x16sbwd[bwd]);
+ if (bwd == 4)
+ fp16x16conv[tofrom][bwd][su] =
+ funcOfType (dbuf_c_str (&dbuf), fixed16x16Type, floatType, 1, options.float_rent);
+ else
+ fp16x16conv[tofrom][bwd][su] =
+ funcOfType (dbuf_c_str (&dbuf), fixed16x16Type, multypes[bwd][su], 1, options.float_rent);
+ }
+ dbuf_destroy (&dbuf);
+ }
+ }
+ }
+
+/*
+ for (muldivmod = 0; muldivmod < 3; muldivmod++)
+ {
+ for (bwd = 0; bwd < 4; bwd++)
+ {
+ for (su = 0; su < 2; su++)
+ {
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, 128);
+ dbuf_printf (&dbuf, "_%s%s%s", smuldivmod[muldivmod], ssu[su*3], sbwd[bwd]);
+ muldiv[muldivmod][bwd][su] = funcOfType (_mangleFunctionName(dbuf_c_str (&dbuf)), multypes[bwd][su], multypes[bwd][su], 2, options.intlong_rent);
+ dbuf_destroy (&dbuf);
+ FUNC_NONBANKED (muldiv[muldivmod][bwd][su]->type) = 1;
+ }
+ }
+ }
+
+ muluint() and mulsint() resp. mululong() and mulslong() return the same result.
+ Therefore they've been merged into mulint() and mullong().
+*/
+
+ /* byte */
+
+ /* _divschar/_modschar return int, so that both
+ * 100 / -4 = -25 and -128 / -1 = 128 can be handled correctly
+ * (first one would have to be sign extended, second one must not be).
+ * Similarly, modschar should be handled, but the iCode introduces cast
+ * here and forces '% : s8 x s8 -> s8' ... */
+ bwd = 0;
+ for (su = 0; su < 4; su++)
+ {
+ for (muldivmod = 0; muldivmod < 3; muldivmod++)
+ {
+ /* muluchar, mulschar, mulsuchar and muluschar are separate functions, because e.g. the z80
+ port is sign/zero-extending to int before calling mulint() */
+ /* div and mod : s8_t x s8_t -> s8_t should be s8_t x s8_t -> s16_t, see below */
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, 128);
+ dbuf_printf (&dbuf, "_%s%s%s", smuldivmod[muldivmod], ssu[su], sbwd[bwd]);
+ muldiv[muldivmod][bwd][su] =
+ funcOfType (_mangleFunctionName (dbuf_c_str (&dbuf)), multypes[(TARGET_IS_PIC16 && muldivmod == 1 && bwd == 0 && su == 0 || (TARGET_IS_PIC14 || TARGET_IS_STM8 || TARGET_Z80_LIKE || TARGET_PDK_LIKE) && bwd == 0) ? 1 : bwd][su % 2], multypes[bwd][su / 2], 2,
+ options.intlong_rent);
+ dbuf_destroy (&dbuf);
+ }
+ }
+
+ for (bwd = 1; bwd < 4; bwd++)
+ {
+ for (su = 0; su < 2; su++)
+ {
+ for (muldivmod = 1; muldivmod < 3; muldivmod++)
+ {
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, 128);
+ dbuf_printf (&dbuf, "_%s%s%s", smuldivmod[muldivmod], ssu[su * 3], sbwd[bwd]);
+ muldiv[muldivmod][bwd][su] =
+ funcOfType (_mangleFunctionName (dbuf_c_str (&dbuf)), multypes[(TARGET_IS_PIC16 && muldivmod == 1 && bwd == 0 && su == 0 || (TARGET_IS_STM8 || TARGET_Z80_LIKE || TARGET_PDK_LIKE) && bwd == 0) ? 1 : bwd][su], multypes[bwd][su], 2,
+ options.intlong_rent);
+ dbuf_destroy (&dbuf);
+ }
+ }
+ }
+
+ /* mul only */
+ muldivmod = 0;
+ /* signed only */
+ su = 0;
+ /* word, doubleword, and quadword */
+ for (bwd = 1; bwd < 4; bwd++)
+ {
+ /* mul, int/long */
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, 128);
+ dbuf_printf (&dbuf, "_%s%s", smuldivmod[muldivmod], sbwd[bwd]);
+ muldiv[muldivmod][bwd][0] =
+ funcOfType (_mangleFunctionName (dbuf_c_str (&dbuf)), multypes[bwd][su], multypes[bwd][su], 2, options.intlong_rent);
+ dbuf_destroy (&dbuf);
+ /* signed = unsigned */
+ muldiv[muldivmod][bwd][1] = muldiv[muldivmod][bwd][0];
+ }
+
+ for (slsr = 0; slsr < 2; slsr++)
+ {
+ for (bwd = 0; bwd < 4; bwd++)
+ {
+ for (su = 0; su < 2; su++)
+ {
+ struct dbuf_s dbuf;
+ symbol *sym;
+ const char *params[2];
+
+ params[0] = sbwdCodes[bwd + 4*su];
+ params[1] = sbwdCodes[0];
+
+ dbuf_init (&dbuf, 128);
+ dbuf_printf (&dbuf, "_%s%s%s", srlrr[slsr], ssu[su * 3], sbwd[bwd]);
+ rlrr[slsr][bwd][su] = sym =
+ funcOfTypeVarg (_mangleFunctionName (dbuf_c_str (&dbuf)),
+ sbwdCodes[bwd + 4*su], 2, &params[0]);
+ FUNC_ISREENT (sym->type) = options.intlong_rent ? 1 : 0;
+ FUNC_NONBANKED (sym->type) = 1;
+ dbuf_destroy (&dbuf);
+ }
+ }
+ }
+
+ {
+ const char *iparams[] = {"i", "i"};
+ const char *uiparams[] = {"Ui", "Ui"};
+ muls16tos32[0] = port->support.has_mulint2long ? funcOfTypeVarg ("__mulsint2slong", "l", 2, iparams) : 0;
+ muls16tos32[1] = port->support.has_mulint2long ? funcOfTypeVarg ("__muluint2ulong", "Ul", 2, uiparams) : 0;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* initBuiltIns - create prototypes for builtin functions */
+/*-----------------------------------------------------------------*/
+void
+initBuiltIns ()
+{
+ int i;
+ symbol *sym;
+
+ if (port->builtintable)
+ {
+ for (i = 0; port->builtintable[i].name; i++)
+ {
+ sym = funcOfTypeVarg (port->builtintable[i].name, port->builtintable[i].rtype,
+ port->builtintable[i].nParms, (const char **)port->builtintable[i].parm_types);
+ FUNC_ISBUILTIN (sym->type) = 1;
+ FUNC_ISREENT (sym->type) = 0; /* can never be reentrant */
+ }
+ }
+
+ /* initialize memcpy symbol for struct assignment */
+ memcpy_builtin = findSym (SymbolTab, NULL, "__builtin_memcpy");
+ /* if there is no __builtin_memcpy, use __memcpy instead of an actual builtin */
+ if (!memcpy_builtin)
+ {
+ const char *argTypeStrs[] = {"vg*", "Cvg*", "Ui"};
+ memcpy_builtin = funcOfTypeVarg ("__memcpy", "vg*", 3, argTypeStrs);
+ FUNC_ISBUILTIN (memcpy_builtin->type) = 0;
+ FUNC_ISREENT (memcpy_builtin->type) = options.stackAuto;
+ }
+}
+
+sym_link *
+validateLink (sym_link * l, const char *macro, const char *args, const char select, const char *file, unsigned line)
+{
+ if (l && l->xclass == select)
+ {
+ return l;
+ }
+ fprintf (stderr,
+ "Internal error: validateLink failed in %s(%s) @ %s:%u:"
+ " expected %s, got %s\n",
+ macro, args, file, line, DECLSPEC2TXT (select), l ? DECLSPEC2TXT (l->xclass) : "null-link");
+ exit (EXIT_FAILURE);
+ return l; // never reached, makes compiler happy.
+}
+
+/*--------------------------------------------------------------------*/
+/* newEnumType - create an integer type compatible with enumerations */
+/*--------------------------------------------------------------------*/
+sym_link *
+newEnumType (symbol * enumlist)
+{
+ int min, max, v;
+ symbol *sym;
+ sym_link *type;
+
+ if (!enumlist)
+ {
+ type = newLink (SPECIFIER);
+ SPEC_NOUN (type) = V_INT;
+ return type;
+ }
+
+ /* Determine the range of the enumerated values */
+ sym = enumlist;
+ min = max = (int) ulFromVal (valFromType (sym->type));
+ for (sym = sym->next; sym; sym = sym->next)
+ {
+ v = (int) ulFromVal (valFromType (sym->type));
+ if (v < min)
+ min = v;
+ if (v > max)
+ max = v;
+ }
+
+ /* Determine the smallest integer type that is compatible with this range */
+ type = newLink (SPECIFIER);
+ if (min >= 0 && max <= 255)
+ {
+ SPEC_NOUN (type) = V_CHAR;
+ SPEC_USIGN (type) = 1;
+ }
+ else if (min >= -128 && max <= 127)
+ {
+ SPEC_NOUN (type) = V_CHAR;
+ SPEC_SIGN (type) = 1;
+ }
+ else if (min >= 0 && max <= 65535)
+ {
+ SPEC_NOUN (type) = V_INT;
+ SPEC_USIGN (type) = 1;
+ }
+ else if (min >= -32768 && max <= 32767)
+ {
+ SPEC_NOUN (type) = V_INT;
+ }
+ else
+ {
+ SPEC_NOUN (type) = V_INT;
+ SPEC_LONG (type) = 1;
+ if (min >= 0)
+ SPEC_USIGN (type) = 1;
+ }
+
+ return type;
+}
+
+/*-------------------------------------------------------------------*/
+/* isConstant - check if the type is constant */
+/*-------------------------------------------------------------------*/
+int
+isConstant (sym_link * type)
+{
+ if (!type)
+ return 0;
+
+ while (IS_ARRAY (type))
+ type = type->next;
+
+ if (IS_SPEC (type))
+ return SPEC_CONST (type);
+ else
+ return DCL_PTR_CONST (type);
+}
+
+/*-------------------------------------------------------------------*/
+/* isVolatile - check if the type is volatile */
+/*-------------------------------------------------------------------*/
+int
+isVolatile (sym_link * type)
+{
+ if (!type)
+ return 0;
+
+ while (IS_ARRAY (type))
+ type = type->next;
+
+ if (IS_SPEC (type))
+ return SPEC_VOLATILE (type);
+ else
+ return DCL_PTR_VOLATILE (type);
+}
+
+/*-------------------------------------------------------------------*/
+/* isRestrict - check if the type is restricted */
+/*-------------------------------------------------------------------*/
+int
+isRestrict (sym_link * type)
+{
+ if (!type)
+ return 0;
+
+ while (IS_ARRAY (type))
+ type = type->next;
+
+ if (IS_SPEC (type))
+ return SPEC_RESTRICT (type);
+ else
+ return DCL_PTR_RESTRICT (type);
+}