summaryrefslogtreecommitdiff
path: root/src/SDCCast.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/SDCCast.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/SDCCast.c')
-rw-r--r--src/SDCCast.c8612
1 files changed, 8612 insertions, 0 deletions
diff --git a/src/SDCCast.c b/src/SDCCast.c
new file mode 100644
index 0000000..36f7e26
--- /dev/null
+++ b/src/SDCCast.c
@@ -0,0 +1,8612 @@
+/*-------------------------------------------------------------------------
+ SDCCast.c - source file for parser support & all ast related routines
+
+ 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!
+-------------------------------------------------------------------------*/
+
+#define DEBUG_CF(x) /* puts(x); */
+
+#include <stdint.h>
+
+#include "common.h"
+#include "dbuf_string.h"
+#include "SDCCbtree.h"
+#include "SDCCset.h"
+
+int currLineno = 0;
+set *astList = NULL;
+set *operKeyReset = NULL;
+ast *staticAutos = NULL;
+int labelKey = 1;
+static struct
+{
+ int count; /* number of inline functions inserted */
+ symbol *retsym; /* variable for inlined function return value */
+ symbol *retlab; /* label ending inlined function (virtual return) */
+} inlineState;
+
+#define LRVAL(x) x->left->rvalue
+#define RRVAL(x) x->right->rvalue
+#define TRVAL(x) x->rvalue
+#define LLVAL(x) x->left->lvalue
+#define RLVAL(x) x->right->lvalue
+#define TLVAL(x) x->lvalue
+#define RTYPE(x) x->right->ftype
+#define RETYPE(x) x->right->etype
+#define LTYPE(x) x->left->ftype
+#define LETYPE(x) x->left->etype
+#define TTYPE(x) x->ftype
+#define TETYPE(x) x->etype
+#define ALLOCATE 1
+#define DEALLOCATE 2
+
+#define IS_AND(ex) (ex->type == EX_OP && ex->opval.op == AND_OP )
+#define IS_OR(ex) (ex->type == EX_OP && ex->opval.op == OR_OP )
+#define IS_NOT(ex) (ex->type == EX_OP && ex->opval.op == '!' )
+#define IS_ANDORNOT(ex) (IS_AND(ex) || IS_OR(ex) || IS_NOT(ex))
+#define IS_IFX(ex) (ex->type == EX_OP && ex->opval.op == IFX )
+#define IS_LT(ex) (ex->type == EX_OP && ex->opval.op == '<' )
+#define IS_GT(ex) (ex->type == EX_OP && ex->opval.op == '>')
+
+int noLineno = 0;
+int noAlloc = 0;
+symbol *currFunc = NULL;
+static ast *createIval (ast *, sym_link *, initList *, ast *, ast *, int);
+static ast *createIvalCharPtr (ast *, sym_link *, ast *, ast *);
+static ast *optimizeCompare (ast *);
+ast *optimizeRRCRLC (ast *);
+ast *optimizeSWAP (ast *);
+ast *optimizeGetHbit (ast *, RESULT_TYPE);
+ast *optimizeGetAbit (ast *, RESULT_TYPE);
+ast *optimizeGetByte (ast *, RESULT_TYPE);
+ast *optimizeGetWord (ast *, RESULT_TYPE);
+static ast *backPatchLabels (ast *, symbol *, symbol *);
+static void copyAstLoc (ast *, ast *);
+void PA (ast * t);
+int inInitMode = 0;
+memmap *GcurMemmap = NULL; /* points to the memmap that's currently active */
+struct dbuf_s *codeOutBuf;
+extern int inCriticalFunction;
+extern int inCriticalBlock;
+
+int
+ptt (ast * tree)
+{
+ printTypeChain (tree->ftype, stdout);
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* newAst - creates a fresh node for an expression tree */
+/*-----------------------------------------------------------------*/
+static ast *
+newAst_ (unsigned type)
+{
+ ast *ex;
+
+ ex = Safe_alloc (sizeof (ast));
+
+ ex->type = type;
+ ex->lineno = (noLineno ? 0 : lexLineno);
+ ex->filename = lexFilename;
+ ex->level = NestLevel;
+ ex->block = currBlockno;
+ ex->initMode = inInitMode;
+ ex->seqPoint = seqPointNo;
+ return ex;
+}
+
+ast *
+newAst_VALUE (value * val)
+{
+ ast *ex = newAst_ (EX_VALUE);
+ ex->opval.val = val;
+ return ex;
+}
+
+ast *
+newAst_OP (unsigned op)
+{
+ ast *ex = newAst_ (EX_OP);
+ ex->opval.op = op;
+ return ex;
+}
+
+ast *
+newAst_LINK (sym_link * val)
+{
+ ast *ex = newAst_ (EX_LINK);
+ ex->opval.lnk = val;
+ return ex;
+}
+
+/*-----------------------------------------------------------------*/
+/* newNode - creates a new node */
+/*-----------------------------------------------------------------*/
+ast *
+newNode (long op, ast * left, ast * right)
+{
+ ast *ex;
+
+ ex = newAst_OP (op);
+ ex->left = left;
+ ex->right = right;
+
+ return ex;
+}
+
+/*-----------------------------------------------------------------*/
+/* newIfxNode - creates a new Ifx Node */
+/*-----------------------------------------------------------------*/
+ast *
+newIfxNode (ast * condAst, symbol * trueLabel, symbol * falseLabel)
+{
+ ast *ifxNode;
+
+ /* if this is a literal then we already know the result */
+ if (condAst->etype && IS_LITERAL (condAst->etype) && IS_AST_VALUE (condAst))
+ {
+ /* then depending on the expression value */
+ if (floatFromVal (condAst->opval.val))
+ ifxNode = newNode (GOTO, newAst_VALUE (symbolVal (trueLabel)), NULL);
+ else
+ ifxNode = newNode (GOTO, newAst_VALUE (symbolVal (falseLabel)), NULL);
+ }
+ else
+ {
+ ifxNode = newNode (IFX, condAst, NULL);
+ ifxNode->trueLabel = trueLabel;
+ ifxNode->falseLabel = falseLabel;
+ }
+
+ return ifxNode;
+}
+
+/*-----------------------------------------------------------------*/
+/* copyAstValues - copies value portion of ast if needed */
+/*-----------------------------------------------------------------*/
+void
+copyAstValues (ast * dest, ast * src)
+{
+ switch (src->opval.op)
+ {
+ case BLOCK:
+ dest->values.sym = copySymbolChain (src->values.sym);
+ break;
+
+ case SWITCH:
+ dest->values.switchVals.swVals = copyValueChain (src->values.switchVals.swVals);
+ dest->values.switchVals.swDefault = src->values.switchVals.swDefault;
+ dest->values.switchVals.swNum = src->values.switchVals.swNum;
+ dest->values.switchVals.swSuffix = src->values.switchVals.swSuffix;
+ break;
+
+ case INLINEASM:
+ dest->values.inlineasm = Safe_strdup (src->values.inlineasm);
+ break;
+
+ case ARRAYINIT:
+ dest->values.constlist = copyLiteralList (src->values.constlist);
+ break;
+
+ case FOR:
+ AST_FOR (dest, trueLabel) = copySymbol (AST_FOR (src, trueLabel));
+ AST_FOR (dest, continueLabel) = copySymbol (AST_FOR (src, continueLabel));
+ AST_FOR (dest, falseLabel) = copySymbol (AST_FOR (src, falseLabel));
+ AST_FOR (dest, condLabel) = copySymbol (AST_FOR (src, condLabel));
+ AST_FOR (dest, initExpr) = copyAst (AST_FOR (src, initExpr));
+ AST_FOR (dest, condExpr) = copyAst (AST_FOR (src, condExpr));
+ AST_FOR (dest, loopExpr) = copyAst (AST_FOR (src, loopExpr));
+ break;
+
+ case CAST:
+ dest->values.cast.literalFromCast = src->values.cast.literalFromCast;
+ dest->values.cast.removedCast = src->values.cast.removedCast;
+ dest->values.cast.implicitCast = src->values.cast.implicitCast;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* copyAst - makes a copy of a given astession */
+/*-----------------------------------------------------------------*/
+ast *
+copyAst (ast * src)
+{
+ ast *dest = NULL;
+ static long level = -1;
+ static set *pset;
+
+ if (!src)
+ return NULL;
+
+ if (++level == 0)
+ if ((pset = newSet ()) == NULL)
+ goto exit_1;
+
+ /* check if it is a infinate recursive call */
+ if (isinSet (pset, src))
+ goto exit_1;
+ else
+ addSet (&pset, src);
+
+ dest = Safe_alloc (sizeof (ast));
+ dest->type = src->type;
+ dest->filename = src->filename;
+ dest->lineno = src->lineno;
+ dest->level = src->level;
+ dest->funcName = src->funcName;
+ dest->reversed = src->reversed;
+
+ if (src->ftype)
+ dest->etype = getSpec (dest->ftype = copyLinkChain (src->ftype));
+
+ /* if this is a leaf */
+ /* if value */
+ if (src->type == EX_VALUE)
+ {
+ dest->opval.val = copyValue (src->opval.val);
+ goto exit;
+ }
+
+ /* if link */
+ if (src->type == EX_LINK)
+ {
+ dest->opval.lnk = copyLinkChain (src->opval.lnk);
+ goto exit;
+ }
+
+ dest->opval.op = src->opval.op;
+
+ /* if this is a node that has special values */
+ copyAstValues (dest, src);
+
+ dest->trueLabel = copySymbol (src->trueLabel);
+ dest->falseLabel = copySymbol (src->falseLabel);
+ dest->left = copyAst (src->left);
+ dest->right = copyAst (src->right);
+
+exit:
+ if (pset != NULL && isinSet (pset, src))
+ deleteSetItem (&pset, src);
+exit_1:
+ if (level-- == 0)
+ if (pset != NULL)
+ deleteSet (&pset);
+ return dest;
+}
+
+#if 0
+/*-----------------------------------------------------------------*/
+/* removeIncDecOps: remove for side effects in *_ASSIGN's */
+/* "*s++ += 3" -> "*s++ = *s++ + 3" */
+/*-----------------------------------------------------------------*/
+ast *
+removeIncDecOps (ast * tree)
+{
+
+ // traverse the tree and remove inc/dec ops
+
+ if (!tree)
+ return NULL;
+
+ if (tree->type == EX_OP && (tree->opval.op == INC_OP || tree->opval.op == DEC_OP))
+ {
+ if (tree->left)
+ tree = tree->left;
+ else
+ tree = tree->right;
+ }
+
+ tree->left = removeIncDecOps (tree->left);
+ tree->right = removeIncDecOps (tree->right);
+
+ return tree;
+}
+
+/*-----------------------------------------------------------------*/
+/* removePreIncDecOps: remove for side effects in *_ASSIGN's */
+/* "*++s += 3" -> "*++s = *++s + 3" */
+/*-----------------------------------------------------------------*/
+ast *
+removePreIncDecOps (ast * tree)
+{
+
+ // traverse the tree and remove pre-inc/dec ops
+
+ if (!tree)
+ return NULL;
+
+ if (tree->type == EX_OP && (tree->opval.op == INC_OP || tree->opval.op == DEC_OP))
+ {
+ if (tree->right)
+ tree = tree->right;
+ }
+
+ tree->left = removePreIncDecOps (tree->left);
+ tree->right = removePreIncDecOps (tree->right);
+
+ return tree;
+}
+
+/*-----------------------------------------------------------------*/
+/* removePostIncDecOps: remove for side effects in *_ASSIGN's */
+/* "*s++ += 3" -> "*s++ = *s++ + 3" */
+/*-----------------------------------------------------------------*/
+ast *
+removePostIncDecOps (ast * tree)
+{
+
+ // traverse the tree and remove pre-inc/dec ops
+
+ if (!tree)
+ return NULL;
+
+ if (tree->type == EX_OP && (tree->opval.op == INC_OP || tree->opval.op == DEC_OP))
+ {
+ if (tree->left)
+ tree = tree->left;
+ }
+
+ tree->left = removePostIncDecOps (tree->left);
+ tree->right = removePostIncDecOps (tree->right);
+
+ return tree;
+}
+#endif
+
+/*-----------------------------------------------------------------*/
+/* replaceAstWithTemporary: Replace the AST pointed to by the arg */
+/* with a reference to a new temporary variable. Returns*/
+/* an AST which assigns the original value to the */
+/* temporary. */
+/*-----------------------------------------------------------------*/
+static ast *
+replaceAstWithTemporary (ast ** treeptr)
+{
+ symbol *sym = newSymbol (genSymName (NestLevel), NestLevel);
+ ast *tempvar;
+
+ /* Tell gatherImplicitVariables() to automatically give the
+ symbol the correct type */
+ sym->infertype = 1;
+ sym->type = NULL;
+ sym->etype = NULL;
+
+ tempvar = newNode ('=', newAst_VALUE (symbolVal (sym)), *treeptr);
+ *treeptr = newAst_VALUE (symbolVal (sym));
+
+ addSymChain (&sym);
+
+ return tempvar;
+}
+
+/*-----------------------------------------------------------------*/
+/* createRMW: Create a read-modify-write expression, using a */
+/* temporary variable if necessary to avoid duplicating */
+/* any side effects, for use in e.g. */
+/* foo()->count += 5; becomes */
+/* tmp = foo(); tmp->count = tmp->count + 5; */
+/*-----------------------------------------------------------------*/
+ast *
+createRMW (ast * target, unsigned op, ast * operand)
+{
+ ast *readval, *writeval;
+ ast *tempvar1 = NULL;
+ ast *tempvar2 = NULL;
+ ast *result;
+
+ if (!target || !operand)
+ {
+ return NULL;
+ }
+
+ /* we need to create two copies of target: one to read from and
+ one to write to. but we need to do this without duplicating
+ any side effects that may be contained in the tree. */
+
+ if (IS_AST_OP (target))
+ {
+ /* if this is a dereference, put the referenced item in the temporary */
+ if (IS_DEREF_OP (target))
+ {
+ /* create a new temporary containing the item being dereferenced */
+ if (hasSEFcalls (target->left))
+ tempvar1 = replaceAstWithTemporary (&(target->left));
+ }
+ else if (target->opval.op == '[')
+ {
+ /* Array access is similar, but we have to avoid side effects in
+ both values [WIML: Why not transform a[b] to *(a+b) in parser?] */
+ if (hasSEFcalls (target->left))
+ tempvar1 = replaceAstWithTemporary (&(target->left));
+ if (hasSEFcalls (target->right))
+ tempvar2 = replaceAstWithTemporary (&(target->right));
+ }
+ else if ((target->opval.op == INC_OP) || (target->opval.op == DEC_OP))
+ {
+ /* illegal pre/post-increment/decrement */
+ werrorfl (target->filename, target->lineno, E_LVALUE_REQUIRED, "=");
+ }
+ else
+ {
+ /* we would have to handle '.', but it is not generated any more */
+ wassertl (target->opval.op != '.', "obsolete opcode in tree");
+
+ /* no other kinds of ASTs are lvalues and can contain side effects */
+ }
+ }
+
+ readval = target;
+ writeval = copyAst (target);
+
+ result = newNode ('=', writeval, newNode (op, readval, operand));
+ if (tempvar2)
+ result = newNode (',', tempvar2, result);
+ if (tempvar1)
+ result = newNode (',', tempvar1, result);
+
+ return result;
+}
+
+/*-----------------------------------------------------------------*/
+/* hasSEFcalls - returns TRUE if tree has a function call, */
+/* inc/decrement, or other side effect */
+/*-----------------------------------------------------------------*/
+bool
+hasSEFcalls (ast * tree)
+{
+ if (!tree)
+ return FALSE;
+
+ if (tree->type == EX_OP &&
+ (tree->opval.op == CALL ||
+ tree->opval.op == PCALL || tree->opval.op == '=' || tree->opval.op == INC_OP || tree->opval.op == DEC_OP))
+ return TRUE;
+
+ if (astHasVolatile(tree))
+ return TRUE;
+
+ return (hasSEFcalls (tree->left) | hasSEFcalls (tree->right));
+}
+
+/*-----------------------------------------------------------------*/
+/* isAstEqual - compares two asts & returns 1 if they are equal */
+/*-----------------------------------------------------------------*/
+static int
+isAstEqual (ast * t1, ast * t2)
+{
+ if (!t1 && !t2)
+ return 1;
+
+ if (!t1 || !t2)
+ return 0;
+
+ /* match type */
+ if (t1->type != t2->type)
+ return 0;
+
+ switch (t1->type)
+ {
+ case EX_OP:
+ if (t1->opval.op != t2->opval.op)
+ return 0;
+ return (isAstEqual (t1->left, t2->left) && isAstEqual (t1->right, t2->right));
+ break;
+
+ case EX_VALUE:
+ if (t1->opval.val->sym)
+ {
+ if (!t2->opval.val->sym)
+ return 0;
+ else
+ return isSymbolEqual (t1->opval.val->sym, t2->opval.val->sym);
+ }
+ else
+ {
+ if (t2->opval.val->sym)
+ return 0;
+ else
+ return (floatFromVal (t1->opval.val) == floatFromVal (t2->opval.val));
+ }
+ break;
+
+ /* only compare these two types */
+ default:
+ return 0;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* resolveSymbols - resolve symbols from the symbol table */
+/*-----------------------------------------------------------------*/
+ast *
+resolveSymbols (ast * tree)
+{
+ /* walk the entire tree and check for values */
+ /* with symbols if we find one then replace */
+ /* symbol with that from the symbol table */
+
+ if (tree == NULL)
+ return tree;
+
+#if 0
+ /* print the line */
+ /* if not block & function */
+ if (tree->type == EX_OP && (tree->opval.op != FUNCTION && tree->opval.op != BLOCK && tree->opval.op != NULLOP))
+ {
+ filename = tree->filename;
+ lineno = tree->lineno;
+ }
+#endif
+
+ /* make sure we resolve the true & false labels for ifx */
+ if (tree->type == EX_OP && tree->opval.op == IFX)
+ {
+ symbol *csym;
+
+ if (tree->trueLabel)
+ {
+ if ((csym = findSym (LabelTab, tree->trueLabel, tree->trueLabel->name)))
+ tree->trueLabel = csym;
+ else
+ werrorfl (tree->filename, tree->lineno, E_LABEL_UNDEF, tree->trueLabel->name);
+ }
+
+ if (tree->falseLabel)
+ {
+ if ((csym = findSym (LabelTab, tree->falseLabel, tree->falseLabel->name)))
+ tree->falseLabel = csym;
+ else
+ werrorfl (tree->filename, tree->lineno, E_LABEL_UNDEF, tree->falseLabel->name);
+ }
+ }
+
+ if (tree->type == EX_OP && tree->opval.op == FOR)
+ {
+ symbol *csym;
+
+ if (AST_FOR (tree, trueLabel))
+ {
+ if ((csym = findSym (LabelTab, AST_FOR (tree, trueLabel), AST_FOR (tree, trueLabel)->name)))
+ AST_FOR (tree, trueLabel) = csym;
+ }
+ if (AST_FOR (tree, falseLabel))
+ {
+ if ((csym = findSym (LabelTab, AST_FOR (tree, falseLabel), AST_FOR (tree, falseLabel)->name)))
+ AST_FOR (tree, falseLabel) = csym;
+ }
+ if (AST_FOR (tree, continueLabel))
+ {
+ if ((csym = findSym (LabelTab, AST_FOR (tree, continueLabel), AST_FOR (tree, continueLabel)->name)))
+ AST_FOR (tree, continueLabel) = csym;
+ }
+ if (AST_FOR (tree, condLabel))
+ {
+ if ((csym = findSym (LabelTab, AST_FOR (tree, condLabel), AST_FOR (tree, condLabel)->name)))
+ AST_FOR (tree, condLabel) = csym;
+ }
+ AST_FOR (tree, initExpr) = resolveSymbols (AST_FOR (tree, initExpr));
+ AST_FOR (tree, condExpr) = resolveSymbols (AST_FOR (tree, condExpr));
+ AST_FOR (tree, loopExpr) = resolveSymbols (AST_FOR (tree, loopExpr));
+ }
+
+ /* if this is a label resolve it from the labelTab */
+ if (IS_AST_VALUE (tree) && tree->opval.val->sym && tree->opval.val->sym->islbl)
+ {
+ symbol *csym = findSym (LabelTab, tree->opval.val->sym,
+ tree->opval.val->sym->name);
+
+ if (!csym)
+ werrorfl (tree->filename, tree->lineno, E_LABEL_UNDEF, tree->opval.val->sym->name);
+ else
+ tree->opval.val->sym = csym;
+
+ goto resolveChildren;
+ }
+
+ /* do only for leafs */
+ if (IS_AST_VALUE (tree) && tree->opval.val->sym && !tree->opval.val->sym->implicit)
+ {
+ symbol *csym = findSymWithLevel (SymbolTab, tree->opval.val->sym);
+
+ /* if found in the symbol table & they are not the same */
+ if (csym && tree->opval.val->sym != csym)
+ {
+ tree->opval.val->sym = csym;
+ tree->opval.val->type = csym->type;
+ tree->opval.val->etype = csym->etype;
+ if (*csym->rname)
+ {
+ SNPRINTF (tree->opval.val->name, sizeof (tree->opval.val->name), "%s", csym->rname);
+ }
+ else
+ {
+ SNPRINTF (tree->opval.val->name, sizeof (tree->opval.val->name), "_%s", csym->name);
+ }
+ }
+
+ /* if not found in the symbol table */
+ /* mark it as undefined & assume it */
+ /* is an integer in data space */
+ if (!csym && !tree->opval.val->sym->implicit && !tree->opval.val->type)
+ {
+ /* if this is a function name then */
+ /* mark it as returning an int */
+ if (tree->funcName)
+ {
+ tree->opval.val->sym->type = newLink (DECLARATOR);
+ DCL_TYPE (tree->opval.val->sym->type) = FUNCTION;
+ tree->opval.val->sym->type->next = tree->opval.val->sym->etype = newIntLink ();
+ tree->opval.val->etype = tree->opval.val->etype;
+ tree->opval.val->type = tree->opval.val->sym->type;
+ werrorfl (tree->filename, tree->lineno, W_IMPLICIT_FUNC, tree->opval.val->sym->name);
+ //tree->opval.val->sym->undefined = 1;
+ allocVariables (tree->opval.val->sym);
+ }
+ else
+ {
+ tree->opval.val->sym->undefined = 1;
+ tree->opval.val->type = tree->opval.val->etype = newIntLink ();
+ tree->opval.val->sym->type = tree->opval.val->sym->etype = newIntLink ();
+ }
+ }
+ }
+
+ /* If entering a block with symbols defined, mark the symbols in-scope */
+ /* before continuing down the tree, and mark them out-of-scope again */
+ /* on the way back up */
+ if (tree->type == EX_OP && tree->opval.op == BLOCK && tree->values.sym)
+ {
+ symbol * sym = tree->values.sym;
+ while (sym)
+ {
+ sym->isinscope = 1;
+ sym = sym->next;
+ }
+ resolveSymbols (tree->left);
+ resolveSymbols (tree->right);
+ sym = tree->values.sym;
+ while (sym)
+ {
+ sym->isinscope = 0;
+ sym = sym->next;
+ }
+ return tree;
+ }
+
+resolveChildren:
+ resolveSymbols (tree->left);
+ resolveSymbols (tree->right);
+
+ return tree;
+}
+
+/*------------------------------------------------------------------------*/
+/* setAstFileLine - walks a ast tree & sets the file name and line number */
+/*------------------------------------------------------------------------*/
+int
+setAstFileLine (ast * tree, char *filename, int lineno)
+{
+ if (!tree)
+ return 0;
+
+ tree->filename = filename;
+ tree->lineno = lineno;
+ setAstFileLine (tree->left, filename, lineno);
+ setAstFileLine (tree->right, filename, lineno);
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* funcOfType :- function of type with name */
+/*-----------------------------------------------------------------*/
+symbol *
+funcOfType (const char *name, sym_link * type, sym_link * argType, int nArgs, int rent)
+{
+ symbol *sym;
+ /* create the symbol */
+ sym = newSymbol (name, 0);
+
+ /* setup return value */
+ sym->type = newLink (DECLARATOR);
+ DCL_TYPE (sym->type) = FUNCTION;
+ sym->type->next = copyLinkChain (type);
+ sym->etype = getSpec (sym->type);
+ FUNC_ISREENT (sym->type) = rent ? 1 : 0;
+ FUNC_NONBANKED (sym->type) = 1;
+
+ /* if arguments required */
+ if (nArgs)
+ {
+ value *args;
+ args = FUNC_ARGS (sym->type) = newValue ();
+
+ while (nArgs--)
+ {
+ args->type = copyLinkChain (argType);
+ args->etype = getSpec (args->type);
+ SPEC_EXTR (args->etype) = 1;
+ if (!nArgs)
+ break;
+ args = args->next = newValue ();
+ }
+ }
+
+ /* save it */
+ addSymChain (&sym);
+ sym->cdef = 1;
+ allocVariables (sym);
+ return sym;
+}
+
+/*-----------------------------------------------------------------*/
+/* funcOfTypeVarg :- function of type with name and argtype */
+/*-----------------------------------------------------------------*/
+symbol *
+funcOfTypeVarg (const char *name, const char *rtype, int nArgs, const char **atypes)
+{
+ symbol *sym;
+ int i;
+ /* create the symbol */
+ sym = newSymbol (name, 0);
+
+ /* setup return value */
+ sym->type = newLink (DECLARATOR);
+ DCL_TYPE (sym->type) = FUNCTION;
+ sym->type->next = typeFromStr (rtype);
+ sym->etype = getSpec (sym->type);
+
+ /* if arguments required */
+ if (nArgs)
+ {
+ value *args;
+ args = FUNC_ARGS (sym->type) = newValue ();
+
+ for (i = 0; i < nArgs; i++)
+ {
+ args->type = typeFromStr (atypes[i]);
+ args->etype = getSpec (args->type);
+ SPEC_EXTR (args->etype) = 1;
+ if ((i + 1) == nArgs)
+ break;
+ args = args->next = newValue ();
+ }
+ }
+
+ /* save it */
+ addSymChain (&sym);
+ sym->cdef = 1;
+ allocVariables (sym);
+ return sym;
+}
+
+/*-----------------------------------------------------------------*/
+/* reverseParms - will reverse a parameter tree */
+/*-----------------------------------------------------------------*/
+static void
+reverseParms (ast * ptree, int r)
+{
+ ast *ttree;
+ if (!ptree)
+ return;
+
+ /* top down if we find a nonParm tree then quit */
+ if (ptree->type == EX_OP && ptree->opval.op == PARAM && ptree->reversed != r)
+ {
+ /* The various functions expect the parameter tree to be right heavy. */
+ /* Rotate the tree to be left heavy so that after reversal it is */
+ /* right heavy again. */
+ while ((ttree = ptree->right) && ttree->type == EX_OP && ttree->opval.op == PARAM)
+ {
+ ptree->right = ttree->right;
+ ttree->right = ttree->left;
+ ttree->left = ptree->left;
+ ptree->left = ttree;
+ }
+
+ /* Now reverse */
+ ttree = ptree->left;
+ ptree->left = ptree->right;
+ ptree->right = ttree;
+ ptree->reversed = r;
+ reverseParms (ptree->left, r);
+ reverseParms (ptree->right, r);
+ }
+
+ return;
+}
+
+/*-----------------------------------------------------------------*/
+/* processParms - makes sure the parameters are okay and do some */
+/* processing with them */
+/*-----------------------------------------------------------------*/
+static int
+processParms (ast * func, value * defParm, ast ** actParm, int *parmNumber, /* unused, although updated */
+ bool rightmost)
+{
+ RESULT_TYPE resultType;
+ sym_link *functype;
+
+ /* if none of them exist */
+ if (!defParm && !*actParm)
+ return 0;
+
+ if (defParm)
+ {
+ if (getenv ("DEBUG_SANITY"))
+ {
+ fprintf (stderr, "processParms: %s ", defParm->name);
+ }
+ /* make sure the type is complete and sane */
+ checkTypeSanity (defParm->etype, defParm->name);
+ }
+
+ if (IS_FUNCPTR (func->ftype))
+ functype = func->ftype->next;
+ else
+ functype = func->ftype;
+
+ /* if defined parameters ended but actual parameters */
+ /* exist and this is not defined as a variable arg */
+ if (!defParm && *actParm && !IFFUNC_HASVARARGS (functype))
+ {
+ werror (E_TOO_MANY_PARMS);
+ return 1;
+ }
+
+ /* if defined parameters present but no actual parameters */
+ if (defParm && !*actParm)
+ {
+ werror (E_TOO_FEW_PARMS);
+ return 1;
+ }
+
+ /* if this is a PARAM node then match left & right */
+ if (IS_AST_PARAM (*actParm))
+ {
+ (*actParm)->decorated = 1;
+ if ((*actParm)->reversed)
+ {
+ return (processParms (func, defParm, &(*actParm)->right, parmNumber, FALSE) ||
+ processParms (func, defParm ? defParm->next : NULL, &(*actParm)->left, parmNumber, rightmost));
+ }
+ else
+ {
+ return (processParms (func, defParm, &(*actParm)->left, parmNumber, FALSE) ||
+ processParms (func, defParm ? defParm->next : NULL, &(*actParm)->right, parmNumber, rightmost));
+ }
+ }
+ else if (defParm) /* not vararg */
+ {
+ /* If we have found a value node by following only right-hand links,
+ * then we know that there are no more values after us.
+ *
+ * Therefore, if there are more defined parameters, the caller didn't
+ * supply enough.
+ */
+ if (rightmost && defParm->next)
+ {
+ werror (E_TOO_FEW_PARMS);
+ return 1;
+ }
+ }
+
+ /* decorate parameter */
+ resultType = defParm ? getResultTypeFromType (defParm->type) : RESULT_TYPE_NONE;
+ *actParm = decorateType (*actParm, resultType);
+
+ if (IS_VOID ((*actParm)->ftype))
+ {
+ werror (E_VOID_VALUE_USED);
+ return 1;
+ }
+
+ /* If this is a varargs function... */
+ if (!defParm && *actParm && IFFUNC_HASVARARGS (functype))
+ {
+ ast *newType = NULL;
+ sym_link *ftype;
+
+ /* don't perform integer promotion of explicitly typecasted variable arguments
+ * if sdcc extensions are enabled */
+ if (options.std_sdcc && !TARGET_PDK_LIKE &&
+ (IS_CAST_OP (*actParm) ||
+ (IS_AST_SYM_VALUE (*actParm) && AST_VALUES (*actParm, cast.removedCast)) ||
+ (IS_AST_LIT_VALUE (*actParm) && AST_VALUES (*actParm, cast.literalFromCast))))
+ {
+ /* Parameter was explicitly typecast; don't touch it. */
+ return 0;
+ }
+
+ ftype = (*actParm)->ftype;
+
+ resultType = RESULT_TYPE_NONE;
+
+ /* If it's a char, upcast to int. */
+ if (IS_INTEGRAL (ftype) && (getSize (ftype) < (unsigned) INTSIZE))
+ {
+ newType = newAst_LINK (INTTYPE);
+ }
+
+ if (IS_PTR (ftype) && !IS_GENPTR (ftype))
+ {
+ newType = newAst_LINK (copyLinkChain (ftype));
+ DCL_TYPE (newType->opval.lnk) = port->unqualified_pointer;
+ resultType = RESULT_TYPE_GPTR;
+ }
+
+ if (IS_STRUCT (ftype))
+ {
+ werrorfl ((*actParm)->filename, (*actParm)->lineno, E_STRUCT_AS_ARG, (*actParm)->opval.val->name);
+ return 1;
+ }
+
+ if (IS_ARRAY (ftype))
+ {
+ newType = newAst_LINK (copyLinkChain (ftype));
+ DCL_TYPE (newType->opval.lnk) = port->unqualified_pointer;
+ resultType = RESULT_TYPE_GPTR;
+ }
+
+ if (newType)
+ {
+ /* cast required; change this op to a cast. */
+ (*actParm)->decorated = 0;
+ *actParm = newNode (CAST, newType, *actParm);
+ (*actParm)->filename = (*actParm)->right->filename;
+ (*actParm)->lineno = (*actParm)->right->lineno;
+ AST_VALUES (*actParm, cast.implicitCast) = 1;
+
+ *actParm = decorateType (*actParm, resultType);
+ }
+ return 0;
+ } /* vararg */
+
+ /* if defined parameters ended but actual has not & */
+ /* reentrant */
+ if (!defParm && *actParm && (options.stackAuto || IFFUNC_ISREENT (functype)))
+ {
+ return 0;
+ }
+ resolveSymbols (*actParm);
+
+ /* the parameter type must be at least castable */
+ if (compareType (defParm->type, (*actParm)->ftype) == 0)
+ {
+ if (IS_STRUCT ((*actParm)->ftype))
+ {
+ if (IS_AST_VALUE (*actParm))
+ werrorfl ((*actParm)->filename, (*actParm)->lineno, E_STRUCT_AS_ARG, (*actParm)->opval.val->name);
+ else
+ werrorfl ((*actParm)->filename, (*actParm)->lineno, E_STRUCT_AS_ARG, "");
+ }
+ else
+ {
+ werror (E_INCOMPAT_TYPES);
+ printFromToType ((*actParm)->ftype, defParm->type);
+ }
+ return 1;
+ }
+
+ /* if the parameter is castable then add the cast */
+ if ((IS_ARRAY((*actParm)->ftype) && IS_PTR(defParm->type)) ||
+ (compareType (defParm->type, (*actParm)->ftype) == -1))
+ {
+ ast *pTree;
+
+ resultType = getResultTypeFromType (defParm->type);
+ pTree = resolveSymbols (copyAst (*actParm));
+
+ /* now change the current one to a cast */
+ *actParm = newNode (CAST, newAst_LINK (defParm->type), pTree);
+ (*actParm)->filename = (*actParm)->right->filename;
+ (*actParm)->lineno = (*actParm)->right->lineno;
+ AST_VALUES (*actParm, cast.implicitCast) = 1;
+ *actParm = decorateType (*actParm, IS_GENPTR (defParm->type) ? RESULT_TYPE_GPTR : resultType);
+ }
+
+ /* make a copy and change the regparm type to the defined parm */
+ (*actParm)->etype = getSpec ((*actParm)->ftype = copyLinkChain ((*actParm)->ftype));
+ SPEC_REGPARM ((*actParm)->etype) = SPEC_REGPARM (defParm->etype);
+ SPEC_ARGREG ((*actParm)->etype) = SPEC_ARGREG (defParm->etype);
+
+ /* if the function is being called via a pointer & */
+ /* this parameter is not passed in registers */
+ /* then the function must be defined reentrant */
+ if (IS_FUNCPTR (func->ftype) && !SPEC_REGPARM ((*actParm)->etype) && !IFFUNC_ISREENT (functype) && !options.stackAuto)
+ {
+ werror (E_NONRENT_ARGS);
+ fatalError++;
+ return 1;
+ }
+
+ (*parmNumber)++;
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* createIvalType - generates ival for basic types */
+/*-----------------------------------------------------------------*/
+static ast *
+createIvalType (ast * sym, sym_link * type, initList * ilist)
+{
+ ast *iExpr;
+
+ /* if initList is deep */
+ if (ilist && ilist->type == INIT_DEEP)
+ ilist = ilist->init.deep;
+
+ if (ilist)
+ iExpr = decorateType (resolveSymbols (list2expr (ilist)), RESULT_TYPE_NONE);
+ else
+ iExpr = newAst_VALUE (valueFromLit (0));
+ return decorateType (newNode ('=', sym, iExpr), RESULT_TYPE_NONE);
+}
+
+/*------------------------------------------------------------------*/
+/* moveNestedInit - rewrites an initList node with a nested */
+/* designator to remove one level of nesting. */
+/*------------------------------------------------------------------*/
+static initList *
+moveNestedInit (initList *src)
+{
+ initList *dst;
+
+ /** Create new initList element */
+ switch (src->type)
+ {
+ case INIT_NODE:
+ dst = newiList(INIT_NODE, src->init.node);
+ break;
+ case INIT_DEEP:
+ dst = newiList(INIT_DEEP, src->init.deep);
+ break;
+ default:
+ return NULL;
+ }
+ dst->filename = src->filename;
+ dst->lineno = src->lineno;
+ /* remove one level of nesting from the designation */
+ dst->designation = src->designation->next;
+
+ dst = newiList(INIT_DEEP, dst);
+ dst->filename = src->filename;
+ dst->lineno = src->lineno;
+ dst->next = src->next;
+ return dst;
+}
+
+/*-----------------------------------------------------------------*/
+/* findStructField - find a specific field in a struct definition */
+/*-----------------------------------------------------------------*/
+static symbol *
+findStructField (symbol *fields, symbol *target)
+{
+ for ( ; fields; fields = fields->next)
+ {
+ if (strcmp(fields->name, target->name) == 0)
+ return fields;
+ }
+ return NULL; /* not found */
+}
+
+static int aggregateIsAutoVar = 0;
+
+/*-----------------------------------------------------------------*/
+/* createIvalStruct - generates initial value for structures */
+/*-----------------------------------------------------------------*/
+static ast *
+createIvalStruct (ast * sym, sym_link * type, initList * ilist, ast * rootValue)
+{
+ ast *rast = NULL;
+ ast *lAst;
+ symbol *sflds, *old_sflds, *ps;
+ initList *iloop;
+ sym_link *etype = getSpec (type);
+
+ if (ilist && ilist->type != INIT_DEEP)
+ {
+ werror (E_INIT_STRUCT, "");
+ return NULL;
+ }
+
+ iloop = ilist ? ilist->init.deep : NULL;
+
+ for (sflds = SPEC_STRUCT (type)->fields; ; sflds = sflds->next)
+ {
+ /* skip past unnamed bitfields */
+ if (sflds && IS_BITFIELD (sflds->type) && SPEC_BUNNAMED (sflds->etype))
+ continue;
+
+ old_sflds = sflds;
+ /* designated initializer? */
+ if (iloop && iloop->designation)
+ {
+ if (iloop->designation->type != DESIGNATOR_STRUCT)
+ {
+ werrorfl (iloop->filename, iloop->lineno, E_BAD_DESIGNATOR);
+ }
+ else /* find this designated element */
+ {
+ sflds = findStructField(SPEC_STRUCT (type)->fields,
+ iloop->designation->designator.tag);
+ if (sflds)
+ {
+ if (iloop->designation->next)
+ {
+ iloop = moveNestedInit(iloop);
+ }
+ }
+ else
+ {
+ werrorfl (iloop->filename, iloop->lineno, E_NOT_MEMBER,
+ iloop->designation->designator.tag->name);
+ sflds = SPEC_STRUCT (type)->fields; /* fixup */
+ }
+ }
+ }
+
+ /* if we have come to end */
+ if (!sflds)
+ break;
+ if (!iloop && (!AST_SYMBOL (rootValue)->islocal || SPEC_STAT (etype)))
+ break;
+
+ if (aggregateIsAutoVar && (SPEC_STRUCT (type)->type != UNION))
+ for (ps = old_sflds; ps != sflds && ps != NULL; ps = ps->next)
+ {
+ ps->implicit = 1;
+ lAst = newNode (PTR_OP, newNode ('&', sym, NULL), newAst_VALUE (symbolVal (ps)));
+ lAst = decorateType (resolveSymbols (lAst), RESULT_TYPE_NONE);
+ rast = decorateType (resolveSymbols (createIval (lAst, ps->type, NULL, rast, rootValue, 1)), RESULT_TYPE_NONE);
+ }
+
+ /* initialize this field */
+ sflds->implicit = 1;
+ lAst = newNode (PTR_OP, newNode ('&', sym, NULL), newAst_VALUE (symbolVal (sflds)));
+ lAst = decorateType (resolveSymbols (lAst), RESULT_TYPE_NONE);
+ rast = decorateType (resolveSymbols (createIval (lAst, sflds->type, iloop, rast, rootValue, 1)), RESULT_TYPE_NONE);
+ iloop = iloop ? iloop->next : NULL;
+
+ /* Unions can only initialize a single field */
+ if (SPEC_STRUCT (type)->type == UNION)
+ break;
+ }
+
+ if (iloop)
+ {
+ if (IS_AST_VALUE (sym))
+ werrorfl (sym->opval.val->sym->fileDef, sym->opval.val->sym->lineDef,
+ W_EXCESS_INITIALIZERS, "struct", sym->opval.val->sym->name);
+ else
+ werrorfl (sym->filename, sym->lineno, E_INIT_COUNT);
+ }
+
+ return rast;
+}
+
+/*-----------------------------------------------------------------*/
+/* createIvalArray - generates code for array initialization */
+/*-----------------------------------------------------------------*/
+static ast *
+createIvalArray (ast * sym, sym_link * type, initList * ilist, ast * rootValue)
+{
+ ast *rast = NULL;
+ initList *iloop;
+ int lcnt = 0, size = 0, idx = 0;
+ literalList *literalL;
+ sym_link *etype = getSpec (type);
+
+ /* take care of the special case */
+ /* array of characters can be init */
+ /* by a string */
+ /* char *p = "abc"; */
+ if ((IS_CHAR (type->next) || IS_INT (type->next) && IS_UNSIGNED (type->next)) &&
+ ilist && ilist->type == INIT_NODE)
+ if ((rast = createIvalCharPtr (sym,
+ type,
+ decorateType (resolveSymbols (list2expr (ilist)), RESULT_TYPE_NONE),
+ rootValue)))
+ return decorateType (resolveSymbols (rast), RESULT_TYPE_NONE);
+ /* char *p = {"abc"}; */
+ if ((IS_CHAR (type->next) || IS_INT (type->next) && IS_UNSIGNED (type->next)) &&
+ ilist && ilist->type == INIT_DEEP && ilist->init.deep && ilist->init.deep->type == INIT_NODE)
+ if ((rast = createIvalCharPtr (sym,
+ type,
+ decorateType (resolveSymbols (list2expr (ilist->init.deep)), RESULT_TYPE_NONE),
+ rootValue)))
+ return decorateType (resolveSymbols (rast), RESULT_TYPE_NONE);
+
+ /* not the special case */
+ if (ilist && ilist->type != INIT_DEEP)
+ {
+ werror (E_INIT_STRUCT, "");
+ return NULL;
+ }
+
+ iloop = ilist ? ilist->init.deep : NULL;
+ lcnt = DCL_ELEM (type);
+
+ if (!iloop && (!lcnt || !DCL_ELEM (type) || !AST_SYMBOL (rootValue)->islocal || SPEC_STAT (etype)))
+ {
+ return NULL;
+ }
+
+ if (port->arrayInitializerSuppported && convertIListToConstList (reorderIlist(type,ilist), &literalL, lcnt))
+ {
+ ast *aSym;
+
+ aSym = decorateType (resolveSymbols (sym), RESULT_TYPE_NONE);
+
+ rast = newNode (ARRAYINIT, aSym, NULL);
+ rast->values.constlist = literalL;
+
+ // Make sure size is set to length of initializer list.
+ size = getNelements (type, ilist);
+
+ if (lcnt && size > lcnt)
+ {
+ // Array size was specified, and we have more initializers than needed.
+ werrorfl (sym->opval.val->sym->fileDef, sym->opval.val->sym->lineDef,
+ W_EXCESS_INITIALIZERS, "array", sym->opval.val->sym->name);
+ }
+ }
+ else
+ {
+ for (;;)
+ {
+ ast *aSym;
+ if (!iloop && ((lcnt && size >= lcnt) || !DCL_ELEM (type) || !AST_SYMBOL (rootValue)->islocal))
+ {
+ break;
+ }
+
+ if (iloop && iloop->designation)
+ {
+ if (iloop->designation->type != DESIGNATOR_ARRAY)
+ {
+ werrorfl (iloop->filename, iloop->lineno, E_BAD_DESIGNATOR);
+ }
+ else
+ {
+ idx = iloop->designation->designator.elemno;
+ if (iloop->designation->next)
+ {
+ iloop = moveNestedInit(iloop);
+ }
+ }
+ }
+ /* track array size based on the initializers seen */
+ if (size <= idx)
+ {
+ size = idx + 1;
+ }
+ /* too many initializers? */
+ if (iloop && (lcnt && size > lcnt))
+ {
+ // is this a better way? at least it won't crash
+ char *name = (IS_AST_SYM_VALUE (sym)) ? AST_SYMBOL (sym)->name : "";
+ werrorfl (iloop->filename, iloop->lineno, W_EXCESS_INITIALIZERS, "array", name);
+
+ break;
+ }
+
+ aSym = newNode ('[', sym, newAst_VALUE (valueFromLit ((float) (idx))));
+ aSym = decorateType (resolveSymbols (aSym), RESULT_TYPE_NONE);
+ rast = createIval (aSym, type->next, iloop, rast, rootValue, 0);
+ idx++;
+ iloop = (iloop ? iloop->next : NULL);
+ }
+ }
+
+ /* if we have not been given a size */
+ if (!DCL_ELEM (type))
+ {
+ /* check, if it's a flexible array */
+ if (IS_STRUCT (AST_VALUE (rootValue)->type))
+ AST_SYMBOL (rootValue)->flexArrayLength = size * getSize (type->next);
+ else
+ DCL_ELEM (type) = size;
+ }
+
+ return decorateType (resolveSymbols (rast), RESULT_TYPE_NONE);
+}
+
+/*-----------------------------------------------------------------*/
+/* createIvalCharPtr - generates initial values for char pointers */
+/*-----------------------------------------------------------------*/
+static ast *
+createIvalCharPtr (ast * sym, sym_link * type, ast * iexpr, ast * rootVal)
+{
+ ast *rast = NULL;
+ unsigned size = 0;
+
+ /* if this is a pointer & right is a literal array then */
+ /* just assignment will do */
+ if (IS_PTR (type) && ((IS_LITERAL (iexpr->etype) || (IS_SPEC (iexpr->etype) && SPEC_SCLS (iexpr->etype) == S_CODE)) && IS_ARRAY (iexpr->ftype)))
+ return newNode ('=', sym, iexpr);
+
+ /* left side is an array so we have to assign each element */
+ if (!iexpr)
+ {
+ /* for each character generate an assignment */
+ /* to the array element */
+ unsigned int i = 0;
+ unsigned int symsize = DCL_ELEM (type);
+
+ if (!AST_SYMBOL (rootVal)->islocal || SPEC_STAT (getSpec (type)))
+ return NULL;
+
+ for (i = 0; i < symsize; ++i)
+ {
+ rast = newNode (NULLOP,
+ rast,
+ newNode ('=',
+ newNode ('[', sym,
+ newAst_VALUE (valueFromLit ((float) i))), newAst_VALUE (valueFromLit (0))));
+ }
+
+ return decorateType (resolveSymbols (rast), RESULT_TYPE_NONE);
+ }
+
+ if ((IS_LITERAL (iexpr->etype) || (IS_SPEC (iexpr->etype) && SPEC_SCLS (iexpr->etype) == S_CODE)) && IS_ARRAY (iexpr->ftype))
+ {
+ /* for each character generate an assignment */
+ /* to the array element */
+ unsigned int i = 0;
+ unsigned int symsize = DCL_ELEM (type);
+
+ size = DCL_ELEM (iexpr->ftype);
+ if (symsize && size > symsize)
+ {
+ if (size > symsize)
+ {
+ char *name = (IS_AST_SYM_VALUE (sym)) ? AST_SYMBOL (sym)->name : "";
+
+ TYPE_TARGET_ULONG c;
+ if (IS_CHAR (type->next))
+ c = SPEC_CVAL (iexpr->etype).v_char[symsize];
+ else if (!IS_LONG (type->next))
+ c = SPEC_CVAL (iexpr->etype).v_char16[symsize];
+ else
+ c = SPEC_CVAL (iexpr->etype).v_char32[symsize];
+ if (options.std_c99 && c == '\0' && size == symsize + 1)
+ {
+ if (!options.lessPedantic)
+ werrorfl (iexpr->filename, iexpr->lineno, W_STRING_CANNOT_BE_TERMINATED, name);
+ }
+ else
+ werrorfl (iexpr->filename, iexpr->lineno, W_EXCESS_INITIALIZERS, "string", name);
+ }
+ size = symsize;
+ }
+
+ for (i = 0; i < size; i++)
+ {
+ TYPE_TARGET_ULONG c;
+ if (IS_CHAR (type->next))
+ c = SPEC_CVAL (iexpr->etype).v_char[i];
+ else if (!IS_LONG (type->next))
+ c = SPEC_CVAL (iexpr->etype).v_char16[i];
+ else
+ c = SPEC_CVAL (iexpr->etype).v_char32[i];
+ rast = newNode (NULLOP,
+ rast,
+ newNode ('=',
+ newNode ('[', sym,
+ newAst_VALUE (valueFromLit ((float) i))), newAst_VALUE (valueFromLit (c))));
+ }
+
+ /* assign zero to others */
+ for (i = size; i < symsize; i++)
+ {
+ rast = newNode (NULLOP,
+ rast,
+ newNode ('=',
+ newNode ('[', sym,
+ newAst_VALUE (valueFromLit ((float) i))), newAst_VALUE (valueFromLit (0))));
+ }
+
+ // now WE don't need iexpr's symbol anymore
+ freeStringSymbol (AST_SYMBOL (iexpr));
+
+ /* if we have not been given a size */
+ if (!DCL_ELEM (type))
+ {
+ /* check, if it's a flexible array */
+ if (IS_STRUCT (AST_VALUE (rootVal)->type))
+ AST_SYMBOL (rootVal)->flexArrayLength = size * getSize (type->next);
+ else
+ DCL_ELEM (type) = size;
+ }
+
+ return decorateType (resolveSymbols (rast), RESULT_TYPE_NONE);
+ }
+
+ return NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* createIvalPtr - generates initial value for pointers */
+/*-----------------------------------------------------------------*/
+static ast *
+createIvalPtr (ast * sym, sym_link * type, initList * ilist, ast * rootVal)
+{
+ ast *rast;
+ ast *iexpr;
+
+ /* if deep then */
+ if (ilist && ilist->type == INIT_DEEP)
+ ilist = ilist->init.deep;
+
+ if (ilist)
+ iexpr = decorateType (resolveSymbols (list2expr (ilist)), RESULT_TYPE_NONE);
+ else
+ iexpr = newAst_VALUE (valueFromLit (0));
+
+ /* if character pointer */
+ if (IS_CHAR (type->next) || IS_INT (type->next) && IS_UNSIGNED (type->next))
+ if ((rast = createIvalCharPtr (sym, type, iexpr, rootVal)))
+ return rast;
+
+ return newNode ('=', sym, iexpr);
+}
+
+/*-----------------------------------------------------------------*/
+/* createIval - generates code for initial value */
+/*-----------------------------------------------------------------*/
+static ast *
+createIval (ast * sym, sym_link * type, initList * ilist, ast * wid, ast * rootValue, int omitStatic)
+{
+ ast *rast = NULL;
+
+ if (!ilist && (!AST_SYMBOL (rootValue)->islocal || (omitStatic && SPEC_STAT (getSpec (type)))))
+ return NULL;
+
+ /* if structure then */
+ if (IS_STRUCT (type))
+ rast = createIvalStruct (sym, type, ilist, rootValue);
+ else
+ /* if this is a pointer */
+ if (IS_PTR (type))
+ rast = createIvalPtr (sym, type, ilist, rootValue);
+ else
+ /* if this is an array */
+ if (IS_ARRAY (type))
+ rast = createIvalArray (sym, type, ilist, rootValue);
+ else
+ /* if type is SPECIFIER */
+ if (IS_SPEC (type))
+ rast = createIvalType (sym, type, ilist);
+
+ if (wid)
+ return decorateType (resolveSymbols (newNode (NULLOP, wid, rast)), RESULT_TYPE_NONE);
+ else
+ return decorateType (resolveSymbols (rast), RESULT_TYPE_NONE);
+}
+
+/*-----------------------------------------------------------------*/
+/* initAggregates - initialises aggregate variables with initv */
+/*-----------------------------------------------------------------*/
+ast *
+initAggregates (symbol *sym, initList *ival, ast *wid)
+{
+ ast *newAst = newAst_VALUE (symbolVal (sym));
+ return createIval (newAst, sym->type, ival, wid, newAst, 1);
+}
+
+/*-----------------------------------------------------------------*/
+/* gatherAutoInit - creates assignment expressions for initial */
+/* values */
+/*-----------------------------------------------------------------*/
+static ast *
+gatherAutoInit (symbol * autoChain)
+{
+ ast *init = NULL;
+ ast *work;
+ symbol *sym;
+
+ inInitMode = 1;
+ for (sym = autoChain; sym; sym = sym->next)
+ {
+ /* resolve the symbols in the ival */
+ if (sym->ival)
+ resolveIvalSym (sym->ival, sym->type);
+
+#if 1
+ /* if we are PIC16 port,
+ * and this is a static,
+ * and have initial value,
+ * and not S_CODE, don't emit in gs segment,
+ * but allow glue.c:pic16emitRegularMap to put symbol
+ * in idata section */
+ if (TARGET_IS_PIC16 && IS_STATIC (sym->etype) && sym->ival && SPEC_SCLS (sym->etype) != S_CODE)
+ {
+ SPEC_SCLS (sym->etype) = S_DATA;
+ continue;
+ }
+#endif
+
+ /* if this is a static variable & has an */
+ /* initial value the code needs to be lifted */
+ /* here to the main portion since they can be */
+ /* initialised only once at the start */
+ if (IS_STATIC (sym->etype) && sym->ival && SPEC_SCLS (sym->etype) != S_CODE)
+ {
+ symbol *newSym;
+
+ /* insert the symbol into the symbol table */
+ /* with level = 0 & name = rname */
+ newSym = copySymbol (sym);
+ addSym (SymbolTab, newSym, newSym->rname, 0, 0, 1);
+
+ /* now lift the code to main */
+ if (IS_AGGREGATE (sym->type))
+ {
+ work = initAggregates (sym, sym->ival, NULL);
+ }
+ else
+ {
+ if (getNelements (sym->type, sym->ival) > 1)
+ {
+ werrorfl (sym->fileDef, sym->lineDef, W_EXCESS_INITIALIZERS, "scalar", sym->name);
+ }
+ work = newNode ('=', newAst_VALUE (symbolVal (newSym)), list2expr (sym->ival));
+ }
+
+ setAstFileLine (work, sym->fileDef, sym->lineDef);
+
+ sym->ival = NULL;
+ if (staticAutos)
+ staticAutos = newNode (NULLOP, staticAutos, work);
+ else
+ staticAutos = work;
+
+ continue;
+ }
+
+ /* if there is an initial value */
+ if (sym->ival && SPEC_SCLS (sym->etype) != S_CODE)
+ {
+ initList *ilist = sym->ival;
+
+ while (ilist->type == INIT_DEEP)
+ {
+ ilist = ilist->init.deep;
+ }
+
+ /* update lineno for error msg */
+ filename = sym->fileDef;
+ lineno = sym->lineDef;
+ setAstFileLine (ilist->init.node, sym->fileDef, sym->lineDef);
+
+ if (IS_AGGREGATE (sym->type))
+ {
+ aggregateIsAutoVar = 1;
+ work = initAggregates (sym, sym->ival, NULL);
+ aggregateIsAutoVar = 0;
+ }
+ else
+ {
+ if (getNelements (sym->type, sym->ival) > 1)
+ {
+ werrorfl (sym->fileDef, sym->lineDef, W_EXCESS_INITIALIZERS, "scalar", sym->name);
+ }
+ work = newNode ('=', newAst_VALUE (symbolVal (sym)), list2expr (sym->ival));
+ }
+
+ // just to be sure
+ setAstFileLine (work, sym->fileDef, sym->lineDef);
+
+ sym->ival = NULL;
+ if (init)
+ init = newNode (NULLOP, init, work);
+ else
+ init = work;
+ }
+ }
+ inInitMode = 0;
+ return init;
+}
+
+/*-----------------------------------------------------------------*/
+/* freeStringSymbol - delete a literal string if no more usage */
+/*-----------------------------------------------------------------*/
+void
+freeStringSymbol (symbol *sym)
+{
+ /* make sure this is a literal string */
+ assert (sym->isstrlit);
+ if (--sym->isstrlit == 0)
+ { // lower the usage count
+ memmap *segment = SPEC_OCLS (sym->etype);
+ if (segment)
+ {
+ deleteSetItem (&segment->syms, sym);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* stringToSymbol - creates a symbol from a literal string */
+/*-----------------------------------------------------------------*/
+value *
+stringToSymbol (value *val)
+{
+ struct dbuf_s dbuf;
+ static int charLbl = 0;
+ symbol *sym;
+ set *sp;
+ unsigned int size;
+
+ // have we heard this before?
+ for (sp = statsg->syms; sp; sp = sp->next)
+ {
+ sym = sp->item;
+ size = getSize (sym->type);
+ if (sym->isstrlit && size == getSize (val->type) &&
+ !memcmp (SPEC_CVAL (sym->etype).v_char, SPEC_CVAL (val->etype).v_char, size))
+ {
+ // yes, this is old news. Don't publish it again.
+ sym->isstrlit++; // but raise the usage count
+ return symbolVal (sym);
+ }
+ }
+
+ dbuf_init (&dbuf, 128);
+ dbuf_printf (&dbuf, "__str_%d", charLbl++);
+ sym = newSymbol (dbuf_c_str (&dbuf), 0); /* make it @ level 0 */
+ strncpyz (sym->rname, dbuf_c_str (&dbuf), SDCC_NAME_MAX);
+ dbuf_destroy (&dbuf);
+
+ /* copy the type from the value passed */
+ sym->type = copyLinkChain (val->type);
+ sym->etype = getSpec (sym->type);
+ /* change to storage class & output class */
+ SPEC_SCLS (sym->etype) = S_CODE;
+ SPEC_CVAL (sym->etype).v_char = SPEC_CVAL (val->etype).v_char;
+ SPEC_STAT (sym->etype) = 1;
+ /* make the level & block = 0 */
+ sym->block = sym->level = 0;
+ sym->isstrlit = 1;
+ /* create an ival */
+ sym->ival = newiList (INIT_NODE, newAst_VALUE (val));
+ if (noAlloc == 0)
+ {
+ /* allocate it */
+ addSymChain (&sym);
+ allocVariables (sym);
+ }
+ else
+ {
+ defaultOClass (sym);
+ addSet (&strSym, sym);
+ addSet (&statsg->syms, sym);
+ }
+ sym->ival = NULL;
+ return symbolVal (sym);
+}
+
+/*-----------------------------------------------------------------*/
+/* processBlockVars - will go thru the ast looking for block if */
+/* a block is found then will allocate the syms */
+/* will also gather the auto inits present */
+/*-----------------------------------------------------------------*/
+ast *
+processBlockVars (ast * tree, int *stack, int action)
+{
+ if (!tree)
+ return NULL;
+
+ /* if this is a block */
+ if (tree->type == EX_OP && tree->opval.op == BLOCK)
+ {
+ ast *autoInit;
+ symbol * sym = tree->values.sym;
+
+ while (sym)
+ {
+ sym->isinscope = 1;
+ sym = sym->next;
+ }
+
+ if (action == ALLOCATE)
+ {
+ *stack += allocVariables (tree->values.sym);
+ autoInit = gatherAutoInit (tree->values.sym);
+
+ /* if there are auto inits then do them */
+ if (autoInit)
+ tree->left = newNode (NULLOP, autoInit, tree->left);
+ }
+ else /* action is deallocate */
+ {
+ deallocLocal (tree->values.sym);
+ }
+ }
+
+ if (IS_FOR_STMT (tree))
+ {
+ processBlockVars (AST_FOR (tree, initExpr), stack, action);
+ processBlockVars (AST_FOR (tree, condExpr), stack, action);
+ processBlockVars (AST_FOR (tree, loopExpr), stack, action);
+ }
+ processBlockVars (tree->left, stack, action);
+ processBlockVars (tree->right, stack, action);
+
+ /* if this is a block */
+ if (tree->type == EX_OP && tree->opval.op == BLOCK)
+ {
+ symbol * sym = tree->values.sym;
+
+ while (sym)
+ {
+ sym->isinscope = 0;
+ sym = sym->next;
+ }
+ }
+
+ return tree;
+}
+
+/*-------------------------------------------------------------*/
+/* constExprTree - returns TRUE if this tree is a constant */
+/* expression */
+/*-------------------------------------------------------------*/
+bool
+constExprTree (ast * cexpr)
+{
+ if (!cexpr)
+ {
+ return TRUE;
+ }
+
+ cexpr = decorateType (resolveSymbols (cexpr), RESULT_TYPE_NONE);
+
+ switch (cexpr->type)
+ {
+ case EX_VALUE:
+ if (IS_AST_LIT_VALUE (cexpr))
+ {
+ // this is a literal
+ return TRUE;
+ }
+ if (IS_AST_SYM_VALUE (cexpr) && IS_FUNC (AST_SYMBOL (cexpr)->type))
+ {
+ // a function's address will never change
+ return TRUE;
+ }
+ if (IS_AST_SYM_VALUE (cexpr) && IS_ARRAY (AST_SYMBOL (cexpr)->type))
+ {
+ // an array's address will never change
+ return TRUE;
+ }
+ if (IS_AST_SYM_VALUE (cexpr) && !AST_SYMBOL (cexpr)->etype)
+ {
+ // the offset of a struct field will never change
+ return TRUE;
+ }
+#if 0
+ if (IS_AST_SYM_VALUE (cexpr) && IN_CODESPACE (SPEC_OCLS (AST_SYMBOL (cexpr)->etype)))
+ {
+ // a symbol in code space will never change
+ // This is only for the 'char *s="hallo"' case and will have to leave
+ //printf(" code space symbol");
+ return TRUE;
+ }
+#endif
+ return FALSE;
+ case EX_LINK:
+ wassertl (0, "unexpected link in expression tree");
+ return FALSE;
+ case EX_OP:
+ if (cexpr->opval.op == ARRAYINIT)
+ {
+ // this is a list of literals
+ return TRUE;
+ }
+ if (cexpr->opval.op == '=')
+ {
+ return constExprTree (cexpr->right);
+ }
+ if (cexpr->opval.op == CAST)
+ {
+ // cast ignored, maybe we should throw a warning here?
+ return constExprTree (cexpr->right);
+ }
+ if (cexpr->opval.op == '&')
+ {
+ return TRUE;
+ }
+ if (cexpr->opval.op == CALL || cexpr->opval.op == PCALL)
+ {
+ return FALSE;
+ }
+ if (constExprTree (cexpr->left) && constExprTree (cexpr->right))
+ {
+ return TRUE;
+ }
+ return FALSE;
+ case EX_OPERAND:
+ return IS_CONSTANT (operandType (cexpr->opval.oprnd));
+ }
+ return FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* constExprValue - returns the value of a constant expression */
+/* or NULL if it is not a constant expression */
+/*-----------------------------------------------------------------*/
+value *
+constExprValue (ast * cexpr, int check)
+{
+ cexpr = decorateType (resolveSymbols (cexpr), RESULT_TYPE_NONE);
+
+ /* if this is not a constant then */
+ if (!IS_LITERAL (cexpr->ftype))
+ {
+ /* then check if this is a literal array
+ in code segment */
+ if (SPEC_SCLS (cexpr->etype) == S_CODE && SPEC_CVAL (cexpr->etype).v_char && IS_ARRAY (cexpr->ftype))
+ {
+ value *val = valFromType (cexpr->ftype);
+ SPEC_SCLS (val->etype) = S_LITERAL;
+ val->sym = cexpr->opval.val->sym;
+ val->sym->type = copyLinkChain (cexpr->ftype);
+ val->sym->etype = getSpec (val->sym->type);
+ strncpyz (val->name, cexpr->opval.val->sym->rname, SDCC_NAME_MAX);
+ return val;
+ }
+
+ /* if we are casting a literal value then */
+ if (IS_CAST_OP (cexpr) && IS_LITERAL (cexpr->right->ftype))
+ {
+ return valCastLiteral (cexpr->ftype, floatFromVal (cexpr->right->opval.val), (TYPE_TARGET_ULONGLONG) ullFromVal (cexpr->right->opval.val));
+ }
+
+ if (IS_AST_VALUE (cexpr))
+ {
+ return cexpr->opval.val;
+ }
+
+ if (check)
+ werrorfl (cexpr->filename, cexpr->lineno, E_CONST_EXPECTED, "found expression");
+
+ return NULL;
+ }
+
+ /* return the value */
+ if (IS_AST_VALUE (cexpr))
+ {
+ return cexpr->opval.val;
+ }
+ return NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* isLabelInAst - will return true if a given label is found */
+/*-----------------------------------------------------------------*/
+bool
+isLabelInAst (symbol * label, ast * tree)
+{
+ if (!tree || IS_AST_VALUE (tree) || IS_AST_LINK (tree))
+ return FALSE;
+
+ if (IS_AST_OP (tree) && tree->opval.op == LABEL && isSymbolEqual (AST_SYMBOL (tree->left), label))
+ return TRUE;
+
+ return isLabelInAst (label, tree->right) && isLabelInAst (label, tree->left);
+}
+
+/*-----------------------------------------------------------------*/
+/* isLoopCountable - return true if the loop count can be */
+/* determined at compile time . */
+/*-----------------------------------------------------------------*/
+static bool
+isLoopCountable (ast * initExpr, ast * condExpr, ast * loopExpr, symbol ** sym, ast ** init, ast ** end)
+{
+ /* the loop is considered countable if the following
+ conditions are true :-
+
+ a) initExpr :- <sym> = <const>
+ b) condExpr :- <sym> < <const1>
+ c) loopExpr :- <sym> ++
+ */
+
+ /* first check the initExpr */
+ if (IS_AST_OP (initExpr) && initExpr->opval.op == '=' && /* is assignment */
+ IS_AST_SYM_VALUE (initExpr->left))
+ { /* left is a symbol */
+
+ *sym = AST_SYMBOL (initExpr->left);
+ *init = initExpr->right;
+ }
+ else
+ return FALSE;
+
+ /* don't reverse loop with volatile counter */
+ if (IS_VOLATILE ((*sym)->type))
+ return FALSE;
+
+ /* for now the symbol has to be of
+ integral type */
+ if (!IS_INTEGRAL ((*sym)->type))
+ return FALSE;
+
+ /* now check condExpr */
+ if (IS_AST_OP (condExpr))
+ {
+ switch (condExpr->opval.op)
+ {
+ case '<':
+ if (IS_AST_SYM_VALUE (condExpr->left) &&
+ isSymbolEqual (*sym, AST_SYMBOL (condExpr->left)) && IS_AST_LIT_VALUE (condExpr->right))
+ {
+ *end = condExpr->right;
+ break;
+ }
+ return FALSE;
+
+ case '!':
+ if (IS_AST_OP (condExpr->left) &&
+ condExpr->left->opval.op == '>' &&
+ IS_AST_LIT_VALUE (condExpr->left->right) &&
+ IS_AST_SYM_VALUE (condExpr->left->left) && isSymbolEqual (*sym, AST_SYMBOL (condExpr->left->left)))
+ {
+
+ *end = newNode ('+', condExpr->left->right, newAst_VALUE (constVal ("1")));
+ break;
+ }
+ return FALSE;
+
+ default:
+ return FALSE;
+ }
+ }
+ else
+ return FALSE;
+
+ /* check loop expression is of the form <sym>++ */
+ if (!IS_AST_OP (loopExpr))
+ return FALSE;
+
+ /* check if <sym> ++ */
+ if (loopExpr->opval.op == INC_OP)
+ {
+ if (loopExpr->left)
+ {
+ /* pre */
+ if (IS_AST_SYM_VALUE (loopExpr->left) && isSymbolEqual (*sym, AST_SYMBOL (loopExpr->left)))
+ return TRUE;
+ }
+ else
+ {
+ /* post */
+ if (IS_AST_SYM_VALUE (loopExpr->right) && isSymbolEqual (*sym, AST_SYMBOL (loopExpr->right)))
+ return TRUE;
+ }
+ }
+ else
+ {
+ /* check for += */
+ if (loopExpr->opval.op == ADD_ASSIGN) /* seems to never happen, createRMW() absorbed */
+ {
+ wassertl (0, "obsolete opcode in tree");
+
+ if (IS_AST_SYM_VALUE (loopExpr->left) &&
+ isSymbolEqual (*sym, AST_SYMBOL (loopExpr->left)) &&
+ IS_AST_LIT_VALUE (loopExpr->right) && AST_ULONG_VALUE (loopExpr->right) == 1)
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* astHasVolatile - returns true if ast contains any volatile */
+/*-----------------------------------------------------------------*/
+bool
+astHasVolatile (ast *tree)
+{
+ if (!tree)
+ return FALSE;
+
+ if (TETYPE (tree) && IS_VOLATILE (TETYPE (tree)))
+ return TRUE;
+
+ if (IS_AST_OP (tree))
+ return astHasVolatile (tree->left) || astHasVolatile (tree->right);
+ else
+ return FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* astHasPointer - return true if the ast contains any ptr variable */
+/*-----------------------------------------------------------------*/
+bool
+astHasPointer (ast * tree)
+{
+ if (!tree)
+ return FALSE;
+
+ if (IS_AST_LINK (tree))
+ return TRUE;
+
+ /* if we hit an array expression then check
+ only the left side */
+ if (IS_AST_OP (tree) && tree->opval.op == '[')
+ return astHasPointer (tree->left);
+
+ if (IS_AST_VALUE (tree))
+ return IS_PTR (tree->ftype) || IS_ARRAY (tree->ftype);
+
+ return astHasPointer (tree->left) || astHasPointer (tree->right);
+}
+
+/*-----------------------------------------------------------------*/
+/* astHasSymbol - return true if the ast has the given symbol */
+/*-----------------------------------------------------------------*/
+bool
+astHasSymbol (ast * tree, symbol * sym)
+{
+ if (!tree || IS_AST_LINK (tree))
+ return FALSE;
+
+ if (IS_AST_VALUE (tree))
+ {
+ if (IS_AST_SYM_VALUE (tree))
+ return isSymbolEqual (AST_SYMBOL (tree), sym);
+ else
+ return FALSE;
+ }
+
+ return astHasSymbol (tree->left, sym) || astHasSymbol (tree->right, sym);
+}
+
+/*-----------------------------------------------------------------*/
+/* astHasDeref - return true if the ast has an indirect access */
+/*-----------------------------------------------------------------*/
+static bool
+astHasDeref (ast * tree)
+{
+ if (!tree || IS_AST_LINK (tree) || IS_AST_VALUE (tree))
+ return FALSE;
+
+ if (tree->opval.op == '*' && tree->right == NULL)
+ return TRUE;
+
+ return astHasDeref (tree->left) || astHasDeref (tree->right);
+}
+
+/*-----------------------------------------------------------------*/
+/* isConformingBody - the loop body has to conform to a set of */
+/* rules for the loop to be considered reversible read on for rules*/
+/*-----------------------------------------------------------------*/
+bool
+isConformingBody (ast * pbody, symbol * sym, ast * body)
+{
+ /* we are going to do a pre-order traversal of the
+ tree && check for the following conditions. (essentially
+ a set of very shallow tests )
+ a) the sym passed does not participate in any arithmetic operation
+ b) There are no function calls
+ c) all jumps are within the body
+ d) address of loop control variable not taken
+ e) if an assignment has a pointer on the left hand side make sure
+ right does not have loop control variable
+ */
+
+ /* if we reach the end or a leaf then true */
+ if (!pbody || IS_AST_LINK (pbody) || IS_AST_VALUE (pbody))
+ return TRUE;
+
+ /* if anything else is "volatile" */
+ if (IS_VOLATILE (TETYPE (pbody)))
+ return FALSE;
+
+ /* we will walk the body in a pre-order traversal for
+ efficiency sake */
+ switch (pbody->opval.op)
+ {
+/*------------------------------------------------------------------*/
+ case '[':
+ /* if the loopvar is used as an index */
+ /* array op is commutative -- must check both left & right */
+ if (astHasSymbol (pbody->right, sym) || astHasSymbol (pbody->left, sym))
+ {
+ return FALSE;
+ }
+ return isConformingBody (pbody->right, sym, body) && isConformingBody (pbody->left, sym, body);
+
+/*------------------------------------------------------------------*/
+ case PTR_OP:
+ /* '->' right: is a symbol
+ left: check if the loopvar is used as an index */
+ if (astHasSymbol (pbody->left, sym))
+ return FALSE;
+ return isConformingBody (pbody->left, sym, body);
+
+ case '.':
+ wassertl (0, "obsolete opcode in tree");
+ break;
+
+/*------------------------------------------------------------------*/
+ case INC_OP:
+ case DEC_OP:
+
+ if (astHasSymbol (pbody->right, sym) || astHasSymbol (pbody->left, sym))
+ return FALSE;
+
+ return isConformingBody (pbody->right, sym, body) && isConformingBody (pbody->left, sym, body);
+
+/*------------------------------------------------------------------*/
+
+ case '*': /* can be unary : if right is null then unary operation */
+ case '+':
+ case '-':
+ case '&':
+
+ /* if right is NULL then unary operation */
+/*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* address of */
+ /*----------------------------*/
+ if (!pbody->right)
+ {
+ if (IS_AST_SYM_VALUE (pbody->left) && isSymbolEqual (AST_SYMBOL (pbody->left), sym))
+ return FALSE;
+ else
+ return isConformingBody (pbody->left, sym, body);
+ }
+ else
+ {
+ if (astHasSymbol (pbody->left, sym) || astHasSymbol (pbody->right, sym))
+ return FALSE;
+ }
+
+/*------------------------------------------------------------------*/
+ case '|':
+ case '^':
+ case '/':
+ case '%':
+ case LEFT_OP:
+ case RIGHT_OP:
+ case GETABIT:
+ case GETBYTE:
+ case GETWORD:
+
+ if (IS_AST_SYM_VALUE (pbody->left) && isSymbolEqual (AST_SYMBOL (pbody->left), sym))
+ return FALSE;
+
+ if (IS_AST_SYM_VALUE (pbody->right) && isSymbolEqual (AST_SYMBOL (pbody->right), sym))
+ return FALSE;
+
+ return isConformingBody (pbody->left, sym, body) && isConformingBody (pbody->right, sym, body);
+
+ case '~':
+ case '!':
+ case RRC:
+ case RLC:
+ case GETHBIT:
+ case SWAP:
+ if (IS_AST_SYM_VALUE (pbody->left) && isSymbolEqual (AST_SYMBOL (pbody->left), sym))
+ return FALSE;
+ return isConformingBody (pbody->left, sym, body);
+
+/*------------------------------------------------------------------*/
+
+ case AND_OP:
+ case OR_OP:
+ case '>':
+ case '<':
+ case LE_OP:
+ case GE_OP:
+ case EQ_OP:
+ case NE_OP:
+ case '?':
+ case ':':
+ case SIZEOF: /* evaluate wihout code generation */
+
+ if (IS_AST_SYM_VALUE (pbody->left) && isSymbolEqual (AST_SYMBOL (pbody->left), sym))
+ return FALSE;
+
+ if (IS_AST_SYM_VALUE (pbody->right) && isSymbolEqual (AST_SYMBOL (pbody->right), sym))
+ return FALSE;
+
+ return isConformingBody (pbody->left, sym, body) && isConformingBody (pbody->right, sym, body);
+
+/*------------------------------------------------------------------*/
+ case '=':
+
+ /* if left has a pointer & right has loop
+ control variable then we cannot */
+ if (astHasPointer (pbody->left) && astHasSymbol (pbody->right, sym))
+ return FALSE;
+
+ if (astHasVolatile (pbody->left))
+ return FALSE;
+
+ if (IS_AST_SYM_VALUE (pbody->left))
+ {
+ // if the loopvar has an assignment
+ if (isSymbolEqual (AST_SYMBOL (pbody->left), sym))
+ return FALSE;
+ // if the loopvar is used in another (maybe conditional) block
+ if (astHasSymbol (pbody->right, sym) && (pbody->level >= body->level))
+ {
+ return FALSE;
+ }
+ }
+
+ if (astHasDeref (pbody->right))
+ return FALSE;
+
+ return isConformingBody (pbody->left, sym, body) && isConformingBody (pbody->right, sym, body);
+
+ case MUL_ASSIGN:
+ case DIV_ASSIGN:
+ case AND_ASSIGN:
+ case OR_ASSIGN:
+ case XOR_ASSIGN:
+ case RIGHT_ASSIGN:
+ case LEFT_ASSIGN:
+ case SUB_ASSIGN:
+ case ADD_ASSIGN:
+ assert ("Parser should not have generated this\n");
+
+/*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* comma operator */
+ /*----------------------------*/
+ case ',':
+ return isConformingBody (pbody->left, sym, body) && isConformingBody (pbody->right, sym, body);
+
+/*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* function call */
+ /*----------------------------*/
+ case CALL:
+ /* if local & no parameters &
+ not used to find the function then ok */
+ if (sym->level && !pbody->right && !astHasSymbol (pbody->left, sym))
+ {
+ return TRUE;
+ }
+ return FALSE;
+
+/*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* return statement */
+ /*----------------------------*/
+ case RETURN:
+ return FALSE;
+
+ case GOTO:
+ if (isLabelInAst (AST_SYMBOL (pbody->left), body))
+ return TRUE;
+ else
+ return FALSE;
+
+ case SWITCH:
+ if (astHasSymbol (pbody->left, sym))
+ return FALSE;
+ break;
+
+ default:
+ break;
+ }
+
+ return isConformingBody (pbody->left, sym, body) && isConformingBody (pbody->right, sym, body);
+}
+
+/*-----------------------------------------------------------------*/
+/* isLoopReversible - takes a for loop as input && returns true */
+/* if the for loop is reversible. If yes will set the value of */
+/* the loop control var & init value & termination value */
+/*-----------------------------------------------------------------*/
+static bool
+isLoopReversible (ast * loop, symbol ** loopCntrl, ast ** init, ast ** end)
+{
+ /* if option says don't do it then don't */
+ if (optimize.noLoopReverse)
+ return 0;
+ /* there are several tests to determine this */
+
+ /* for loop has to be of the form
+ for ( <sym> = <const1> ;
+ [<sym> < <const2>] ;
+ [<sym>++] | [<sym> += 1] | [<sym> = <sym> + 1] )
+ forBody */
+ if (!isLoopCountable (AST_FOR (loop, initExpr), AST_FOR (loop, condExpr), AST_FOR (loop, loopExpr), loopCntrl, init, end))
+ return 0;
+
+ /* now do some serious checking on the body of the loop
+ */
+
+ return isConformingBody (loop->left, *loopCntrl, loop->left);
+}
+
+/*-----------------------------------------------------------------*/
+/* replLoopSym - replace the loop sym by loop sym -1 */
+/*-----------------------------------------------------------------*/
+static void
+replLoopSym (ast * body, symbol * sym)
+{
+ /* reached end */
+ if (!body || IS_AST_LINK (body))
+ return;
+
+ if (IS_AST_SYM_VALUE (body))
+ {
+ if (isSymbolEqual (AST_SYMBOL (body), sym))
+ {
+
+ body->type = EX_OP;
+ body->opval.op = '-';
+ body->left = newAst_VALUE (symbolVal (sym));
+ body->right = newAst_VALUE (constVal ("1"));
+ }
+ return;
+ }
+
+ replLoopSym (body->left, sym);
+ replLoopSym (body->right, sym);
+}
+
+/*-----------------------------------------------------------------*/
+/* reverseLoop - do the actual loop reversal */
+/*-----------------------------------------------------------------*/
+ast *
+reverseLoop (ast * loop, symbol * sym, ast * init, ast * end)
+{
+ ast *rloop;
+
+ /* create the following tree
+ <sym> = loopCount ;
+ for_continue:
+ forbody
+ <sym> -= 1;
+ if (sym) goto for_continue ;
+ <sym> = end */
+
+ /* put it together piece by piece */
+ rloop = newNode (NULLOP,
+ createIf (newAst_VALUE (symbolVal (sym)),
+ newNode (GOTO,
+ newAst_VALUE (symbolVal (AST_FOR (loop, continueLabel))),
+ NULL), NULL), newNode ('=', newAst_VALUE (symbolVal (sym)), end));
+
+ replLoopSym (loop->left, sym);
+ setAstFileLine (rloop, init->filename, init->lineno);
+
+ rloop = newNode (NULLOP,
+ newNode ('=',
+ newAst_VALUE (symbolVal (sym)),
+ newNode ('-', end, init)),
+ createLabel (AST_FOR (loop, continueLabel),
+ newNode (NULLOP,
+ loop->left,
+ newNode (NULLOP,
+ newNode (SUB_ASSIGN,
+ newAst_VALUE (symbolVal (sym)),
+ newAst_VALUE (constVal ("1"))), rloop))));
+
+ rloop->lineno = init->lineno;
+ return decorateType (rloop, RESULT_TYPE_NONE);
+}
+
+/*-----------------------------------------------------------------*/
+/* replLoopSymByVal - replace the loop sym by a value */
+/*-----------------------------------------------------------------*/
+static int
+replLoopSymByVal (ast * body, symbol * sym, value * val)
+{
+ int changed;
+ /* reached end */
+ if (!body || IS_AST_LINK (body))
+ return 0;
+
+ if (IS_AST_SYM_VALUE (body))
+ {
+ if (isSymbolEqual (AST_SYMBOL (body), sym))
+ {
+
+ body->type = EX_VALUE;
+ AST_VALUE (body) = copyValue (val);
+ body->decorated = 0;
+ return 1;
+ }
+ return 0;
+ }
+
+ changed = replLoopSymByVal (body->left, sym, val);
+ changed |= replLoopSymByVal (body->right, sym, val);
+ if (changed)
+ body->decorated = 0;
+ return changed;
+}
+
+/*-----------------------------------------------------------------*/
+/* isInitiallyTrue - check if a for loop's condition is true for */
+/* the initial iteration */
+/*-----------------------------------------------------------------*/
+static bool
+isInitiallyTrue (ast *initExpr, ast * condExpr)
+{
+ symbol * sym;
+ ast * init;
+
+ if (!condExpr)
+ return TRUE;
+ if (!initExpr)
+ return FALSE;
+
+ /* first check the initExpr */
+ if (IS_AST_OP (initExpr) && initExpr->opval.op == '=' && /* is assignment */
+ IS_AST_SYM_VALUE (initExpr->left))
+ { /* left is a symbol */
+
+ sym = AST_SYMBOL (initExpr->left);
+ init = initExpr->right;
+ }
+ else
+ return FALSE;
+
+ /* don't defer condition test if volatile */
+ if (IS_VOLATILE ((sym)->type))
+ return FALSE;
+
+ if (!IS_AST_LIT_VALUE (init))
+ return FALSE;
+
+ /* Cannot move the condition if the condition has side-effects */
+ if (hasSEFcalls (condExpr))
+ return FALSE;
+
+ /* Cast the initial value to the type of the loop symbol so that */
+ /* we have the actual value that we would read out of that symbol */
+ /* rather than just the value assigned to it. */
+ initExpr = copyAst (initExpr);
+ initExpr->opval.op = CAST;
+ initExpr->left = newAst_LINK (LTYPE (initExpr));
+ initExpr->decorated = 0;
+ decorateType (initExpr, RESULT_TYPE_NONE);
+ if (!IS_AST_LIT_VALUE (initExpr))
+ return FALSE;
+
+ /* Replace the symbol with its initial value and see if the condition */
+ /* simplifies to a non-zero (TRUE) literal value */
+ condExpr = copyAst (condExpr);
+ if (replLoopSymByVal (condExpr, sym, AST_VALUE (initExpr)))
+ {
+ int original;
+
+ /* We are speculating that the condition is always true */
+ /* or false for the first loop iteration; no need to */
+ /* trigger a warning that may not apply to the original */
+ /* source code. */
+ original = setWarningDisabledState (W_COMP_RANGE, TRUE);
+ condExpr = decorateType (condExpr, RESULT_TYPE_NONE);
+ setWarningDisabledState (W_COMP_RANGE, original);
+ }
+ if (!IS_AST_LIT_VALUE (condExpr))
+ return FALSE;
+ return !isEqualVal (AST_VALUE (condExpr), 0);
+}
+
+/*-----------------------------------------------------------------*/
+/* createDoFor - creates parse tree for 'for' statement */
+/* */
+/* When we know that the condition is always true for the initial */
+/* iteration, we can build a more optimal tree by testing the */
+/* condition at the end of the loop (like do-while). */
+/* */
+/* initExpr */
+/* _forbody_n: */
+/* statements */
+/* _forcontinue_n: */
+/* loopExpr */
+/* condExpr +-> trueLabel -> _forbody_n */
+/* | */
+/* +-> falseLabel-> _forbreak_n */
+/* _forbreak_n: */
+/*-----------------------------------------------------------------*/
+ast *
+createDoFor (symbol * trueLabel, symbol * continueLabel, symbol * falseLabel,
+ symbol * condLabel, ast * initExpr, ast * condExpr,
+ ast * loopExpr, ast * forBody, ast * continueLabelAst)
+{
+ ast *forTree;
+
+ if (condExpr)
+ {
+ condExpr = backPatchLabels (condExpr, trueLabel, falseLabel);
+ if (condExpr && !IS_IFX (condExpr))
+ condExpr = newIfxNode (condExpr, trueLabel, falseLabel);
+ }
+ else /* if no condition specified, it is considered always TRUE */
+ condExpr = newNode (GOTO, newAst_VALUE (symbolVal (trueLabel)), NULL);
+
+ /* attach body label to body */
+ forBody = createLabel (trueLabel, forBody);
+
+ /* attach continue to forLoop expression and condition */
+ loopExpr = newNode (NULLOP, loopExpr, condExpr);
+ if (continueLabelAst)
+ {
+ continueLabelAst->right = loopExpr;
+ loopExpr = continueLabelAst;
+ }
+ else
+ loopExpr = createLabel (continueLabel, loopExpr);
+
+ /* now start putting them together */
+ forTree = newNode (NULLOP, initExpr, forBody);
+ forTree = newNode (NULLOP, forTree, loopExpr);
+
+ /* the break label is already in the tree as a sibling */
+ /* to the original FOR node this tree is replacing */
+ return forTree;
+}
+
+/*-----------------------------------------------------------------*/
+/* searchLitOp - search tree (*ops only) for an ast with literal */
+/*-----------------------------------------------------------------*/
+static ast *
+searchLitOp (ast * tree, ast ** parent, const char *ops)
+{
+ ast *ret;
+
+ if (tree && optimize.global_cse)
+ {
+ /* is there a literal operand? */
+ if (tree->right &&
+ IS_AST_OP (tree->right) &&
+ tree->right->right && (tree->right->opval.op == (unsigned) ops[0] || tree->right->opval.op == (unsigned) ops[1]))
+ {
+ if (IS_LITERAL (RTYPE (tree->right)) != IS_LITERAL (LTYPE (tree->right)))
+ {
+ tree->right->decorated = 0;
+ tree->decorated = 0;
+ *parent = tree;
+ return tree->right;
+ }
+ ret = searchLitOp (tree->right, parent, ops);
+ if (ret)
+ return ret;
+ }
+ if (tree->left &&
+ IS_AST_OP (tree->left) &&
+ tree->left->right && (tree->left->opval.op == (unsigned) ops[0] || tree->left->opval.op == (unsigned) ops[1]))
+ {
+ if (IS_LITERAL (RTYPE (tree->left)) != IS_LITERAL (LTYPE (tree->left)))
+ {
+ tree->left->decorated = 0;
+ tree->decorated = 0;
+ *parent = tree;
+ return tree->left;
+ }
+ ret = searchLitOp (tree->left, parent, ops);
+ if (ret)
+ return ret;
+ }
+ }
+ return NULL;
+}
+
+const char *
+getResultTypeName (RESULT_TYPE resultType)
+{
+ switch (resultType)
+ {
+ case RESULT_TYPE_NONE: return "RESULT_TYPE_NONE";
+ case RESULT_TYPE_BOOL: return "RESULT_TYPE_BOOL";
+ case RESULT_TYPE_CHAR: return "RESULT_TYPE_CHAR";
+ case RESULT_TYPE_INT: return "RESULT_TYPE_INT";
+ case RESULT_TYPE_OTHER: return "RESULT_TYPE_OTHER";
+ case RESULT_TYPE_IFX: return "RESULT_TYPE_IFX";
+ case RESULT_TYPE_GPTR: return "RESULT_TYPE_GPTR";
+ }
+ return "invalid result type";
+}
+
+/*-----------------------------------------------------------------*/
+/* getResultFromType */
+/*-----------------------------------------------------------------*/
+RESULT_TYPE
+getResultTypeFromType (sym_link * type)
+{
+ /* type = getSpec (type); */
+ if (IS_BOOLEAN (type))
+ return RESULT_TYPE_BOOL;
+ if (IS_BITFIELD (type))
+ {
+ unsigned blen = SPEC_BLEN (type);
+
+/* BOOL and single bit BITFIELD are not interchangeable!
+ * There must be a cast to do this safely, in which case
+ * the previous IS_BOOLEAN test will handle it.
+
+ if (blen <= 1)
+ return RESULT_TYPE_BOOL;
+*/
+ if (blen <= 8)
+ return RESULT_TYPE_CHAR;
+ return RESULT_TYPE_INT;
+ }
+ if (IS_CHAR (type))
+ return RESULT_TYPE_CHAR;
+ if (IS_INT (type) && !IS_LONG (type) && !IS_LONGLONG (type))
+ return RESULT_TYPE_INT;
+ return RESULT_TYPE_OTHER;
+}
+
+/*-----------------------------------------------------------------*/
+/* addCast - adds casts to a type specified by RESULT_TYPE */
+/*-----------------------------------------------------------------*/
+static ast *
+addCast (ast * tree, RESULT_TYPE resultType, bool promote)
+{
+ sym_link *newLink;
+ bool upCasted = FALSE;
+
+ switch (resultType)
+ {
+ case RESULT_TYPE_NONE:
+ /* if thing smaller than int must be promoted to int */
+ if (!promote || getSize (tree->etype) >= INTSIZE)
+ /* promotion not necessary or already an int */
+ return tree;
+ /* char and bits: promote to int */
+ newLink = newIntLink ();
+ upCasted = TRUE;
+ break;
+ case RESULT_TYPE_BOOL:
+ if (!promote ||
+ /* already an int */
+ bitsForType (tree->etype) >= 16 ||
+ /* bit to bit operation: don't promote, the code generators
+ hopefully know everything about promotion rules */
+ bitsForType (tree->etype) == 1)
+ return tree;
+ newLink = newIntLink ();
+ upCasted = TRUE;
+ break;
+ case RESULT_TYPE_CHAR:
+ if (IS_CHAR (tree->etype) || IS_FLOAT (tree->etype) || IS_FIXED (tree->etype))
+ return tree;
+ newLink = newCharLink ();
+ break;
+ case RESULT_TYPE_INT:
+ case RESULT_TYPE_GPTR:
+#if 0
+ if (getSize (tree->etype) > INTSIZE)
+ {
+ /* warn ("Loosing significant digits"); */
+ return;
+ }
+#endif
+ /* char: promote to int */
+ if (!promote || getSize (tree->etype) >= INTSIZE)
+ return tree;
+ newLink = newIntLink ();
+ upCasted = TRUE;
+ break;
+ case RESULT_TYPE_IFX:
+ case RESULT_TYPE_OTHER:
+ if (!promote ||
+ /* return type is ifx, long, float: promote char to int */
+ getSize (tree->etype) >= INTSIZE)
+ return tree;
+ newLink = newIntLink ();
+ upCasted = TRUE;
+ break;
+ default:
+ return tree;
+ }
+ tree->decorated = 0;
+ tree = newNode (CAST, newAst_LINK (newLink), tree);
+ tree->filename = tree->right->filename;
+ tree->lineno = tree->right->lineno;
+ /* keep unsigned type during cast to smaller type,
+ but not when promoting from char to int */
+ if (!upCasted)
+ SPEC_USIGN (tree->left->opval.lnk) = IS_UNSIGNED (tree->right->etype) ? 1 : 0;
+ return decorateType (tree, resultType);
+}
+
+/*-----------------------------------------------------------------*/
+/* resultTypePropagate - decides if resultType can be propagated */
+/*-----------------------------------------------------------------*/
+static RESULT_TYPE
+resultTypePropagate (ast *tree, RESULT_TYPE resultType)
+{
+ switch (tree->opval.op)
+ {
+ case AND_OP:
+ case OR_OP:
+ case '!':
+ /* Logical operators should always propagate to boolean */
+ return RESULT_TYPE_BOOL;
+ case '=':
+ case '?':
+ case ':':
+ case '|':
+ case '^':
+ case '~':
+ case LEFT_OP:
+ case LABEL:
+ case GETHBIT:
+ case GETABIT:
+ case GETBYTE:
+ case GETWORD:
+ return resultType;
+ case '*':
+ case '+':
+ case '-':
+ if ((IS_AST_VALUE (tree->left) && !IS_INTEGRAL (tree->left->opval.val->etype)) ||
+ (IS_AST_VALUE (tree->right) && !IS_INTEGRAL (tree->right->opval.val->etype)))
+ return RESULT_TYPE_NONE;
+ return resultType;
+ case '&':
+ if (!tree->right)
+ /* can be unary */
+ return RESULT_TYPE_NONE;
+ else
+ return resultType;
+ case IFX:
+ return RESULT_TYPE_IFX;
+ default:
+ return RESULT_TYPE_NONE;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* getLeftResultType - gets type from left branch for propagation */
+/*-----------------------------------------------------------------*/
+static RESULT_TYPE
+getLeftResultType (ast * tree, RESULT_TYPE resultType)
+{
+ switch (tree->opval.op)
+ {
+ case '=':
+ case CAST:
+ if (IS_GENPTR (LTYPE (tree)))
+ return RESULT_TYPE_GPTR;
+ else if (IS_PTR (LTYPE (tree)))
+ return RESULT_TYPE_NONE;
+ else
+ return getResultTypeFromType (LETYPE (tree));
+ case RETURN:
+ if (IS_PTR (currFunc->type->next))
+ return RESULT_TYPE_NONE;
+ else
+ return getResultTypeFromType (currFunc->type->next);
+ case '[':
+ if (!IS_ARRAY (LTYPE (tree)))
+ return resultType;
+ if (DCL_ELEM (LTYPE (tree)) > 0 && getSize (tree->left->ftype) < 128)
+ return RESULT_TYPE_CHAR; // TODO: Instead of doing this optimization here, do it later on the iCode (where it probably could use a more efficient unsigned char).
+ return resultType;
+ default:
+ return resultType;
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* gatherImplicitVariables: assigns correct type information to */
+/* symbols and values created by replaceAstWithTemporary */
+/* and adds the symbols to the declarations list of the */
+/* innermost block that contains them */
+/*------------------------------------------------------------------*/
+void
+gatherImplicitVariables (ast * tree, ast * block)
+{
+ if (!tree)
+ return;
+
+ if (tree->type == EX_OP && tree->opval.op == BLOCK)
+ {
+ /* keep track of containing scope */
+ block = tree;
+ }
+ if (tree->type == EX_OP && tree->opval.op == '=' && tree->left->type == EX_VALUE && tree->left->opval.val->sym)
+ {
+ symbol *assignee = tree->left->opval.val->sym;
+
+ /* special case for assignment to compiler-generated temporary variable:
+ compute type of RHS, and set the symbol's type to match */
+ if (assignee->type == NULL && assignee->infertype)
+ {
+ ast *dtr = decorateType (resolveSymbols (tree->right), RESULT_TYPE_NONE);
+
+ if (dtr != tree->right)
+ tree->right = dtr;
+
+ assignee->type = copyLinkChain (TTYPE (dtr));
+ assignee->etype = getSpec (assignee->type);
+ SPEC_ADDRSPACE (assignee->etype) = 0;
+ SPEC_SCLS (assignee->etype) = S_AUTO;
+ SPEC_OCLS (assignee->etype) = NULL;
+ SPEC_EXTR (assignee->etype) = 0;
+ SPEC_STAT (assignee->etype) = 0;
+ SPEC_VOLATILE (assignee->etype) = 0;
+ SPEC_ABSA (assignee->etype) = 0;
+ SPEC_CONST (assignee->etype) = 0;
+
+ wassertl (block != NULL, "implicit variable not contained in block");
+ wassert (assignee->next == NULL);
+ if (block != NULL)
+ {
+ symbol **decl = &(block->values.sym);
+
+ while (*decl)
+ {
+ wassert (*decl != assignee); /* should not already be in list */
+ decl = &((*decl)->next);
+ }
+
+ *decl = assignee;
+ }
+ }
+ }
+ if (tree->type == EX_VALUE && !(IS_LITERAL (tree->opval.val->etype)) &&
+ tree->opval.val->type == NULL && tree->opval.val->sym && tree->opval.val->sym->infertype)
+ {
+ /* fixup type of value for compiler-inferred temporary var */
+ tree->opval.val->type = tree->opval.val->sym->type;
+ tree->opval.val->etype = tree->opval.val->sym->etype;
+ }
+
+ gatherImplicitVariables (tree->left, block);
+ gatherImplicitVariables (tree->right, block);
+}
+
+/*-----------------------------------------------------------------*/
+/* CodePtrPointsToConst - if code memory is read-only, then */
+/* pointers to code memory implicitly point to constants. */
+/* Make this explicit. */
+/*-----------------------------------------------------------------*/
+void
+CodePtrPointsToConst (sym_link * t)
+{
+ if (port->mem.code_ro)
+ {
+ while (t && t->next)
+ {
+ if (IS_CODEPTR (t))
+ {
+ sym_link *t2 = t;
+ /* find the first non-array link */
+ while (IS_ARRAY (t2->next))
+ t2 = t2->next;
+ if (IS_SPEC (t2->next))
+ SPEC_CONST (t2->next) = 1;
+ else
+ DCL_PTR_CONST (t2->next) = 1;
+ }
+ t = t->next;
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* checkPtrCast - if casting to/from pointers, do some checking */
+/*-----------------------------------------------------------------*/
+void
+checkPtrCast (sym_link *newType, sym_link *orgType, bool implicit, bool orgIsNullPtrConstant)
+{
+ int errors = 0;
+
+ if (IS_ARRAY (orgType))
+ {
+ value *val;
+ val = aggregateToPointer (valFromType (orgType));
+ orgType = val->type;
+ Safe_free (val);
+ }
+
+ if (IS_PTR (newType)) // to a pointer
+ {
+ if (!IS_PTR (orgType) && !IS_FUNC (orgType) && !IS_AGGREGATE (orgType)) // from a non pointer
+ {
+ if (IS_INTEGRAL (orgType))
+ {
+ // maybe this is NULL, then it's ok.
+ if (!(IS_LITERAL (orgType) && (SPEC_CVAL (orgType).v_ulong == 0)))
+ {
+ if (GPTRSIZE > FARPTRSIZE && IS_GENPTR (newType) && !IS_FUNCPTR (newType))
+ {
+ // no way to set the storage
+ if (IS_LITERAL (orgType))
+ {
+ errors += werror (W_LITERAL_GENERIC);
+ }
+ else
+ {
+ errors += werror (W_NONPTR2_GENPTR);
+ }
+ }
+ else if (implicit)
+ {
+ errors += werror (W_INTEGRAL2PTR_NOCAST);
+ }
+ }
+ }
+ else
+ {
+ // shouldn't do that with float, array or structure unless to void
+ if (!IS_VOID (getSpec (newType)) && !(IS_CODEPTR (newType) && IS_FUNC (newType->next) && IS_FUNC (orgType)))
+ {
+ errors += werror (E_INCOMPAT_TYPES);
+ }
+ }
+ }
+ else // from a pointer to a pointer
+ {
+ if (implicit && getAddrspace (newType->next) != getAddrspace (orgType->next))
+ {
+ errors += werror (E_INCOMPAT_PTYPES);
+ }
+ else if (IS_GENPTR (newType) && IS_VOID (newType->next)) // cast to void* is always allowed
+ {
+ if (IS_FUNCPTR (orgType))
+ errors += werror (FUNCPTRSIZE > GPTRSIZE ? E_INCOMPAT_PTYPES : W_INCOMPAT_PTYPES);
+ }
+ else if (IS_GENPTR (orgType) && IS_VOID (orgType->next)) // cast from void* is always allowed - as long as we cast to a pointer to an object type
+ {
+ if (IS_FUNCPTR (newType) && !orgIsNullPtrConstant) // cast to pointer to function is only allowed for null pointer constants
+ errors += werror (W_INCOMPAT_PTYPES);
+ }
+ else if (GPTRSIZE > FARPTRSIZE /*!TARGET_IS_Z80 && !TARGET_IS_GBZ80 */ )
+ {
+ // if not a pointer to a function
+ if (!(IS_CODEPTR (newType) && IS_FUNC (newType->next) && IS_FUNC (orgType)))
+ {
+ if (implicit) // if not to generic, they have to match
+ {
+ if (!IS_GENPTR (newType) &&
+ !((DCL_TYPE (orgType) == DCL_TYPE (newType)) ||
+ ((DCL_TYPE (orgType) == POINTER) && (DCL_TYPE (newType) == IPOINTER))))
+ {
+ errors += werror (E_INCOMPAT_PTYPES);
+ }
+ }
+ }
+ }
+ }
+ }
+ else // to a non pointer
+ {
+ if (IS_PTR (orgType)) // from a pointer
+ {
+ if (implicit) // sneaky
+ {
+ if (IS_INTEGRAL (newType))
+ {
+ errors += werror (W_PTR2INTEGRAL_NOCAST);
+ }
+ else // shouldn't do that with float, array or structure
+ {
+ errors += werror (E_INCOMPAT_TYPES);
+ }
+ }
+ }
+ }
+ if (errors)
+ {
+ printFromToType (orgType, newType);
+ }
+}
+
+/*-----------------------------*/
+/* check if div or mod by zero */
+/*-----------------------------*/
+static void
+checkZero (value *val)
+{
+ if (!val)
+ return;
+
+ if (IS_FLOAT (val->type) || IS_FIXED16X16 (val->type))
+ {
+ if (floatFromVal (val) == 0.0)
+ werror (E_DIVIDE_BY_ZERO);
+ }
+ else if (SPEC_LONGLONG (val->type))
+ {
+ if (ullFromVal (val) == 0LL)
+ werror (E_DIVIDE_BY_ZERO);
+ }
+ else if (ulFromVal (val) == 0L)
+ {
+ werror (E_DIVIDE_BY_ZERO);
+ }
+}
+
+/*--------------------------------------------------------*/
+/* return true if subtree <search> is somewhere in <tree> */
+/*--------------------------------------------------------*/
+static bool
+isAstInAst (ast *tree, ast *search)
+{
+ if (tree == search)
+ return TRUE;
+ if (!tree)
+ return FALSE;
+ if (tree->type == EX_OP)
+ {
+ if (isAstInAst (tree->left, search))
+ return TRUE;
+ if (isAstInAst (tree->right, search))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*---------------------------------------*/
+/* make a simple copy of single ast node */
+/*---------------------------------------*/
+static ast *
+copyAstNode (ast *tree)
+{
+ ast * newtree;
+
+ newtree = newAst_(tree->type);
+ newtree->lineno = tree->lineno;
+ newtree->filename = tree->filename;
+ newtree->level = tree->level;
+ newtree->block = tree->block;
+ newtree->initMode = tree->initMode;
+ newtree->seqPoint = tree->seqPoint;
+ newtree->funcName = tree->funcName;
+ newtree->reversed = tree->reversed;
+ newtree->decorated = tree->decorated;
+
+ if (tree->ftype)
+ newtree->etype = getSpec (newtree->ftype = copyLinkChain (tree->ftype));
+
+ if (tree->type == EX_VALUE)
+ {
+ newtree->opval.val = tree->opval.val;
+ }
+ else if (tree->type == EX_LINK)
+ {
+ newtree->opval.lnk = tree->opval.lnk;
+ }
+ else
+ {
+ newtree->opval.op = tree->opval.op;
+ copyAstValues (newtree, tree);
+ newtree->left = tree->left;
+ newtree->right = tree->right;
+
+ newtree->trueLabel = tree->trueLabel;
+ newtree->falseLabel = tree->falseLabel;
+ }
+
+ return newtree;
+}
+
+/*-------------------------------------------------*/
+/* extract the ast subtrees that have side-effects */
+/*-------------------------------------------------*/
+static void
+rewriteAstGatherSideEffects (ast *tree, set ** sideEffects)
+{
+ if (!tree)
+ return;
+
+ if (tree->type == EX_OP)
+ {
+ switch (tree->opval.op)
+ {
+ case '=':
+ case INC_OP:
+ case DEC_OP:
+ case CALL:
+ case PCALL:
+ addSetHead (sideEffects, tree);
+ break;
+ default:
+ if (tree->left)
+ rewriteAstGatherSideEffects (tree->left, sideEffects);
+ if (tree->right)
+ rewriteAstGatherSideEffects (tree->right, sideEffects);
+ break;
+ }
+ return;
+ }
+ if (TETYPE (tree) && IS_VOLATILE (TETYPE (tree)))
+ {
+ addSetHead (sideEffects, tree);
+ return;
+ }
+}
+
+/*-------------------------------------------------------------------*/
+/* after rewriting a node, rejoin the portions of any old left/right */
+/* subtree that had side effects with a comma operator */
+/*-------------------------------------------------------------------*/
+static void
+rewriteAstJoinSideEffects (ast *tree, ast *oLeft, ast *oRight)
+{
+ set * sideEffects = NULL;
+ ast * sefTree;
+
+ /* If the old left or right subtree has been orphaned, */
+ /* gather any side-effects in it */
+ if (oLeft && !isAstInAst (tree, oLeft))
+ rewriteAstGatherSideEffects (oLeft, &sideEffects);
+ if (oRight && !isAstInAst (tree, oRight))
+ rewriteAstGatherSideEffects (oRight, &sideEffects);
+
+ /* Join any side-effects found */
+ for (sefTree = setFirstItem (sideEffects); sefTree; sefTree = setNextItem (sideEffects))
+ {
+ tree->right = copyAstNode (tree);
+ tree->left = sefTree;
+ tree->type = EX_OP;
+ tree->opval.op = ',';
+ }
+
+ deleteSet (&sideEffects);
+}
+
+static void
+optStdLibCall (ast *tree, RESULT_TYPE resulttype)
+{
+ ast *parms = tree->right;
+ ast *func = tree->left;
+
+ if (!TARGET_IS_STM8 && !TARGET_Z80_LIKE && !TARGET_PDK_LIKE) // Regression test gcc-torture-execute-20121108-1.c fails to build for hc08 and mcs51 (without --stack-auto)
+ return;
+
+ if (!IS_FUNC (func->ftype) || IS_LITERAL (func->ftype) || func->type != EX_VALUE || !func->opval.val->sym)
+ return;
+
+ const char *funcname = func->opval.val->sym->name;
+
+ unsigned int nparms = 0;
+ ast *parm;
+ for (parm = parms; parm && parm->type == EX_OP && parm->opval.op == PARAM; parm = parm->right)
+ if (parm->left)
+ nparms++;
+ if (parm)
+ nparms++;
+
+ // Optimize printf() to puts().
+ if (!strcmp(funcname, "printf") && nparms == 1 && resulttype == RESULT_TYPE_NONE)
+ {
+ ast *parm = parms;
+
+ if (parm->type == EX_OP && parm->opval.op == CAST)
+ parm = parm->right;
+
+ if (parm->type != EX_VALUE || !IS_ARRAY (parm->opval.val->type) || !parm->opval.val->sym)
+ return;
+
+ size_t strlength = DCL_ELEM (parm->opval.val->type);
+ symbol *strsym = parm->opval.val->sym;
+ sym_link *strlink = strsym->etype;
+
+ if (strsym->isstrlit != 1 || !strlink || !IS_SPEC(strlink) || SPEC_NOUN (strlink) != V_CHAR)
+ return;
+
+ for (size_t i = 0; i < strlength; i++)
+ if (SPEC_CVAL (strlink).v_char[i] == '%')
+ return;
+ if(strlength < 2 || SPEC_CVAL (strlink).v_char[strlength - 2] != '\n')
+ return;
+
+ symbol *puts_sym = findSym (SymbolTab, NULL, "puts");
+
+ if(!puts_sym)
+ return;
+
+ // Do the equivalent of
+ // DCL_ELEM (strsym->type)--;
+ // but in a way that works better with the reuse of string symbols
+ {
+ struct dbuf_s dbuf;
+ dbuf_init (&dbuf, strlength - 1);
+ wassert (dbuf_append (&dbuf, SPEC_CVAL (strlink).v_char, strlength - 1));
+ ((char *)(dbuf_get_buf (&dbuf)))[strlength - 2] = 0;
+
+ parm->opval.val = stringToSymbol (rawStrVal (dbuf_get_buf (&dbuf), strlength - 1));
+ dbuf_destroy (&dbuf);
+
+ freeStringSymbol (strsym);
+ }
+
+ func->opval.val->sym = puts_sym;
+ }
+ // Optimize strcpy() to memcpy().
+ else if (!strcmp(funcname, "strcpy") && nparms == 2)
+ {
+ ast *parm = parms->right;
+
+ if (parm->type == EX_OP && parm->opval.op == CAST)
+ parm = parm->right;
+
+ if (parm->type != EX_VALUE || !IS_ARRAY (parm->opval.val->type) || !parm->opval.val->sym)
+ return;
+
+ size_t strlength = DCL_ELEM (parm->opval.val->type);
+ symbol *strsym = parm->opval.val->sym;
+ sym_link *strlink = strsym->etype;
+
+ if (!strsym->isstrlit || !strlink || !IS_SPEC(strlink) || SPEC_NOUN (strlink) != V_CHAR)
+ return;
+
+ for (size_t i = 0; i < strlength; i++)
+ if (!SPEC_CVAL (strlink).v_char[i])
+ {
+ strlength = i + 1;
+ break;
+ }
+
+ size_t minlength; // Minimum string length for replacement.
+ if (TARGET_IS_STM8)
+ minlength = optimize.codeSize ? SIZE_MAX : 12;
+ else // TODO:Check for other targets when memcpy() is a better choice than strcpy;
+ minlength = SIZE_MAX;
+
+ if (strlength < minlength)
+ return;
+
+ symbol *memcpy_sym = findSym (SymbolTab, NULL, "memcpy");
+
+ if(!memcpy_sym)
+ return;
+
+ ast *lengthparm = newAst_VALUE (valCastLiteral (newIntLink(), strlength, strlength));
+ decorateType (lengthparm, RESULT_TYPE_NONE);
+ ast *node = newAst_OP (PARAM);
+ node->left = parm;
+ node->right = lengthparm;
+ node->decorated = 1;
+ parms->right = node;
+ func->opval.val->sym = memcpy_sym;
+ }
+}
+
+/*--------------------------------------------------------------*/
+/* rewrite ast node as an operator node and rejoin any orphaned */
+/* side-effects with a comma operator */
+/*--------------------------------------------------------------*/
+static void
+rewriteAstNodeOp (ast *tree, int op, ast *left, ast *right)
+{
+ ast *oLeft = (tree->type == EX_OP) ? tree->left : NULL;
+ ast *oRight = (tree->type == EX_OP) ? tree->right : NULL;
+
+ tree->type = EX_OP;
+ tree->opval.op = op;
+ tree->left = left;
+ tree->right = right;
+ tree->decorated = 0;
+
+ rewriteAstJoinSideEffects (tree, oLeft, oRight);
+}
+
+/*----------------------------------------------------------*/
+/* rewrite ast node as a value node and rejoin any orphaned */
+/* side-effects with a comma operator */
+/*----------------------------------------------------------*/
+static void
+rewriteAstNodeVal (ast *tree, value *val)
+{
+ ast *oLeft = (tree->type == EX_OP) ? tree->left : NULL;
+ ast *oRight = (tree->type == EX_OP) ? tree->right : NULL;
+
+ tree->type = EX_VALUE;
+ tree->opval.val = val;
+ tree->left = NULL;
+ tree->right = NULL;
+ TETYPE (tree) = getSpec (TTYPE (tree) = tree->opval.val->type);
+ tree->decorated = 0;
+
+ rewriteAstJoinSideEffects (tree, oLeft, oRight);
+}
+
+/*-----------------------------------------------------------*/
+/* rewrite struct assignment "a = b" to something similar to */
+/* "__builtin_memcpy (&a, &b, sizeof (a)), a" or, if a has */
+/* side effects, "*(__builtin_memcpy (&a, &b, sizeof (a)))" */
+/*-----------------------------------------------------------*/
+ast *
+rewriteStructAssignment (ast *tree)
+{
+ /* prepare pointer to destination */
+ ast *dest = newNode ('&', tree->left, NULL);
+ copyAstLoc (dest, tree->left);
+
+ /* prepare remaining arguments */
+ ast *src = newNode ('&', tree->right, NULL);
+ copyAstLoc (src, tree->right);
+ ast *size = newNode (SIZEOF, NULL, tree->left);
+ copyAstLoc (size, tree->left);
+ ast *srcsize = newNode (PARAM, src, size);
+ copyAstLoc (srcsize, tree);
+ ast *params = newNode (PARAM, dest, srcsize);
+ copyAstLoc (params, tree);
+
+ /* create call to the appropriate memcpy function */
+ ast *memcpy_ast = newAst_VALUE (symbolVal (memcpy_builtin));
+ copyAstLoc (memcpy_ast, tree);
+ ast *call = newNode (CALL, memcpy_ast, params);
+ copyAstLoc (call, tree);
+
+ /* assemble the result expression depending on side effects */
+ ast *newTree;
+ if (hasSEFcalls (dest))
+ {
+ /* memcpy returns the dest pointer -> dereference it */
+ newTree = newNode ('*', call, NULL);
+ }
+ else
+ {
+ /* no side effects -> dereference dest pointer itself */
+ ast *destderef = newNode ('*', dest, NULL);
+ copyAstLoc (destderef, dest);
+ newTree = newNode (',', call, destderef);
+ }
+
+ /* copy source location and return decorated result */
+ copyAstLoc (newTree, tree);
+ return decorateType (newTree, RESULT_TYPE_OTHER);
+}
+
+/*--------------------------------------------------------------------*/
+/* decorateType - compute type for this tree, also does type checking.*/
+/* This is done bottom up, since type has to flow upwards. */
+/* resultType flows top-down and forces e.g. char-arithmetic, if the */
+/* result is a char and the operand(s) are int's. */
+/* It also does constant folding, and parameter checking. */
+/*--------------------------------------------------------------------*/
+ast *
+decorateType (ast *tree, RESULT_TYPE resultType)
+{
+ int parmNumber;
+ sym_link *p;
+ RESULT_TYPE resultTypeProp;
+
+ if (!tree)
+ return tree;
+
+ /* if already has type then do nothing */
+ if (tree->decorated)
+ return tree;
+
+ tree->decorated = 1;
+
+#if 0
+ /* print the line */
+ /* if not block & function */
+ if (tree->type == EX_OP && (tree->opval.op != FUNCTION && tree->opval.op != BLOCK && tree->opval.op != NULLOP))
+ {
+ filename = tree->filename;
+ lineno = tree->lineno;
+ }
+#endif
+
+ /* if any child is an error | this one is an error do nothing */
+ if (tree->isError || (tree->left && tree->left->isError) || (tree->right && tree->right->isError))
+ return tree;
+
+/*------------------------------------------------------------------*/
+/*----------------------------*/
+/* leaf has been reached */
+/*----------------------------*/
+ filename = tree->filename;
+ lineno = tree->lineno;
+ /* if this is of type value */
+ /* just get the type */
+ if (tree->type == EX_VALUE)
+ {
+ if (IS_LITERAL (tree->opval.val->etype))
+ {
+ /* if this is a character array then declare it */
+ if (IS_ARRAY (tree->opval.val->type))
+ tree->opval.val = stringToSymbol (tree->opval.val);
+
+ /* otherwise just copy the type information */
+ COPYTYPE (TTYPE (tree), TETYPE (tree), tree->opval.val->type);
+ return tree;
+ }
+
+ if (tree->opval.val->sym)
+ {
+ /* if the undefined flag is set then give error message */
+ if (tree->opval.val->sym->undefined)
+ {
+ werrorfl (tree->filename, tree->lineno, E_ID_UNDEF, tree->opval.val->sym->name);
+ /* assume int */
+ TTYPE (tree) = TETYPE (tree) =
+ tree->opval.val->type = tree->opval.val->sym->type =
+ tree->opval.val->etype = tree->opval.val->sym->etype = copyLinkChain (INTTYPE);
+ }
+ else if (tree->opval.val->sym->implicit)
+ {
+ /* if implicit i.e. struct/union member then no type */
+ TTYPE (tree) = TETYPE (tree) = NULL;
+ }
+ else
+ {
+ /* copy the type from the value into the ast */
+ COPYTYPE (TTYPE (tree), TETYPE (tree), tree->opval.val->type);
+
+ /* and mark the symbol as referenced */
+ tree->opval.val->sym->isref = 1;
+ }
+ }
+ else
+ {
+ /* unreached: all values are literals or symbols */
+ wassert (0);
+ }
+
+ return tree;
+ }
+
+ /* if type link for the case of cast */
+ if (tree->type == EX_LINK)
+ {
+ COPYTYPE (TTYPE (tree), TETYPE (tree), tree->opval.lnk);
+ return tree;
+ }
+
+ {
+ ast *dtl, *dtr;
+
+#if 0
+ if (tree->opval.op == NULLOP || tree->opval.op == BLOCK)
+ {
+ if (tree->left && tree->left->type == EX_OPERAND
+ && (tree->left->opval.op == INC_OP || tree->left->opval.op == DEC_OP) && tree->left->left)
+ {
+ tree->left->right = tree->left->left;
+ tree->left->left = NULL;
+ }
+ if (tree->right && tree->right->type == EX_OPERAND
+ && (tree->right->opval.op == INC_OP || tree->right->opval.op == DEC_OP) && tree->right->left)
+ {
+ tree->right->right = tree->right->left;
+ tree->right->left = NULL;
+ }
+ }
+#endif
+
+ /* Before decorating the left branch we've to decide in dependence
+ upon tree->opval.op, if resultType can be propagated */
+ resultTypeProp = resultTypePropagate (tree, resultType);
+
+ if ((tree->opval.op == '?') && (resultTypeProp != RESULT_TYPE_BOOL))
+ dtl = decorateType (tree->left, RESULT_TYPE_IFX);
+ else
+ dtl = decorateType (tree->left, resultTypeProp);
+
+ /* if an array node, we may need to swap branches */
+ if (tree->opval.op == '[')
+ {
+ /* determine which is the array & which the index */
+ if ((IS_ARRAY (RTYPE (tree)) || IS_PTR (RTYPE (tree))) && IS_INTEGRAL (LTYPE (tree)))
+ {
+ ast *tempTree = tree->left;
+ tree->left = tree->right;
+ tree->right = tempTree;
+ }
+ }
+
+ /* After decorating the left branch there's type information available
+ in tree->left->?type. If the op is e.g. '=' we extract the type
+ information from there and propagate it to the right branch. */
+ resultTypeProp = getLeftResultType (tree, resultTypeProp);
+
+ switch (tree->opval.op)
+ {
+ case '?':
+ /* delay right side for '?' operator since conditional macro
+ expansions might rely on this */
+ dtr = tree->right;
+ break;
+ case CALL:
+ /* decorate right side for CALL (parameter list) in processParms();
+ there is resultType available */
+ dtr = tree->right;
+ break;
+ case SIZEOF:
+ /* don't allocate string if it is a sizeof argument */
+ ++noAlloc;
+ dtr = decorateType (tree->right, resultTypeProp);
+ --noAlloc;
+ break;
+ default:
+ dtr = decorateType (tree->right, resultTypeProp);
+ break;
+ }
+
+ /* this is to take care of situations
+ when the tree gets rewritten */
+ if (dtl != tree->left)
+ tree->left = dtl;
+ if (dtr != tree->right)
+ tree->right = dtr;
+ if ((dtl && dtl->isError) || (dtr && dtr->isError))
+ return tree;
+ }
+
+ /* depending on type of operator do */
+
+ switch (tree->opval.op)
+ {
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* array node */
+ /*----------------------------*/
+ case '[':
+ /* Swap trees if right side is array or a pointer */
+ if (IS_ARRAY (RTYPE (tree)) || IS_PTR (RTYPE (tree)))
+ {
+ ast *tTree = tree->left;
+ tree->left = tree->right;
+ tree->right = tTree;
+ }
+
+ /* check if this is an array or a pointer */
+ if ((!IS_ARRAY (LTYPE (tree))) && (!IS_PTR (LTYPE (tree))))
+ {
+ werrorfl (tree->filename, tree->lineno, E_NEED_ARRAY_PTR, "[]");
+ goto errorTreeReturn;
+ }
+
+ /* check the type of the idx */
+ if (!IS_INTEGRAL (RTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_IDX_NOT_INT);
+ goto errorTreeReturn;
+ }
+
+ /* if the left is an rvalue then error */
+ if (LRVAL (tree))
+ {
+ werrorfl (tree->filename, tree->lineno, E_LVALUE_REQUIRED, "array access");
+ goto errorTreeReturn;
+ }
+
+ if (IS_LITERAL (RTYPE (tree)))
+ {
+ int arrayIndex = (int) ulFromVal (valFromType (RETYPE (tree)));
+ int arraySize = DCL_ELEM (LTYPE (tree));
+ if (arraySize && arrayIndex >= arraySize)
+ {
+ werrorfl (tree->filename, tree->lineno, W_IDX_OUT_OF_BOUNDS, arrayIndex, arraySize);
+ }
+ }
+
+ RRVAL (tree) = 1;
+ TTYPE (tree) = copyLinkChain (LTYPE (tree)->next);
+ TETYPE (tree) = getSpec (TTYPE (tree));
+
+ if (IS_PTR (LTYPE (tree)) /* && !IS_LITERAL (TETYPE (tree)) caused bug #2850 */)
+ {
+ SPEC_SCLS (TETYPE (tree)) = sclsFromPtr (LTYPE (tree));
+ }
+
+ return tree;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* struct/union */
+ /*----------------------------*/
+ case '.':
+ /* if this is not a structure */
+ if (!IS_STRUCT (LTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_STRUCT_UNION, ".");
+ goto errorTreeReturn;
+ }
+ TTYPE (tree) = structElemType (LTYPE (tree), (tree->right->type == EX_VALUE ? tree->right->opval.val : NULL));
+ TETYPE (tree) = getSpec (TTYPE (tree));
+ return tree;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* struct/union pointer */
+ /*----------------------------*/
+ case PTR_OP:
+ /* if not pointer to a structure */
+ if (!IS_PTR (LTYPE (tree)) && !IS_ARRAY (LTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_PTR_REQD);
+ goto errorTreeReturn;
+ }
+
+ if (!IS_STRUCT (LTYPE (tree)->next))
+ {
+ werrorfl (tree->filename, tree->lineno, E_STRUCT_UNION, "->");
+ goto errorTreeReturn;
+ }
+
+ TTYPE (tree) = structElemType (LTYPE (tree)->next, (tree->right->type == EX_VALUE ? tree->right->opval.val : NULL));
+ TETYPE (tree) = getSpec (TTYPE (tree));
+
+ /* adjust the storage class */
+ if (DCL_TYPE (LTYPE (tree)) != ARRAY)
+ {
+ setOClass (LTYPE (tree), TETYPE (tree));
+ SPEC_SCLS (TETYPE (tree)) = sclsFromPtr (LTYPE (tree));
+ SPEC_ADDRSPACE (TETYPE (tree)) = DCL_PTR_ADDRSPACE (LTYPE (tree));
+ }
+ /* This breaks with extern declarations, bit-fields, and perhaps other */
+ /* cases (gcse). Let's leave this optimization disabled for now and */
+ /* ponder if there's a safe way to do this. -- EEP */
+#if 0
+ if (IS_ADDRESS_OF_OP (tree->left) && IS_AST_SYM_VALUE (tree->left->left)
+ && SPEC_ABSA (AST_SYMBOL (tree->left->left)->etype))
+ {
+ /* If defined struct type at addr var
+ then rewrite (&struct var)->member
+ as temp
+ and define membertype at (addr+offsetof(struct var,member)) temp
+ */
+ symbol *sym;
+ symbol *element = getStructElement (SPEC_STRUCT (LETYPE (tree)),
+ AST_SYMBOL (tree->right));
+
+ sym = newSymbol (genSymName (0), 0);
+ sym->type = TTYPE (tree);
+ sym->etype = getSpec (sym->type);
+ sym->lineDef = tree->lineno;
+ sym->cdef = 1;
+ sym->isref = 1;
+ SPEC_STAT (sym->etype) = 1;
+ SPEC_ADDR (sym->etype) = SPEC_ADDR (AST_SYMBOL (tree->left->left)->etype) + element->offset;
+ SPEC_ABSA (sym->etype) = 1;
+ addSym (SymbolTab, sym, sym->name, 0, 0, 0);
+ allocGlobal (sym);
+
+ AST_VALUE (tree) = symbolVal (sym);
+ TLVAL (tree) = 1;
+ TRVAL (tree) = 0;
+ tree->type = EX_VALUE;
+ tree->left = NULL;
+ tree->right = NULL;
+ }
+#endif
+
+ return tree;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* ++/-- operation */
+ /*----------------------------*/
+ case INC_OP:
+ case DEC_OP:
+ {
+ sym_link *ltc = (tree->right ? RTYPE (tree) : LTYPE (tree));
+ COPYTYPE (TTYPE (tree), TETYPE (tree), ltc);
+ if (!tree->initMode && IS_CONSTANT (TTYPE (tree)))
+ werrorfl (tree->filename, tree->lineno, E_CODE_WRITE, tree->opval.op == INC_OP ? "++" : "--");
+
+ if (tree->right)
+ RLVAL (tree) = 1;
+ else
+ LLVAL (tree) = 1;
+ return tree;
+ }
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* bitwise and */
+ /*----------------------------*/
+ case '&': /* can be unary */
+ /* if right is NULL then unary operation */
+ if (tree->right) /* not a unary operation */
+ {
+ ast *otree;
+
+ if (!IS_INTEGRAL (LTYPE (tree)) || !IS_INTEGRAL (RTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_BITWISE_OP);
+ werrorfl (tree->filename, tree->lineno, W_CONTINUE, "left & right types are ");
+ printTypeChain (LTYPE (tree), stderr);
+ fprintf (stderr, ",");
+ printTypeChain (RTYPE (tree), stderr);
+ fprintf (stderr, "\n");
+ goto errorTreeReturn;
+ }
+
+ /* if they are both literal */
+ if (IS_LITERAL (RTYPE (tree)) && IS_LITERAL (LTYPE (tree)))
+ {
+ tree->type = EX_VALUE;
+ tree->opval.val = valBitwise (valFromType (LETYPE (tree)), valFromType (RETYPE (tree)), '&');
+
+ tree->right = tree->left = NULL;
+ TETYPE (tree) = tree->opval.val->etype;
+ TTYPE (tree) = tree->opval.val->type;
+ return tree;
+ }
+
+ /* if left is a literal exchange left & right */
+ if (IS_LITERAL (LTYPE (tree)))
+ {
+ ast *tTree = tree->left;
+ tree->left = tree->right;
+ tree->right = tTree;
+ }
+
+ /* if right is a literal and */
+ /* we can find a 2nd literal in an and-tree then */
+ /* rearrange the tree */
+ if (IS_LITERAL (RTYPE (tree)))
+ {
+ ast *parent;
+ ast *litTree = searchLitOp (tree, &parent, "&");
+ if (litTree)
+ {
+ DEBUG_CF ("&") ast *tTree = litTree->left;
+ litTree->left = tree->right;
+ tree->right = tTree;
+ /* both operands in litTree are literal now */
+ decorateType (parent, resultType);
+ }
+ }
+
+ /* if ANDing boolean with literal then reduce literal LSB to boolean */
+ if (IS_LITERAL (RTYPE (tree)) && IS_BOOLEAN (LTYPE (tree)))
+ {
+ unsigned long litval = AST_ULONG_VALUE (tree->right);
+ tree->right = decorateType (newAst_VALUE (constBoolVal (litval & 1)), resultType);
+ }
+
+ /* see if this is a GETHBIT operation if yes
+ then return that */
+ otree = optimizeGetHbit (tree, resultType);
+ if (otree != tree)
+ return decorateType (otree, RESULT_TYPE_NONE);
+
+ /* see if this is a GETABIT operation if yes
+ then return that */
+ otree = optimizeGetAbit (tree, resultType);
+ if (otree != tree)
+ return decorateType (otree, RESULT_TYPE_NONE);
+
+ /* see if this is a GETBYTE operation if yes
+ then return that */
+ otree = optimizeGetByte (tree, resultType);
+ if (otree != tree)
+ return decorateType (otree, RESULT_TYPE_NONE);
+
+ /* see if this is a GETWORD operation if yes
+ then return that */
+ otree = optimizeGetWord (tree, resultType);
+ if (otree != tree)
+ return decorateType (otree, RESULT_TYPE_NONE);
+
+ /* if right is a literal and has the same size with left,
+ then also sync their signess to avoid unecessary cast */
+ if (IS_LITERAL (RTYPE (tree)) && getSize (RTYPE (tree)) == getSize (LTYPE (tree)))
+ SPEC_USIGN (RTYPE (tree)) = SPEC_USIGN (LTYPE (tree));
+
+ LRVAL (tree) = RRVAL (tree) = 1;
+
+ TTYPE (tree) = computeType (LTYPE (tree), RTYPE (tree), resultType, tree->opval.op);
+ TETYPE (tree) = getSpec (TTYPE (tree));
+
+ return tree;
+ }
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* address of */
+ /*----------------------------*/
+ if (IS_FUNC (LTYPE (tree)))
+ {
+ // this ought to be ignored
+ return (tree->left);
+ }
+
+ /* if bit field then error */
+ if (IS_BITFIELD (tree->left->etype) || (IS_BITVAR (tree->left->etype) && TARGET_MCS51_LIKE))
+ {
+ werrorfl (tree->filename, tree->lineno, E_ILLEGAL_ADDR, "address of bit variable");
+ goto errorTreeReturn;
+ }
+
+ if (LETYPE (tree) && SPEC_SCLS (tree->left->etype) == S_REGISTER)
+ {
+ werrorfl (tree->filename, tree->lineno, E_ILLEGAL_ADDR, "address of register variable");
+ goto errorTreeReturn;
+ }
+
+ if (IS_LITERAL (LTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_ILLEGAL_ADDR, "address of literal");
+ goto errorTreeReturn;
+ }
+
+ if (LRVAL (tree))
+ {
+ werrorfl (tree->filename, tree->lineno, E_LVALUE_REQUIRED, "address of");
+ goto errorTreeReturn;
+ }
+
+ p = newLink (DECLARATOR);
+ if (!LETYPE (tree))
+ DCL_TYPE (p) = POINTER;
+ else if (SPEC_SCLS (LETYPE (tree)) == S_CODE)
+ DCL_TYPE (p) = CPOINTER;
+ else if (SPEC_SCLS (LETYPE (tree)) == S_XDATA)
+ DCL_TYPE (p) = FPOINTER;
+ else if (SPEC_SCLS (LETYPE (tree)) == S_XSTACK)
+ DCL_TYPE (p) = PPOINTER;
+ else if (SPEC_SCLS (LETYPE (tree)) == S_IDATA)
+ DCL_TYPE (p) = IPOINTER;
+ else if (SPEC_SCLS (LETYPE (tree)) == S_EEPROM)
+ DCL_TYPE (p) = EEPPOINTER;
+ else if (SPEC_OCLS (LETYPE (tree)))
+ DCL_TYPE (p) = PTR_TYPE (SPEC_OCLS (LETYPE (tree)));
+ else
+ DCL_TYPE (p) = POINTER;
+
+ if (IS_AST_SYM_VALUE (tree->left))
+ {
+ AST_SYMBOL (tree->left)->addrtaken = 1;
+ AST_SYMBOL (tree->left)->allocreq = 1;
+ }
+
+ p->next = LTYPE (tree);
+ TTYPE (tree) = p;
+ TETYPE (tree) = getSpec (TTYPE (tree));
+ LLVAL (tree) = 1;
+ TLVAL (tree) = 1;
+
+#if 0
+ if (IS_AST_OP (tree->left) && tree->left->opval.op == PTR_OP
+ && IS_AST_VALUE (tree->left->left) && !IS_AST_SYM_VALUE (tree->left->left))
+ {
+ symbol *element = getStructElement (SPEC_STRUCT (LETYPE (tree->left)),
+ AST_SYMBOL (tree->left->right));
+ AST_VALUE (tree) = valPlus (AST_VALUE (tree->left->left), valueFromLit (element->offset));
+ tree->left = NULL;
+ tree->right = NULL;
+ tree->type = EX_VALUE;
+ tree->values.cast.literalFromCast = 1;
+ }
+#endif
+
+ return tree;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* bitwise or */
+ /*----------------------------*/
+ case '|':
+ /* if the rewrite succeeds then don't go any further */
+ {
+ ast *wtree = optimizeRRCRLC (tree);
+ if (wtree != tree)
+ return decorateType (wtree, RESULT_TYPE_NONE);
+
+ wtree = optimizeSWAP (tree);
+ if (wtree != tree)
+ return decorateType (wtree, RESULT_TYPE_NONE);
+ }
+
+ /* if left is a literal exchange left & right */
+ if (IS_LITERAL (LTYPE (tree)))
+ {
+ ast *tTree = tree->left;
+ tree->left = tree->right;
+ tree->right = tTree;
+ }
+
+ /* if right is a literal and */
+ /* we can find a 2nd literal in an or-tree then */
+ /* rearrange the tree */
+ if (IS_LITERAL (RTYPE (tree)))
+ {
+ ast *parent;
+ ast *litTree = searchLitOp (tree, &parent, "|");
+ if (litTree)
+ {
+ DEBUG_CF ("|") ast *tTree = litTree->left;
+ litTree->left = tree->right;
+ tree->right = tTree;
+ /* both operands in tTree are literal now */
+ decorateType (parent, resultType);
+ }
+ }
+
+ /* if ORing boolean with literal then reduce literal to boolean */
+ if (IS_LITERAL (RTYPE (tree)) &&
+ IS_BOOLEAN (LTYPE (tree)) &&
+ IS_INTEGRAL (RTYPE (tree)) &&
+ resultType == RESULT_TYPE_BOOL)
+ {
+ unsigned long litval = AST_ULONG_VALUE (tree->right);
+ tree->right = decorateType (newAst_VALUE (constBoolVal (litval != 0)), resultType);
+ }
+
+ /* fall through */
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* bitwise xor */
+ /*----------------------------*/
+ case '^':
+ if (!IS_INTEGRAL (LTYPE (tree)) || !IS_INTEGRAL (RTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_BITWISE_OP);
+ werrorfl (tree->filename, tree->lineno, W_CONTINUE, "left & right types are ");
+ printTypeChain (LTYPE (tree), stderr);
+ fprintf (stderr, ",");
+ printTypeChain (RTYPE (tree), stderr);
+ fprintf (stderr, "\n");
+ goto errorTreeReturn;
+ }
+
+ /* if they are both literal then rewrite the tree */
+ if (IS_LITERAL (RTYPE (tree)) && IS_LITERAL (LTYPE (tree)))
+ {
+ rewriteAstNodeVal (tree, valBitwise (valFromType (LETYPE (tree)), valFromType (RETYPE (tree)), tree->opval.op));
+ return decorateType (tree, resultType);
+ }
+
+ /* if left is a literal exchange left & right */
+ if (IS_LITERAL (LTYPE (tree)))
+ {
+ ast *tTree = tree->left;
+ tree->left = tree->right;
+ tree->right = tTree;
+ }
+
+ /* if right is a literal and */
+ /* we can find a 2nd literal in a xor-tree then */
+ /* rearrange the tree */
+ if (IS_LITERAL (RTYPE (tree)) && tree->opval.op == '^') /* the same source is used by 'bitwise or' */
+ {
+ ast *parent;
+ ast *litTree = searchLitOp (tree, &parent, "^");
+ if (litTree)
+ {
+ DEBUG_CF ("^") ast *tTree = litTree->left;
+ litTree->left = tree->right;
+ tree->right = tTree;
+ /* both operands in litTree are literal now */
+ decorateType (parent, resultType);
+ }
+ }
+
+ /* if XORing boolean with literal then reduce literal to boolean */
+ if (IS_LITERAL (RTYPE (tree)) &&
+ IS_BOOLEAN (LTYPE (tree)) &&
+ IS_INTEGRAL (RTYPE (tree)) &&
+ resultType == RESULT_TYPE_BOOL &&
+ tree->opval.op == '^') /* the same source is used by 'bitwise or' */
+ {
+ unsigned long litval = AST_ULONG_VALUE (tree->right);
+ if (litval == 0 || litval == 1)
+ {
+ tree->right = decorateType (newAst_VALUE (constBoolVal (litval != 0)), resultType);
+ }
+ else
+ {
+ tree->opval.op = '|';
+ tree->right = newAst_VALUE (constBoolVal (1));
+ tree->decorated = 0;
+ return decorateType (tree, resultType);
+ }
+ }
+
+ /* if right is a literal and has the same size with left,
+ then also sync their signess to avoid unecessary cast */
+ if (IS_LITERAL (RTYPE (tree)) && getSize (RTYPE (tree)) == getSize (LTYPE (tree)))
+ SPEC_USIGN (RTYPE (tree)) = SPEC_USIGN (LTYPE (tree));
+
+ LRVAL (tree) = RRVAL (tree) = 1;
+
+ TTYPE (tree) = computeType (LTYPE (tree), RTYPE (tree), resultType, tree->opval.op);
+ TETYPE (tree) = getSpec (TTYPE (tree));
+
+ return tree;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* division */
+ /*----------------------------*/
+ case '/':
+ if (!IS_ARITHMETIC (LTYPE (tree)) || !IS_ARITHMETIC (RTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_INVALID_OP, "divide");
+ goto errorTreeReturn;
+ }
+ /* check if div by zero */
+ if (IS_LITERAL (RTYPE (tree)) && !IS_LITERAL (LTYPE (tree)))
+ checkZero (valFromType (RETYPE (tree)));
+ /* if they are both literal then */
+ /* rewrite the tree */
+ if (IS_LITERAL (RTYPE (tree)) && IS_LITERAL (LTYPE (tree)))
+ {
+ rewriteAstNodeVal (tree, valDiv (valFromType (LETYPE (tree)), valFromType (RETYPE (tree))));
+ return decorateType (tree, resultType);
+ }
+
+ LRVAL (tree) = RRVAL (tree) = 1;
+
+ TETYPE (tree) = getSpec (TTYPE (tree) = computeType (LTYPE (tree), RTYPE (tree), resultType, tree->opval.op));
+
+ /* if right is a literal and */
+ /* left is also a division by a literal then */
+ /* rearrange the tree */
+#if 0
+ /* This converts (a/b)/c into a/(b*c)/1, where b and c are literals. */
+ /* Algebraically, this is fine, but may fail as an optimization if */
+ /* b*c overflows or causes the expression to have a different resultant */
+ /* type. I don't think it's worth the effort to sort out the cases of */
+ /* when this is safe or not safe, so I am just going to leave this */
+ /* disabled. -- EEP -- 15 Nov 2012 */
+ if (IS_LITERAL (RTYPE (tree))
+ /* avoid infinite loop */
+ && (TYPE_TARGET_ULONG) ulFromVal (tree->right->opval.val) != 1)
+ {
+ ast *parent;
+ ast *litTree = searchLitOp (tree, &parent, "/");
+ if (litTree)
+ {
+ if (IS_LITERAL (RTYPE (litTree)))
+ {
+ /* foo_div */
+ DEBUG_CF ("div r") litTree->right = newNode ('*', litTree->right, copyAst (tree->right));
+ litTree->right->filename = tree->filename;
+ litTree->right->lineno = tree->lineno;
+
+ tree->right->opval.val = constCharVal (1);
+ decorateType (parent, resultType);
+ }
+ else
+ {
+ /* litTree->left is literal: no gcse possible.
+ We can't call decorateType(parent, RESULT_TYPE_NONE), because
+ this would cause an infinit loop. */
+ parent->decorated = 1;
+ decorateType (litTree, resultType);
+ }
+ }
+ }
+#endif
+
+ return tree;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* modulus */
+ /*----------------------------*/
+ case '%':
+ if (!IS_INTEGRAL (LTYPE (tree)) || !IS_INTEGRAL (RTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_BITWISE_OP);
+ werrorfl (tree->filename, tree->lineno, W_CONTINUE, "left & right types are ");
+ printTypeChain (LTYPE (tree), stderr);
+ fprintf (stderr, ",");
+ printTypeChain (RTYPE (tree), stderr);
+ fprintf (stderr, "\n");
+ goto errorTreeReturn;
+ }
+ /* check if div by zero */
+ if (IS_LITERAL (RTYPE (tree)) && !IS_LITERAL (LTYPE (tree)))
+ checkZero (valFromType (RETYPE (tree)));
+ /* if they are both literal then */
+ /* rewrite the tree */
+ if (IS_LITERAL (RTYPE (tree)) && IS_LITERAL (LTYPE (tree)))
+ {
+ rewriteAstNodeVal (tree, valMod (valFromType (LETYPE (tree)), valFromType (RETYPE (tree))));
+ return decorateType (tree, resultType);
+ }
+ LRVAL (tree) = RRVAL (tree) = 1;
+ TETYPE (tree) = getSpec (TTYPE (tree) = computeType (LTYPE (tree), RTYPE (tree), resultType, tree->opval.op));
+ return tree;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* address dereference */
+ /*----------------------------*/
+ case '*': /* can be unary : if right is null then unary operation */
+ if (!tree->right)
+ {
+ if (!IS_PTR (LTYPE (tree)) && !IS_ARRAY (LTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_PTR_REQD);
+ goto errorTreeReturn;
+ }
+
+ if (LRVAL (tree))
+ {
+ werrorfl (tree->filename, tree->lineno, E_LVALUE_REQUIRED, "pointer deref");
+ goto errorTreeReturn;
+ }
+ if (IS_ADDRESS_OF_OP (tree->left))
+ {
+ /* replace *&obj with obj */
+ return tree->left->left;
+ }
+ TTYPE (tree) = copyLinkChain (LTYPE (tree)->next);
+ TETYPE (tree) = getSpec (TTYPE (tree));
+ /* adjust the storage class */
+ if (DCL_TYPE (tree->left->ftype) != ARRAY && DCL_TYPE (tree->left->ftype) != FUNCTION)
+ SPEC_SCLS (TETYPE (tree)) = sclsFromPtr (tree->left->ftype);
+
+ return tree;
+ }
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* multiplication */
+ /*----------------------------*/
+ if (!IS_ARITHMETIC (LTYPE (tree)) || !IS_ARITHMETIC (RTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_INVALID_OP, "multiplication");
+ goto errorTreeReturn;
+ }
+
+ /* if they are both literal then */
+ /* rewrite the tree */
+ if (IS_LITERAL (RTYPE (tree)) && IS_LITERAL (LTYPE (tree)))
+ {
+ rewriteAstNodeVal (tree, valMult (valFromType (LETYPE (tree)), valFromType (RETYPE (tree))));
+ return decorateType (tree, resultType);
+ }
+
+ /* if left is a literal exchange left & right */
+ if (IS_LITERAL (LTYPE (tree)))
+ {
+ ast *tTree = tree->left;
+ tree->left = tree->right;
+ tree->right = tTree;
+ }
+
+ /* if right is a literal and */
+ /* we can find a 2nd literal in a mul-tree then */
+ /* rearrange the tree */
+ if (IS_LITERAL (RTYPE (tree)))
+ {
+ ast *parent;
+ ast *litTree = searchLitOp (tree, &parent, "*");
+ if (litTree)
+ {
+ DEBUG_CF ("mul") ast *tTree = litTree->left;
+ litTree->left = tree->right;
+ tree->right = tTree;
+ /* both operands in litTree are literal now */
+ decorateType (parent, resultType);
+ }
+ }
+
+ LRVAL (tree) = RRVAL (tree) = 1;
+
+ { // cast happen only if both left and right can be casted to result type
+ ast *l = addCast (tree->left, resultTypeProp, FALSE);
+ ast *r = addCast (tree->right, resultTypeProp, FALSE);
+ if (l != tree->left && r != tree->right)
+ {
+ tree->left = l;
+ tree->right = r;
+ }
+ }
+ TETYPE (tree) = getSpec (TTYPE (tree) = computeType (LTYPE (tree), RTYPE (tree), resultType, tree->opval.op));
+
+ return tree;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* unary '+' operator */
+ /*----------------------------*/
+ case '+':
+ /* if unary plus */
+ if (!tree->right)
+ {
+ if (!IS_ARITHMETIC (LTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_UNARY_OP, '+');
+ goto errorTreeReturn;
+ }
+
+ /* if left is a literal then do it */
+ if (IS_LITERAL (LTYPE (tree)))
+ {
+ tree->type = EX_VALUE;
+ tree->opval.val = valFromType (LETYPE (tree));
+ tree->left = NULL;
+ TETYPE (tree) = TTYPE (tree) = tree->opval.val->type;
+ return tree;
+ }
+ LRVAL (tree) = 1;
+ COPYTYPE (TTYPE (tree), TETYPE (tree), LTYPE (tree));
+ return tree;
+ }
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* addition */
+ /*----------------------------*/
+
+ /* this is not a unary operation */
+ /* if both pointers then problem */
+ if ((IS_PTR (LTYPE (tree)) || IS_ARRAY (LTYPE (tree))) && (IS_PTR (RTYPE (tree)) || IS_ARRAY (RTYPE (tree))))
+ {
+ werrorfl (tree->filename, tree->lineno, E_PTR_PLUS_PTR);
+ goto errorTreeReturn;
+ }
+
+ if (!IS_ARITHMETIC (LTYPE (tree)) && !IS_PTR (LTYPE (tree)) && !IS_ARRAY (LTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_PLUS_INVALID, "+");
+ goto errorTreeReturn;
+ }
+
+ if (!IS_ARITHMETIC (RTYPE (tree)) && !IS_PTR (RTYPE (tree)) && !IS_ARRAY (RTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_PLUS_INVALID, "+");
+ goto errorTreeReturn;
+ }
+ /* if they are both literal then */
+ /* rewrite the tree */
+ if (IS_LITERAL (RTYPE (tree)) && IS_LITERAL (LTYPE (tree)))
+ {
+ tree->left = addCast (tree->left, resultTypeProp, TRUE);
+ tree->right = addCast (tree->right, resultTypeProp, TRUE);
+ rewriteAstNodeVal (tree, valPlus (valFromType (LETYPE (tree)), valFromType (RETYPE (tree))));
+ return decorateType (tree, resultType);
+ }
+
+ /* if the right is a pointer or left is a literal
+ xchange left & right */
+ if (IS_ARRAY (RTYPE (tree)) || IS_PTR (RTYPE (tree)) || IS_LITERAL (LTYPE (tree)))
+ {
+ ast *tTree = tree->left;
+ tree->left = tree->right;
+ tree->right = tTree;
+ }
+
+ /* if right is a literal and */
+ /* left is also an addition/subtraction with a literal then */
+ /* rearrange the tree */
+ if (IS_LITERAL (RTYPE (tree)))
+ {
+ ast *litTree, *parent;
+ litTree = searchLitOp (tree, &parent, "+-");
+ if (litTree)
+ {
+ if (litTree->opval.op == '+')
+ {
+ /* foo_aa */
+ DEBUG_CF ("+ 1 AA") ast *tTree = litTree->left;
+ litTree->left = tree->right;
+ tree->right = tree->left;
+ tree->left = tTree;
+ }
+ else if (litTree->opval.op == '-')
+ {
+ if (IS_LITERAL (RTYPE (litTree)))
+ {
+ DEBUG_CF ("+ 2 ASR")
+ /* foo_asr */
+ ast *tTree = litTree->left;
+ litTree->left = tree->right;
+ tree->right = tTree;
+ }
+ else
+ {
+ DEBUG_CF ("+ 3 ASL")
+ /* foo_asl */
+ ast *tTree = litTree->right;
+ litTree->right = tree->right;
+ tree->right = tTree;
+ litTree->opval.op = '+';
+ tree->opval.op = '-';
+ }
+ }
+ decorateType (parent, resultType);
+ }
+ }
+
+ LRVAL (tree) = RRVAL (tree) = 1;
+
+ /* if the left is a pointer */
+ if (IS_PTR (LTYPE (tree)) || IS_AGGREGATE (LTYPE (tree)))
+ TETYPE (tree) = getSpec (TTYPE (tree) = LTYPE (tree));
+ else
+ {
+ tree->left = addCast (tree->left, resultTypeProp, TRUE);
+ tree->right = addCast (tree->right, resultTypeProp, TRUE);
+ TETYPE (tree) = getSpec (TTYPE (tree) = computeType (LTYPE (tree), RTYPE (tree), resultType, tree->opval.op));
+ }
+ if (IS_LITERAL (TETYPE (tree)))
+ {
+ if (TTYPE (tree) == LTYPE (tree))
+ TETYPE (tree) = getSpec (TTYPE (tree) = copyLinkChain (TTYPE (tree)));
+ SPEC_SCLS (TETYPE (tree)) = 0;
+ }
+
+ return tree;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* unary '-' */
+ /*----------------------------*/
+ case '-': /* can be unary */
+ /* if right is null then unary */
+ if (!tree->right)
+ {
+ if (!IS_ARITHMETIC (LTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_UNARY_OP, tree->opval.op);
+ goto errorTreeReturn;
+ }
+
+ /* if left is a literal then do it */
+ if (IS_LITERAL (LTYPE (tree)))
+ {
+ tree->type = EX_VALUE;
+ tree->opval.val = valUnaryPM (valFromType (LETYPE (tree)));
+ tree->left = NULL;
+ TETYPE (tree) = TTYPE (tree) = tree->opval.val->type;
+ return tree;
+ }
+ tree->left = addCast (tree->left, resultTypeProp, TRUE);
+ TETYPE (tree) = getSpec (TTYPE (tree) = computeType (LTYPE (tree), NULL, resultType, tree->opval.op));
+ LRVAL (tree) = 1;
+ return tree;
+ }
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* subtraction */
+ /*----------------------------*/
+
+ if (!(IS_PTR (LTYPE (tree)) || IS_ARRAY (LTYPE (tree)) || IS_ARITHMETIC (LTYPE (tree))))
+ {
+ werrorfl (tree->filename, tree->lineno, E_PLUS_INVALID, "-");
+ goto errorTreeReturn;
+ }
+
+ if (!(IS_PTR (RTYPE (tree)) || IS_ARRAY (RTYPE (tree)) || IS_ARITHMETIC (RTYPE (tree))))
+ {
+ werrorfl (tree->filename, tree->lineno, E_PLUS_INVALID, "-");
+ goto errorTreeReturn;
+ }
+
+ if ((IS_PTR (LTYPE (tree)) || IS_ARRAY (LTYPE (tree))) &&
+ !(IS_PTR (RTYPE (tree)) || IS_ARRAY (RTYPE (tree)) || IS_INTEGRAL (RTYPE (tree))))
+ {
+ werrorfl (tree->filename, tree->lineno, E_PLUS_INVALID, "-");
+ goto errorTreeReturn;
+ }
+
+ /* if they are both literal then */
+ /* rewrite the tree */
+ if (IS_LITERAL (RTYPE (tree)) && IS_LITERAL (LTYPE (tree)))
+ {
+ tree->left = addCast (tree->left, resultTypeProp, TRUE);
+ tree->right = addCast (tree->right, resultTypeProp, TRUE);
+ rewriteAstNodeVal (tree, valMinus (valFromType (LETYPE (tree)), valFromType (RETYPE (tree))));
+ return decorateType (tree, resultType);
+ }
+
+ /* if the left & right are equal then zero */
+ if (!hasSEFcalls(tree->left) && !hasSEFcalls(tree->right) &&
+ isAstEqual (tree->left, tree->right))
+ {
+ tree->type = EX_VALUE;
+ tree->left = tree->right = NULL;
+ tree->opval.val = constVal ("0");
+ TETYPE (tree) = TTYPE (tree) = tree->opval.val->type;
+ return tree;
+ }
+
+ /* if both of them are pointers or arrays then */
+ /* the result is going to be an integer */
+ if ((IS_ARRAY (LTYPE (tree)) || IS_PTR (LTYPE (tree))) && (IS_ARRAY (RTYPE (tree)) || IS_PTR (RTYPE (tree))))
+ TETYPE (tree) = TTYPE (tree) = newIntLink ();
+ else
+ /* if only the left is a pointer */
+ /* then result is a pointer */
+ if (IS_PTR (LTYPE (tree)) || IS_ARRAY (LTYPE (tree)))
+ TETYPE (tree) = getSpec (TTYPE (tree) = LTYPE (tree));
+ else
+ {
+ tree->left = addCast (tree->left, resultTypeProp, TRUE);
+ tree->right = addCast (tree->right, resultTypeProp, TRUE);
+
+ TETYPE (tree) = getSpec (TTYPE (tree) = computeType (LTYPE (tree), RTYPE (tree), resultType, tree->opval.op));
+ }
+ if (IS_LITERAL (TETYPE (tree)))
+ {
+ if (TTYPE (tree) == LTYPE (tree))
+ TETYPE (tree) = getSpec (TTYPE (tree) = copyLinkChain (TTYPE (tree)));
+ SPEC_SCLS (TETYPE (tree)) = 0;
+ }
+
+ LRVAL (tree) = RRVAL (tree) = 1;
+
+ /* if right is a literal and */
+ /* left is also an addition/subtraction with a literal then */
+ /* rearrange the tree */
+ if (IS_LITERAL (RTYPE (tree))
+ /* avoid infinite loop */
+ && (TYPE_TARGET_ULONG) ulFromVal (tree->right->opval.val) != 0)
+ {
+ ast *litTree, *litParent;
+ litTree = searchLitOp (tree, &litParent, "+-");
+ if (litTree)
+ {
+ if (litTree->opval.op == '+')
+ {
+ /* foo_sa */
+ DEBUG_CF ("- 1 SA") ast *tTree = litTree->left;
+ litTree->left = litTree->right;
+ litTree->right = tree->right;
+ tree->right = tTree;
+ tree->opval.op = '+';
+ litTree->opval.op = '-';
+ }
+ else if (litTree->opval.op == '-')
+ {
+ if (IS_LITERAL (RTYPE (litTree)))
+ {
+ /* foo_ssr */
+ DEBUG_CF ("- 2 SSR") ast *tTree = litTree->left;
+ litTree->left = tree->right;
+ tree->right = litParent->left;
+ litParent->left = tTree;
+ litTree->opval.op = '+';
+
+ tree->decorated = 0;
+ decorateType (tree, resultType);
+ }
+ else
+ {
+ /* foo_ssl */
+ DEBUG_CF ("- 3 SSL") ast *tTree = litTree->right;
+ litTree->right = tree->right;
+ tree->right = tTree;
+ }
+ }
+ decorateType (litParent, resultType);
+ }
+ }
+ return tree;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* complement */
+ /*----------------------------*/
+ case '~':
+ /* can be only integral type */
+ if (!IS_INTEGRAL (LTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_UNARY_OP, tree->opval.op);
+ goto errorTreeReturn;
+ }
+
+ /* if left is a literal then do it */
+ if (IS_LITERAL (LTYPE (tree)))
+ {
+ tree->type = EX_VALUE;
+ tree->opval.val = valComplement (valFromType (LETYPE (tree)));
+ tree->left = NULL;
+ TETYPE (tree) = TTYPE (tree) = tree->opval.val->type;
+ return addCast (tree, resultTypeProp, TRUE);
+ }
+
+ if (resultType == RESULT_TYPE_BOOL && IS_UNSIGNED (tree->left->etype) && getSize (tree->left->etype) < INTSIZE)
+ {
+ /* promotion rules are responsible for this strange result:
+ bit -> int -> ~int -> bit
+ uchar -> int -> ~int -> bit
+ */
+ werrorfl (tree->filename, tree->lineno, W_COMPLEMENT);
+
+ /* optimize bit-result, even if we optimize a buggy source */
+ tree->type = EX_VALUE;
+ tree->opval.val = constBoolVal (1);
+ }
+ else
+ tree->left = addCast (tree->left, resultTypeProp, TRUE);
+ LRVAL (tree) = 1;
+ COPYTYPE (TTYPE (tree), TETYPE (tree), LTYPE (tree));
+ return tree;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* not */
+ /*----------------------------*/
+ case '!':
+ /* can be pointer */
+ if (!IS_ARITHMETIC (LTYPE (tree)) && !IS_PTR (LTYPE (tree)) && !IS_ARRAY (LTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_UNARY_OP, tree->opval.op);
+ goto errorTreeReturn;
+ }
+
+ /* if left is another '!' */
+#if 0 /* Disabled optimization due to bugs #2548, #2551. */
+ if (IS_AST_NOT_OPER (tree->left))
+ {
+ if (resultType == RESULT_TYPE_IFX || resultType == RESULT_TYPE_BOOL))
+ {
+ /* replace double '!!X' by 'X' */
+ return tree->left->left;
+ }
+
+ /* remove double '!!X' by 'X ? 1 : 0' */ /* TODO: Casts to _Bools tend to result in far more efficient code than '?' */
+ tree->opval.op = '?';
+ tree->left = tree->left->left;
+ tree->right = newNode (':', newAst_VALUE (constBoolVal (1)), newAst_VALUE (constBoolVal (0)));
+ tree->right->filename = tree->filename;
+ tree->right->lineno = tree->lineno;
+ tree->decorated = 0;
+ return decorateType (tree, resultType);
+ }
+#endif
+
+ /* if left is a literal then do it */
+ if (IS_LITERAL (LTYPE (tree)))
+ {
+ rewriteAstNodeVal (tree, valNot (valFromType (LETYPE (tree))));
+ return decorateType (tree, resultType);
+ }
+ LRVAL (tree) = 1;
+ TTYPE (tree) = TETYPE (tree) = (resultTypeProp == RESULT_TYPE_BOOL) ? newBoolLink () : newCharLink ();
+ if (IS_BOOLEAN (LTYPE (tree)))
+ SPEC_USIGN (TTYPE (tree)) = SPEC_USIGN (LTYPE (tree));
+ return tree;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* shift */
+ /*----------------------------*/
+ case RRC:
+ case RLC:
+ case SWAP:
+ TTYPE (tree) = LTYPE (tree);
+ TETYPE (tree) = LETYPE (tree);
+ return tree;
+
+ case GETHBIT:
+ case GETABIT:
+ TTYPE (tree) = TETYPE (tree) = (resultTypeProp == RESULT_TYPE_BOOL) ? newBoolLink () : newCharLink ();
+ return tree;
+
+ case GETBYTE:
+ TTYPE (tree) = TETYPE (tree) = newCharLink ();
+ return tree;
+
+ case GETWORD:
+ TTYPE (tree) = TETYPE (tree) = newIntLink ();
+ return tree;
+
+ case LEFT_OP:
+ case RIGHT_OP:
+ if (!IS_INTEGRAL (LTYPE (tree)) || !IS_INTEGRAL (tree->left->etype))
+ {
+ werrorfl (tree->filename, tree->lineno, E_SHIFT_OP_INVALID);
+ werrorfl (tree->filename, tree->lineno, W_CONTINUE, "left & right types are ");
+ printTypeChain (LTYPE (tree), stderr);
+ fprintf (stderr, ",");
+ printTypeChain (RTYPE (tree), stderr);
+ fprintf (stderr, "\n");
+ goto errorTreeReturn;
+ }
+
+ /* make smaller type only if it's a LEFT_OP */
+ if (tree->opval.op == LEFT_OP)
+ tree->left = addCast (tree->left, resultTypeProp, TRUE);
+
+ /* if they are both literal then */
+ /* rewrite the tree */
+ if (IS_LITERAL (RTYPE (tree)) && IS_LITERAL (LTYPE (tree)))
+ {
+ rewriteAstNodeVal (tree, valShift (valFromType (LETYPE (tree)), valFromType (RETYPE (tree)), (tree->opval.op == LEFT_OP ? 1 : 0)));
+ return decorateType (tree, resultType);
+ }
+
+ /* see if this is a GETBYTE operation if yes
+ then return that */
+ {
+ ast *otree = optimizeGetByte (tree, resultType);
+
+ if (otree != tree)
+ return decorateType (otree, RESULT_TYPE_NONE);
+ }
+
+ /* see if this is a GETWORD operation if yes
+ then return that */
+ {
+ ast *otree = optimizeGetWord (tree, resultType);
+
+ if (otree != tree)
+ return decorateType (otree, RESULT_TYPE_NONE);
+ }
+
+ LRVAL (tree) = RRVAL (tree) = 1;
+ if (tree->opval.op == LEFT_OP)
+ {
+ TETYPE (tree) = getSpec (TTYPE (tree) = computeType (LTYPE (tree), NULL, resultType, tree->opval.op));
+ }
+ else /* RIGHT_OP */
+ {
+ /* no promotion necessary */
+ TTYPE (tree) = TETYPE (tree) = copyLinkChain (LTYPE (tree));
+ if (IS_LITERAL (TTYPE (tree)))
+ SPEC_SCLS (TTYPE (tree)) &= ~S_LITERAL;
+ }
+
+ /* if only the right side is a literal & we are
+ shifting more than size of the left operand then zero */
+ if (IS_LITERAL (RTYPE (tree)) &&
+ ((TYPE_TARGET_ULONG) ulFromVal (valFromType (RETYPE (tree)))) >= (getSize (TETYPE (tree)) * 8))
+ {
+ if (tree->opval.op == LEFT_OP || (tree->opval.op == RIGHT_OP && SPEC_USIGN (LETYPE (tree))))
+ {
+ werrorfl (tree->filename, tree->lineno, W_SHIFT_CHANGED, (tree->opval.op == LEFT_OP ? "left" : "right"));
+ /* Change shift op to comma op and replace the right operand with 0. */
+ /* This preserves the left operand in case there were side-effects. */
+ tree->opval.op = ',';
+ tree->right->opval.val = constVal ("0");
+ TETYPE (tree) = TTYPE (tree) = tree->right->opval.val->type;
+ return tree;
+ }
+ }
+
+ return tree;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* casting */
+ /*----------------------------*/
+ case CAST: /* change the type */
+ /* cannot cast to an aggregate type */
+ if (IS_AGGREGATE (LTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_CAST_ILLEGAL);
+ goto errorTreeReturn;
+ }
+
+ /* make sure the type is complete and sane */
+ if ((resultType == RESULT_TYPE_GPTR) && IS_FUNCPTR (LTYPE (tree)))
+ changePointer (LTYPE (tree)->next);
+ else
+ changePointer (LTYPE (tree));
+ checkTypeSanity (LETYPE (tree), "(cast)");
+
+ /* if 'from' and 'to' are the same remove the superfluous cast,
+ * this helps other optimizations */
+ if (compareTypeExact (LTYPE (tree), RTYPE (tree), -1) == 1)
+ {
+ /* mark that the explicit cast has been removed,
+ * for proper processing (no integer promotion) of explicitly typecasted variable arguments */
+ tree->right->values.cast.removedCast = 1;
+ return tree->right;
+ }
+
+ /* If code memory is read only, then pointers to code memory */
+ /* implicitly point to constants -- make this explicit */
+ CodePtrPointsToConst (LTYPE (tree));
+
+#if 0
+ /* if the right is a literal replace the tree */
+ if (IS_LITERAL (RETYPE (tree)))
+ {
+ if (!IS_PTR (LTYPE (tree)))
+ {
+ tree->type = EX_VALUE;
+ tree->opval.val = valCastLiteral (LTYPE (tree), floatFromVal (valFromType (RETYPE (tree))));
+ tree->left = NULL;
+ tree->right = NULL;
+ TTYPE (tree) = tree->opval.val->type;
+ tree->values.cast.literalFromCast = 1;
+ }
+ else if (IS_GENPTR (LTYPE (tree)) && !IS_PTR (RTYPE (tree)) && ((int) ulFromVal (valFromType (RETYPE (tree)))) != 0) /* special case of NULL */
+ {
+ sym_link *rest = LTYPE (tree)->next;
+ werrorfl (tree->filename, tree->lineno, W_LITERAL_GENERIC);
+ TTYPE (tree) = newLink (DECLARATOR);
+ DCL_TYPE (TTYPE (tree)) = FPOINTER;
+ TTYPE (tree)->next = rest;
+ tree->left->opval.lnk = TTYPE (tree);
+ LRVAL (tree) = 1;
+ }
+ else
+ {
+ TTYPE (tree) = LTYPE (tree);
+ LRVAL (tree) = 1;
+ }
+ }
+ else
+ {
+ TTYPE (tree) = LTYPE (tree);
+ LRVAL (tree) = 1;
+ }
+#else
+#if 0 // this is already checked, now this could be explicit
+ /* if pointer to struct then check names */
+ if (IS_PTR (LTYPE (tree)) && IS_STRUCT (LTYPE (tree)->next) &&
+ IS_PTR (RTYPE (tree)) && IS_STRUCT (RTYPE (tree)->next) &&
+ strcmp (SPEC_STRUCT (LETYPE (tree))->tag, SPEC_STRUCT (RETYPE (tree))->tag))
+ {
+ werrorfl (tree->filename, tree->lineno, W_CAST_STRUCT_PTR, SPEC_STRUCT (RETYPE (tree))->tag,
+ SPEC_STRUCT (LETYPE (tree))->tag);
+ }
+#endif
+#if 0 // disabled to fix bug 2941749
+ if (IS_ADDRESS_OF_OP (tree->right)
+ && IS_AST_SYM_VALUE (tree->right->left) && SPEC_ABSA (AST_SYMBOL (tree->right->left)->etype))
+ {
+ symbol *sym = AST_SYMBOL (tree->right->left);
+ unsigned int gptype = 0;
+ unsigned int addr = SPEC_ADDR (sym->etype);
+
+ if (IS_GENPTR (LTYPE (tree)) && ((GPTRSIZE > FARPTRSIZE) || TARGET_IS_PIC16))
+ {
+ switch (SPEC_SCLS (sym->etype))
+ {
+ case S_CODE:
+ gptype = GPTYPE_CODE;
+ break;
+ case S_XDATA:
+ gptype = GPTYPE_FAR;
+ break;
+ case S_DATA:
+ case S_IDATA:
+ gptype = GPTYPE_NEAR;
+ break;
+ case S_PDATA:
+ gptype = GPTYPE_XSTACK;
+ break;
+ default:
+ gptype = 0;
+ if (TARGET_IS_PIC16 && (SPEC_SCLS (sym->etype) == S_FIXED))
+ gptype = GPTYPE_NEAR;
+ }
+ addr |= gptype << (8 * (GPTRSIZE - 1));
+ }
+
+ tree->type = EX_VALUE;
+ tree->opval.val = valCastLiteral (LTYPE (tree), addr);
+ TTYPE (tree) = tree->opval.val->type;
+ TETYPE (tree) = getSpec (TTYPE (tree));
+ tree->left = NULL;
+ tree->right = NULL;
+ tree->values.cast.literalFromCast = 1;
+ return tree;
+ }
+#endif
+
+ /* if the right is a literal replace the tree */
+ if (IS_LITERAL (RETYPE (tree)))
+ {
+#if 0
+ if (IS_PTR (LTYPE (tree)) && !IS_GENPTR (LTYPE (tree)))
+ {
+ /* rewrite (type *)litaddr
+ as &temp
+ and define type at litaddr temp
+ (but only if type's storage class is not generic)
+ */
+ ast *newTree = newNode ('&', NULL, NULL);
+ symbol *sym;
+
+ TTYPE (newTree) = LTYPE (tree);
+ TETYPE (newTree) = getSpec (LTYPE (tree));
+
+ /* define a global symbol at the casted address */
+ sym = newSymbol (genSymName (0), 0);
+ sym->type = LTYPE (tree)->next;
+ if (!sym->type)
+ sym->type = newLink (V_VOID);
+ sym->etype = getSpec (sym->type);
+ SPEC_SCLS (sym->etype) = sclsFromPtr (LTYPE (tree));
+ sym->lineDef = tree->lineno;
+ sym->cdef = 1;
+ sym->isref = 1;
+ SPEC_STAT (sym->etype) = 1;
+ SPEC_ADDR (sym->etype) = floatFromVal (valFromType (RTYPE (tree)));
+ SPEC_ABSA (sym->etype) = 1;
+ addSym (SymbolTab, sym, sym->name, 0, 0, 0);
+ allocGlobal (sym);
+
+ newTree->left = newAst_VALUE (symbolVal (sym));
+ newTree->left->filename = tree->filename;
+ newTree->left->lineno = tree->lineno;
+ LTYPE (newTree) = sym->type;
+ LETYPE (newTree) = sym->etype;
+ LLVAL (newTree) = 1;
+ LRVAL (newTree) = 0;
+ TLVAL (newTree) = 1;
+ return newTree;
+ }
+#endif
+ if (!IS_PTR (LTYPE (tree)))
+ {
+ tree->type = EX_VALUE;
+ tree->opval.val = valCastLiteral (LTYPE (tree), floatFromVal (valFromType (RTYPE (tree))), (TYPE_TARGET_ULONGLONG) ullFromVal (valFromType (RTYPE (tree))));
+ TTYPE (tree) = tree->opval.val->type;
+ tree->left = NULL;
+ tree->right = NULL;
+ tree->values.cast.literalFromCast = 1;
+ TETYPE (tree) = getSpec (TTYPE (tree));
+ return tree;
+ }
+ else
+ {
+ unsigned long long gpVal = 0;
+ int size = getSize(LTYPE (tree));
+ unsigned long long mask = (size >= sizeof(long long)) ? 0xffffffffffffffffull : (1ull << (size * 8)) - 1;
+ unsigned long long pVal = ullFromVal (valFromType (RTYPE (tree))) & mask;
+
+ /* if casting literal specific pointer to generic pointer */
+ if (IS_GENPTR (LTYPE (tree)) && IS_PTR (RTYPE (tree)) && !IS_GENPTR (RTYPE (tree)))
+ {
+ if (resultType != RESULT_TYPE_GPTR)
+ {
+ DCL_TYPE (LTYPE (tree)) = DCL_TYPE (RTYPE (tree));
+ }
+ else
+ {
+ gpVal = pointerTypeToGPByte (DCL_TYPE (RTYPE (tree)), NULL, NULL);
+ gpVal <<= getSize (RTYPE (tree)) * 8;
+ gpVal &= mask;
+ }
+ }
+ checkPtrCast (LTYPE (tree), RTYPE (tree), tree->values.cast.implicitCast, !ullFromVal (valFromType (RTYPE (tree))));
+ LRVAL (tree) = 1;
+ tree->type = EX_VALUE;
+ tree->opval.val = valCastLiteral (LTYPE (tree), gpVal | pVal, gpVal | pVal);
+ TTYPE (tree) = tree->opval.val->type;
+ tree->left = NULL;
+ tree->right = NULL;
+ tree->values.cast.literalFromCast = 1;
+ TETYPE (tree) = getSpec (TTYPE (tree));
+ return tree;
+ }
+ }
+ checkPtrCast (LTYPE (tree), RTYPE (tree), tree->values.cast.implicitCast, FALSE);
+ if (IS_GENPTR (LTYPE (tree)) && (resultType != RESULT_TYPE_GPTR))
+ {
+ if (IS_PTR (RTYPE (tree)) && !IS_GENPTR (RTYPE (tree)))
+ DCL_TYPE (LTYPE (tree)) = DCL_TYPE (RTYPE (tree));
+ if (IS_ARRAY (RTYPE (tree)) && SPEC_OCLS (RETYPE (tree)))
+ DCL_TYPE (LTYPE (tree)) = PTR_TYPE (SPEC_OCLS (RETYPE (tree)));
+ }
+ TTYPE (tree) = LTYPE (tree);
+ LRVAL (tree) = 1;
+
+#endif
+ TETYPE (tree) = getSpec (TTYPE (tree));
+
+ return tree;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* logical &&, || */
+ /*----------------------------*/
+ case AND_OP:
+ case OR_OP:
+ /* each must be arithmetic type or be a pointer */
+ if (!IS_PTR (LTYPE (tree)) && !IS_ARRAY (LTYPE (tree)) && !IS_INTEGRAL (LTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_COMPARE_OP);
+ goto errorTreeReturn;
+ }
+
+ if (!IS_PTR (RTYPE (tree)) && !IS_ARRAY (RTYPE (tree)) && !IS_INTEGRAL (RTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_COMPARE_OP);
+ goto errorTreeReturn;
+ }
+ /* if they are both literal then */
+ /* rewrite the tree */
+ if (IS_LITERAL (RTYPE (tree)) && IS_LITERAL (LTYPE (tree)))
+ {
+ rewriteAstNodeVal (tree, valLogicAndOr (valFromType (LETYPE (tree)), valFromType (RETYPE (tree)), tree->opval.op));
+ return decorateType (tree, resultType);
+ }
+ LRVAL (tree) = RRVAL (tree) = 1;
+ TTYPE (tree) = TETYPE (tree) = (resultTypeProp == RESULT_TYPE_BOOL) ? newBoolLink () : newCharLink ();
+ return tree;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* comparison operators */
+ /*----------------------------*/
+ case '>':
+ case '<':
+ case LE_OP:
+ case GE_OP:
+ case EQ_OP:
+ case NE_OP:
+ {
+ ast *lt = optimizeCompare (tree);
+
+ if (tree != lt)
+ return lt;
+ }
+
+ /* C does not allow comparison of struct or union. */
+ if (IS_STRUCT (LTYPE (tree)) || IS_STRUCT (RTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_COMPARE_OP);
+ goto errorTreeReturn;
+ }
+
+ /* if they are pointers they must be castable */
+ else if (IS_PTR (LTYPE (tree)) && IS_PTR (RTYPE (tree)))
+ {
+ if (tree->opval.op == EQ_OP && !IS_GENPTR (LTYPE (tree)) && IS_GENPTR (RTYPE (tree)))
+ {
+ // we cannot cast a gptr to a !gptr: switch the leaves
+ struct ast *s = tree->left;
+ tree->left = tree->right;
+ tree->right = s;
+ }
+ if (compareType (LTYPE (tree), RTYPE (tree)) == 0)
+ {
+ werrorfl (tree->filename, tree->lineno, E_INCOMPAT_TYPES);
+ fprintf (stderr, "comparing type ");
+ printTypeChain (LTYPE (tree), stderr);
+ fprintf (stderr, " to type ");
+ printTypeChain (RTYPE (tree), stderr);
+ fprintf (stderr, "\n");
+ goto errorTreeReturn;
+ }
+ }
+ /* else they should be promotable to one another */
+ else
+ {
+ if (!((IS_PTR (LTYPE (tree)) && IS_LITERAL (RTYPE (tree))) || (IS_PTR (RTYPE (tree)) && IS_LITERAL (LTYPE (tree)))))
+
+ if (compareType (LTYPE (tree), RTYPE (tree)) == 0)
+ {
+ if (compareType (RTYPE (tree), LTYPE (tree)) != 0)
+ {
+ struct ast *s = tree->left;
+ tree->left = tree->right;
+ tree->right = s;
+ if (tree->opval.op == '>')
+ tree->opval.op = '<';
+ else if (tree->opval.op == '>')
+ tree->opval.op = '<';
+ else if (tree->opval.op == LE_OP)
+ tree->opval.op = GE_OP;
+ else if (tree->opval.op == GE_OP)
+ tree->opval.op = LE_OP;
+ }
+ else
+ {
+ werrorfl (tree->filename, tree->lineno, E_INCOMPAT_TYPES);
+ fprintf (stderr, "comparing type ");
+ printTypeChain (LTYPE (tree), stderr);
+ fprintf (stderr, " to type ");
+ printTypeChain (RTYPE (tree), stderr);
+ fprintf (stderr, "\n");
+ goto errorTreeReturn;
+ }
+ }
+ }
+
+ {
+ CCR_RESULT ccr_result = CCR_OK;
+ ast * newResult;
+
+ /* if left is integral and right is literal
+ then check constant range */
+ if (IS_INTEGRAL (LTYPE (tree)) && !IS_LITERAL (LTYPE (tree)) && IS_LITERAL (RTYPE (tree)))
+ ccr_result = checkConstantRange (LTYPE (tree), RTYPE (tree), tree->opval.op, FALSE);
+ if (ccr_result == CCR_OK && IS_INTEGRAL (RTYPE (tree)) && !IS_LITERAL (RTYPE (tree)) && IS_LITERAL (LTYPE (tree)))
+ ccr_result = checkConstantRange (RTYPE (tree), LTYPE (tree), tree->opval.op, TRUE);
+ switch (ccr_result)
+ {
+ case CCR_ALWAYS_TRUE:
+ case CCR_ALWAYS_FALSE:
+ werrorfl (tree->filename, tree->lineno, W_COMP_RANGE, ccr_result == CCR_ALWAYS_TRUE ? "true" : "false");
+ newResult = newAst_VALUE (constBoolVal ((unsigned char) (ccr_result == CCR_ALWAYS_TRUE)));
+ /* If there are side effects, join the non-literal side */
+ /* to the boolean result with a comma operator */
+ if (hasSEFcalls (tree))
+ {
+ if (!IS_LITERAL (LTYPE (tree)))
+ newResult = newNode (',', tree->left, newResult);
+ else
+ newResult = newNode (',', tree->right, newResult);
+ }
+ return decorateType (newResult, resultType);
+ case CCR_OK:
+ default:
+ break;
+ }
+ }
+
+ /* if (unsigned value) > 0 then '(unsigned value) ? 1 : 0' */
+ if (tree->opval.op == '>' &&
+ SPEC_USIGN (LETYPE (tree)) && IS_LITERAL (RTYPE (tree)) && ((int) ulFromVal (valFromType (RETYPE (tree)))) == 0)
+ {
+ if ((resultType == RESULT_TYPE_IFX) || (resultType == RESULT_TYPE_BOOL))
+ {
+ /* the parent is an ifx: */
+ /* if (unsigned value) */
+ return tree->left;
+ }
+
+ /* (unsigned value) ? 1 : 0 */ /* TODO: Casts to _Bools tend to result in far more efficient code than '?' */
+ tree->opval.op = '?';
+ tree->right = newNode (':', newAst_VALUE (constBoolVal (1)), tree->right); /* val 0 */
+ tree->right->filename = tree->filename;
+ tree->right->lineno = tree->lineno;
+ tree->right->left->filename = tree->filename;
+ tree->right->left->lineno = tree->lineno;
+ tree->decorated = 0;
+ return decorateType (tree, resultType);
+ }
+
+ /* 'ifx (0 == op)' -> 'ifx (!(op))' */
+ if (IS_LITERAL (LETYPE (tree)) &&
+ floatFromVal (valFromType (LTYPE (tree))) == 0 &&
+ tree->opval.op == EQ_OP && (resultType == RESULT_TYPE_IFX || resultType == RESULT_TYPE_BOOL))
+ {
+ rewriteAstNodeOp (tree, '!', tree->right, NULL);
+ return decorateType (tree, resultType);
+ }
+
+ /* 'ifx (op == 0)' -> 'ifx (!(op))' */
+ if (IS_LITERAL (RETYPE (tree)) &&
+ floatFromVal (valFromType (RTYPE (tree))) == 0 &&
+ tree->opval.op == EQ_OP && (resultType == RESULT_TYPE_IFX || resultType == RESULT_TYPE_BOOL))
+ {
+ rewriteAstNodeOp (tree, '!', tree->left, NULL);
+ return decorateType (tree, resultType);
+ }
+
+ /* 'ifx (op == 1)' -> 'ifx (op)' for bool */
+ if (IS_LITERAL (RETYPE (tree)) &&
+ floatFromVal (valFromType (RTYPE (tree))) == 1 && IS_BOOLEAN (LETYPE (tree)) &&
+ tree->opval.op == EQ_OP && (resultType == RESULT_TYPE_IFX || resultType == RESULT_TYPE_BOOL))
+ {
+ tree = tree->left;
+ return decorateType (tree, resultType);
+ }
+
+ /* if they are both literal then */
+ /* rewrite the tree */
+ if (IS_LITERAL (RETYPE (tree)) && IS_LITERAL (LETYPE (tree)))
+ {
+ rewriteAstNodeVal (tree, valCompare (valFromType (LETYPE (tree)), valFromType (RETYPE (tree)), tree->opval.op));
+ return decorateType (tree, resultType);
+ }
+
+ /* if one is 'signed char ' and the other one is 'unsigned char' */
+ /* it's necessary to promote to int */
+ if (IS_CHAR (RTYPE (tree)) && IS_CHAR (LTYPE (tree)) && (IS_UNSIGNED (RTYPE (tree)) != IS_UNSIGNED (LTYPE (tree))))
+ {
+ /* Small literal integers are 'optimized' to 'unsigned char' but chars in single quotes are 'char'.
+ Try to figure out, if it's possible to do without a cast to integer */
+
+ /* is right a small literal char? */
+ if (IS_LITERAL (RTYPE (tree)))
+ {
+ int val = (int) ulFromVal (valFromType (RETYPE (tree)));
+ /* the overlapping value range of a '(un)signed char' is 0...127;
+ if 0 <= the actual value < 128 it can be changed to (un)signed */
+ if (val >= 0 && val < 128)
+ {
+ /* now we've got 2 '(un)signed char'! */
+ SPEC_USIGN (RETYPE (tree)) = SPEC_USIGN (LETYPE (tree));
+ }
+ }
+ /* same test for the left operand: */
+ else if (IS_LITERAL (LTYPE (tree)))
+ {
+ int val = (int) ulFromVal (valFromType (LETYPE (tree)));
+ if (val >= 0 && val < 128)
+ {
+ SPEC_USIGN (LETYPE (tree)) = SPEC_USIGN (RETYPE (tree));
+ }
+ }
+ else
+ {
+ werrorfl (tree->filename, tree->lineno, W_CMP_SU_CHAR);
+ tree->left = addCast (tree->left, RESULT_TYPE_INT, TRUE);
+ tree->right = addCast (tree->right, RESULT_TYPE_INT, TRUE);
+ }
+ }
+
+ LRVAL (tree) = RRVAL (tree) = 1;
+ TTYPE (tree) = TETYPE (tree) = (resultType == RESULT_TYPE_BOOL) ? newBoolLink () : newCharLink ();
+
+ /* condition transformations */
+ {
+ unsigned transformedOp = 0;
+
+ switch (tree->opval.op)
+ {
+ case '<': /* transform (a < b) to !(a >= b) */
+ if (port->lt_nge)
+ transformedOp = GE_OP;
+ break;
+ case '>': /* transform (a > b) to !(a <= b) */
+ if (port->gt_nle)
+ transformedOp = LE_OP;
+ break;
+ case LE_OP: /* transform (a <= b) to !(a > b) */
+ if (port->le_ngt)
+ transformedOp = '>';
+ break;
+ case GE_OP: /* transform (a >= b) to !(a < b) */
+ if (port->ge_nlt)
+ transformedOp = '<';
+ break;
+ case NE_OP: /* transform (a != b) to !(a == b) */
+ if (port->ne_neq)
+ transformedOp = EQ_OP;
+ break;
+ case EQ_OP: /* transform (a == b) to !(a != b) */
+ if (port->eq_nne)
+ transformedOp = NE_OP;
+ break;
+ default:
+ break;
+ }
+ if (transformedOp)
+ {
+ tree->opval.op = transformedOp;
+ tree->decorated = 0;
+ tree = newNode ('!', tree, NULL);
+ tree->filename = tree->left->filename;
+ tree->lineno = tree->left->lineno;
+ return decorateType (tree, resultType);
+ }
+ }
+
+ return tree;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* sizeof */
+ /*----------------------------*/
+ case SIZEOF: /* evaluate without code generation */
+ {
+ /* change the type to a integer */
+ struct dbuf_s dbuf;
+ int size = getSize (tree->right->ftype);
+
+ dbuf_init (&dbuf, 128);
+ dbuf_printf (&dbuf, "%d", size);
+ if (!size && !IS_VOID (tree->right->ftype))
+ werrorfl (tree->filename, tree->lineno, E_SIZEOF_INCOMPLETE_TYPE);
+ tree->type = EX_VALUE;
+ tree->opval.val = constVal (dbuf_c_str (&dbuf));
+ dbuf_destroy (&dbuf);
+ tree->right = tree->left = NULL;
+ TETYPE (tree) = getSpec (TTYPE (tree) = tree->opval.val->type);
+
+ return tree;
+ }
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* typeof */
+ /*----------------------------*/
+ case TYPEOF:
+ /* return typeof enum value */
+ tree->type = EX_VALUE;
+ {
+ int typeofv = 0;
+ struct dbuf_s dbuf;
+
+ if (IS_SPEC (tree->right->ftype))
+ {
+ switch (SPEC_NOUN (tree->right->ftype))
+ {
+ case V_INT:
+ if (SPEC_LONG (tree->right->ftype))
+ typeofv = TYPEOF_LONG;
+ else
+ typeofv = TYPEOF_INT;
+ break;
+ case V_FLOAT:
+ typeofv = TYPEOF_FLOAT;
+ break;
+ case V_FIXED16X16:
+ typeofv = TYPEOF_FIXED16X16;
+ break;
+ case V_BOOL:
+ typeofv = TYPEOF_BOOL;
+ break;
+ case V_CHAR:
+ typeofv = TYPEOF_CHAR;
+ break;
+ case V_VOID:
+ typeofv = TYPEOF_VOID;
+ break;
+ case V_STRUCT:
+ typeofv = TYPEOF_STRUCT;
+ break;
+ case V_BITFIELD:
+ typeofv = TYPEOF_BITFIELD;
+ break;
+ case V_BIT:
+ typeofv = TYPEOF_BIT;
+ break;
+ case V_SBIT:
+ typeofv = TYPEOF_SBIT;
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ switch (DCL_TYPE (tree->right->ftype))
+ {
+ case POINTER:
+ typeofv = TYPEOF_POINTER;
+ break;
+ case FPOINTER:
+ typeofv = TYPEOF_FPOINTER;
+ break;
+ case CPOINTER:
+ typeofv = TYPEOF_CPOINTER;
+ break;
+ case GPOINTER:
+ typeofv = TYPEOF_GPOINTER;
+ break;
+ case PPOINTER:
+ typeofv = TYPEOF_PPOINTER;
+ break;
+ case IPOINTER:
+ typeofv = TYPEOF_IPOINTER;
+ break;
+ case ARRAY:
+ typeofv = TYPEOF_ARRAY;
+ break;
+ case FUNCTION:
+ typeofv = TYPEOF_FUNCTION;
+ break;
+ default:
+ break;
+ }
+ }
+ dbuf_init (&dbuf, 128);
+ dbuf_printf (&dbuf, "%d", typeofv);
+ tree->opval.val = constVal (dbuf_c_str (&dbuf));
+ dbuf_destroy (&dbuf);
+ tree->right = tree->left = NULL;
+ TETYPE (tree) = getSpec (TTYPE (tree) = tree->opval.val->type);
+ }
+ return tree;
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* conditional operator '?' */
+ /*----------------------------*/
+ case '?':
+ /* the type is value of the colon operator (on the right) */
+ assert (IS_COLON_OP (tree->right));
+
+ /* If already known then replace the tree : optimizer will do it
+ but faster to do it here. If done before decorating tree->right
+ this can save generating unused const strings. */
+ if (IS_LITERAL (LTYPE (tree)))
+ {
+ ast * heir;
+
+ ++noAlloc;
+ tree->right = decorateType (tree->right, resultTypeProp);
+ --noAlloc;
+
+ if (((int) ulFromVal (valFromType (LETYPE (tree)))) != 0)
+ heir = tree->right->left;
+ else
+ heir = tree->right->right;
+
+ heir = decorateType (heir, resultTypeProp);
+ if (IS_LITERAL (TETYPE (heir)))
+ TTYPE (heir) = valRecastLitVal (TTYPE (tree->right), valFromType (TETYPE (heir)))->type;
+ else
+ TTYPE (heir) = TTYPE (tree->right);
+ TETYPE (heir) = getSpec (TTYPE (heir));
+ return heir;
+ }
+
+ tree->right = decorateType (tree->right, resultTypeProp);
+
+ if (IS_AST_LIT_VALUE (tree->right->left) && IS_AST_LIT_VALUE (tree->right->right) &&
+ ((resultType == RESULT_TYPE_IFX) || (resultType == RESULT_TYPE_BOOL)))
+ {
+ double valTrue = AST_FLOAT_VALUE (tree->right->left);
+ double valFalse = AST_FLOAT_VALUE (tree->right->right);
+
+ if ((valTrue != 0) && (valFalse == 0))
+ {
+ /* assign cond to result */
+ tree->left->decorated = 0;
+ return decorateType (tree->left, resultTypeProp);
+ }
+ else if ((valTrue == 0) && (valFalse != 0))
+ {
+ /* assign !cond to result */
+ tree->opval.op = '!';
+ tree->decorated = 0;
+ tree->right = NULL;
+ return decorateType (tree, resultTypeProp);
+ }
+ else
+ {
+ /* they have the same boolean value, make them equal */
+ tree->right->left = tree->right->right;
+ }
+ }
+
+ /* if they are equal then replace the tree */
+ if (isAstEqual (tree->right->left, tree->right->right))
+ {
+ return tree->right->left;
+ }
+
+ TTYPE (tree) = RTYPE (tree);
+ TETYPE (tree) = getSpec (TTYPE (tree));
+ return tree;
+
+ case GENERIC:
+ {
+ sym_link *type = tree->left->ftype;
+ ast *assoc_list;
+ ast *default_expr = 0;
+ ast *found_expr = 0;
+
+ for(assoc_list = tree->right; assoc_list; assoc_list = assoc_list->left)
+ {
+ ast *const assoc = assoc_list->right;
+ if (!assoc->left)
+ {
+ if (default_expr)
+ {
+ werror (E_MULTIPLE_DEFAULT_IN_GENERIC);
+ goto errorTreeReturn;
+ }
+ default_expr = assoc->right;
+ }
+ else
+ {
+ sym_link *assoc_type;
+ wassert (IS_AST_LINK (assoc->left));
+ assoc_type = assoc->left->opval.lnk;
+ checkTypeSanity (assoc_type, "_Generic");
+
+ if (compareType (type, assoc->left->opval.lnk) > 0 && !(SPEC_NOUN (type) == V_CHAR && type->select.s.b_implicit_sign != assoc->left->opval.lnk->select.s.b_implicit_sign))
+ {
+ if (found_expr)
+ {
+ werror (E_MULTIPLE_MATCHES_IN_GENERIC);
+ goto errorTreeReturn;
+ }
+ found_expr = assoc->right;
+ }
+ }
+ }
+ if (!found_expr)
+ found_expr = default_expr;
+
+ if (!found_expr)
+ {
+ werror (E_NO_MATCH_IN_GENERIC);
+ goto errorTreeReturn;
+ }
+
+ tree = found_expr;
+ }
+ return tree;
+
+ case GENERIC_ASSOC_LIST:
+ return tree;
+
+ case GENERIC_ASSOCIATION:
+ return tree;
+
+ case ':':
+ if ((compareType (LTYPE (tree), RTYPE (tree)) == 0) && (compareType (RTYPE (tree), LTYPE (tree)) == 0))
+ {
+ if (IS_PTR (LTYPE (tree)) && !IS_GENPTR (LTYPE (tree)))
+ DCL_TYPE (LTYPE(tree)) = GPOINTER;
+ if (IS_PTR (RTYPE (tree)) && !IS_GENPTR (RTYPE (tree)))
+ DCL_TYPE (RTYPE(tree)) = GPOINTER;
+ }
+
+ if ((compareType (LTYPE (tree), RTYPE (tree)) == 0) &&
+ (compareType (RTYPE (tree), LTYPE (tree)) == 0) &&
+ !(IS_ARRAY(LTYPE (tree)) && IS_INTEGRAL(RTYPE (tree))) &&
+ !(IS_ARRAY(RTYPE (tree)) && IS_INTEGRAL(LTYPE (tree))))
+ {
+ werrorfl (tree->filename, tree->lineno, E_TYPE_MISMATCH, "conditional operator", " ");
+ printFromToType (RTYPE (tree), LTYPE (tree));
+ }
+
+ TTYPE (tree) = computeType (LTYPE (tree), RTYPE (tree), resultType, tree->opval.op);
+ TETYPE (tree) = getSpec (TTYPE (tree));
+
+ return tree;
+
+#if 0 // assignment operators are converted by the parser
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* assignment operators */
+ /*----------------------------*/
+ case MUL_ASSIGN:
+ case DIV_ASSIGN:
+ /* for these it must be both must be integral */
+ if (!IS_ARITHMETIC (LTYPE (tree)) || !IS_ARITHMETIC (RTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_OPS_INTEGRAL);
+ goto errorTreeReturn;
+ }
+ RRVAL (tree) = 1;
+ TETYPE (tree) = getSpec (TTYPE (tree) = LTYPE (tree));
+
+ if (!tree->initMode && IS_CONSTANT (LTYPE (tree)))
+ werrorfl (tree->filename, tree->lineno, E_CODE_WRITE, tree->opval.op == MUL_ASSIGN ? "*=" : "/=");
+
+ if (LRVAL (tree))
+ {
+ werrorfl (tree->filename, tree->lineno, E_LVALUE_REQUIRED, tree->opval.op == MUL_ASSIGN ? "*=" : "/=");
+ goto errorTreeReturn;
+ }
+ LLVAL (tree) = 1;
+
+ return tree;
+
+ case AND_ASSIGN:
+ case OR_ASSIGN:
+ case XOR_ASSIGN:
+ case RIGHT_ASSIGN:
+ case LEFT_ASSIGN:
+ /* for these it must be both must be integral */
+ if (!IS_INTEGRAL (LTYPE (tree)) || !IS_INTEGRAL (RTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_OPS_INTEGRAL);
+ goto errorTreeReturn;
+ }
+ RRVAL (tree) = 1;
+ TETYPE (tree) = getSpec (TTYPE (tree) = LTYPE (tree));
+
+ if (!tree->initMode && IS_CONSTANT (LETYPE (tree)))
+ werrorfl (tree->filename, tree->lineno, E_CODE_WRITE, "&= or |= or ^= or >>= or <<=");
+
+ if (LRVAL (tree))
+ {
+ werrorfl (tree->filename, tree->lineno, E_LVALUE_REQUIRED, "&= or |= or ^= or >>= or <<=");
+ goto errorTreeReturn;
+ }
+ LLVAL (tree) = 1;
+
+ return tree;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* -= operator */
+ /*----------------------------*/
+ case SUB_ASSIGN:
+ if (!(IS_PTR (LTYPE (tree)) || IS_ARITHMETIC (LTYPE (tree))))
+ {
+ werrorfl (tree->filename, tree->lineno, E_PLUS_INVALID, "-=");
+ goto errorTreeReturn;
+ }
+
+ if (!(IS_PTR (RTYPE (tree)) || IS_ARITHMETIC (RTYPE (tree))))
+ {
+ werrorfl (tree->filename, tree->lineno, E_PLUS_INVALID, "-=");
+ goto errorTreeReturn;
+ }
+ RRVAL (tree) = 1;
+ TETYPE (tree) = getSpec (TTYPE (tree) = computeType (LTYPE (tree), RTYPE (tree), RESULT_TYPE_NOPROM, tree->opval.op));
+
+ if (!tree->initMode && IS_CONSTANT (LETYPE (tree)))
+ werrorfl (tree->filename, tree->lineno, E_CODE_WRITE, "-=");
+
+ if (LRVAL (tree))
+ {
+ werrorfl (tree->filename, tree->lineno, E_LVALUE_REQUIRED, "-=");
+ goto errorTreeReturn;
+ }
+ LLVAL (tree) = 1;
+
+ return tree;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* += operator */
+ /*----------------------------*/
+ case ADD_ASSIGN:
+ /* this is not a unary operation */
+ /* if both pointers then problem */
+ if (IS_PTR (LTYPE (tree)) && IS_PTR (RTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_PTR_PLUS_PTR);
+ goto errorTreeReturn;
+ }
+
+ if (!IS_ARITHMETIC (LTYPE (tree)) && !IS_PTR (LTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_PLUS_INVALID, "+=");
+ goto errorTreeReturn;
+ }
+
+ if (!IS_ARITHMETIC (RTYPE (tree)) && !IS_PTR (RTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_PLUS_INVALID, "+=");
+ goto errorTreeReturn;
+ }
+ RRVAL (tree) = 1;
+ TETYPE (tree) = getSpec (TTYPE (tree) = computeType (LTYPE (tree), RTYPE (tree), RESULT_TYPE_NOPROM, tree->opval.op));
+
+ if (!tree->initMode && IS_CONSTANT (LETYPE (tree)))
+ werrorfl (tree->filename, tree->lineno, E_CODE_WRITE, "+=");
+
+ if (LRVAL (tree))
+ {
+ werrorfl (tree->filename, tree->lineno, E_LVALUE_REQUIRED, "+=");
+ goto errorTreeReturn;
+ }
+
+ tree->right = decorateType (newNode ('+', copyAst (tree->left), tree->right), RESULT_TYPE_NONE);
+ tree->opval.op = '=';
+
+ return tree;
+#endif
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* straight assignemnt */
+ /*----------------------------*/
+ case '=':
+ /* cannot be an array */
+ if (IS_ARRAY (LTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_ARRAY_ASSIGN);
+ goto errorTreeReturn;
+ }
+
+ /* they should either match or be castable */
+ if (compareType (LTYPE (tree), RTYPE (tree)) == 0)
+ {
+ if (IS_CODEPTR (LTYPE (tree)) && IS_FUNC (LTYPE (tree)->next)) /* function pointer */
+ {
+ werrorfl (tree->filename, tree->lineno, E_INCOMPAT_TYPES);
+ printFromToType (RTYPE (tree), LTYPE (tree)->next);
+ }
+ else
+ {
+ int lineno = tree->lineno ? tree->lineno : tree->left->lineno ? tree->left->lineno : tree->right->lineno;
+ werrorfl (tree->filename, lineno, E_TYPE_MISMATCH, "assignment", " ");
+ printFromToType (RTYPE (tree), LTYPE (tree));
+ }
+ }
+
+ /* if the left side of the tree is of type void
+ then report error */
+ if (IS_VOID (LTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_CAST_ZERO);
+ printFromToType (RTYPE (tree), LTYPE (tree));
+ }
+
+ TETYPE (tree) = getSpec (TTYPE (tree) = LTYPE (tree));
+ if (IS_STRUCT (LTYPE (tree)))
+ tree = rewriteStructAssignment (tree);
+ else
+ {
+ RRVAL (tree) = 1;
+ LLVAL (tree) = 1;
+ }
+ if (!tree->initMode)
+ {
+ if (IS_CONSTANT (LTYPE (tree)))
+ werrorfl (tree->filename, tree->lineno, E_CODE_WRITE, "=");
+ }
+ if (tree->initMode && SPEC_STAT (getSpec (LTYPE (tree))) && !constExprTree (tree->right))
+ werrorfl (tree->filename, tree->lineno, E_CONST_EXPECTED, "=");
+ if (LRVAL (tree))
+ {
+ werrorfl (tree->filename, tree->lineno, E_LVALUE_REQUIRED, "=");
+ goto errorTreeReturn;
+ }
+
+ return tree;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* comma operator */
+ /*----------------------------*/
+ case ',':
+ TETYPE (tree) = getSpec (TTYPE (tree) = RTYPE (tree));
+ return tree;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* function call */
+ /*----------------------------*/
+ case CALL:
+ if (IFFUNC_ISCRITICAL (LTYPE(tree)) && (inCriticalFunction || inCriticalBlock))
+ werror (E_INVALID_CRITICAL);
+
+ /* undo any explicit pointer dereference; PCALL will handle it instead */
+ if (IS_FUNC (LTYPE (tree)) && tree->left->type == EX_OP)
+ {
+ if (tree->left->opval.op == '*' && !tree->left->right)
+ tree->left = tree->left->left;
+ }
+
+ /* require a function or pointer to function */
+ if (!IS_FUNC (LTYPE (tree)) && !IS_FUNCPTR (LTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_FUNCTION_EXPECTED);
+ goto errorTreeReturn;
+ }
+
+ /* if there are parms, make sure that
+ parms are decorate / process / reverse only once */
+ if (!tree->right || !tree->right->decorated)
+ {
+ sym_link *functype;
+ parmNumber = 1;
+
+ if (IS_FUNCPTR (LTYPE (tree)))
+ {
+ functype = LTYPE (tree)->next;
+ processFuncPtrArgs (functype);
+ }
+ else
+ functype = LTYPE (tree);
+
+ if (tree->right && tree->right->reversed)
+ reverseParms (tree->right, 0);
+
+ if (processParms (tree->left, FUNC_ARGS (functype), &tree->right, &parmNumber, TRUE))
+ goto errorTreeReturn;
+
+ if (!optimize.noStdLibCall)
+ optStdLibCall (tree, resultType);
+
+ if ((options.stackAuto || IFFUNC_ISREENT (functype)) && !IFFUNC_ISBUILTIN (functype))
+ reverseParms (tree->right, 1);
+
+ TTYPE (tree) = copyLinkChain(functype->next);
+ TETYPE (tree) = getSpec (TTYPE (tree));
+ SPEC_SCLS (TETYPE (tree)) = S_FIXED;
+ }
+ return tree;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* return statement */
+ /*----------------------------*/
+ case RETURN:
+ if (tree->right)
+ {
+ int typecompat;
+
+ if (IS_VOID (currFunc->type->next) && tree->right)
+ {
+ if (!IS_VOID (RTYPE (tree)) || !options.std_sdcc)
+ {
+ werrorfl (tree->filename, tree->lineno, E_FUNC_VOID);
+ goto errorTreeReturn;
+ }
+ }
+
+ typecompat = compareType (currFunc->type->next, RTYPE (tree));
+
+ /* if there is going to be a casting required then add it */
+ if (typecompat == -1)
+ {
+ tree->right = newNode (CAST,
+ newAst_LINK (copyLinkChain (currFunc->type->next)),
+ tree->right);
+ tree->right->values.cast.implicitCast = 1;
+ tree->right->lineno = tree->right->left->lineno = tree->lineno;
+ tree->right->filename = tree->right->left->filename = tree->filename;
+ tree->right = decorateType (tree->right, IS_GENPTR (currFunc->type->next) ? RESULT_TYPE_GPTR : RESULT_TYPE_NONE);
+ }
+ else if (!typecompat)
+ {
+ werrorfl (tree->filename, tree->lineno, W_RETURN_MISMATCH);
+ printFromToType (RTYPE (tree), currFunc->type->next);
+ }
+
+ RRVAL (tree) = 1;
+ }
+ else /* no return value specified */
+ {
+ if (!IS_VOID (currFunc->type->next) && tree->right == NULL)
+ {
+ werrorfl (tree->filename, tree->lineno, W_VOID_FUNC, currFunc->name);
+ /* We will return an undefined value */
+ }
+
+ TTYPE (tree) = TETYPE (tree) = NULL;
+ }
+ return tree;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* switch statement */
+ /*----------------------------*/
+ case SWITCH:
+ /* the switch value must be an integer */
+ if (!IS_INTEGRAL (LTYPE (tree)))
+ {
+ werrorfl (tree->filename, tree->lineno, E_SWITCH_NON_INTEGER);
+ goto errorTreeReturn;
+ }
+ LRVAL (tree) = 1;
+ TTYPE (tree) = TETYPE (tree) = NULL;
+ return tree;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* ifx Statement */
+ /*----------------------------*/
+ case IFX:
+ tree->left = backPatchLabels (tree->left, tree->trueLabel, tree->falseLabel);
+ TTYPE (tree) = TETYPE (tree) = NULL;
+ return tree;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* for Statement */
+ /*----------------------------*/
+ case FOR:
+
+ AST_FOR (tree, initExpr) = decorateType (resolveSymbols (AST_FOR (tree, initExpr)), RESULT_TYPE_NONE);
+ AST_FOR (tree, condExpr) = decorateType (resolveSymbols (AST_FOR (tree, condExpr)), RESULT_TYPE_NONE);
+ AST_FOR (tree, loopExpr) = decorateType (resolveSymbols (AST_FOR (tree, loopExpr)), RESULT_TYPE_NONE);
+
+ /* if the for loop is reversible then
+ reverse it otherwise do what we normally
+ do */
+ {
+ symbol *sym;
+ ast *init, *end;
+
+ if (!AST_FOR (tree, continueLabel)->isref &&
+ !AST_FOR (tree, falseLabel)->isref &&
+ isLoopReversible (tree, &sym, &init, &end))
+ return reverseLoop (tree, sym, init, end);
+ else if (isInitiallyTrue (AST_FOR (tree, initExpr), AST_FOR (tree, condExpr)))
+ {
+ tree = createDoFor (AST_FOR (tree, trueLabel),
+ AST_FOR (tree, continueLabel),
+ AST_FOR (tree, falseLabel),
+ AST_FOR (tree, condLabel),
+ AST_FOR (tree, initExpr),
+ AST_FOR (tree, condExpr),
+ AST_FOR (tree, loopExpr),
+ tree->left,
+ tree->right);
+ return decorateType (tree, RESULT_TYPE_NONE);
+ }
+ else
+ {
+ tree = createFor (AST_FOR (tree, trueLabel),
+ AST_FOR (tree, continueLabel),
+ AST_FOR (tree, falseLabel),
+ AST_FOR (tree, condLabel),
+ AST_FOR (tree, initExpr),
+ AST_FOR (tree, condExpr),
+ AST_FOR (tree, loopExpr),
+ tree->left,
+ tree->right);
+ return decorateType (tree, RESULT_TYPE_NONE);
+ }
+ }
+ case PARAM:
+ werrorfl (tree->filename, tree->lineno, E_INTERNAL_ERROR, __FILE__, __LINE__, "node PARAM shouldn't be processed here");
+ /* but in processParms() */
+ return tree;
+ case INLINEASM:
+ formatInlineAsm (tree->values.inlineasm);
+ TTYPE (tree) = TETYPE (tree) = NULL;
+ return tree;
+ default:
+ TTYPE (tree) = TETYPE (tree) = NULL;
+ return tree;
+ }
+
+ /* some error found this tree will be killed */
+errorTreeReturn:
+ TTYPE (tree) = TETYPE (tree) = newCharLink ();
+ tree->opval.op = NULLOP;
+ tree->isError = 1;
+
+ return tree;
+}
+
+/*-----------------------------------------------------------------*/
+/* sizeofOp - processes size of operation */
+/*-----------------------------------------------------------------*/
+value *
+sizeofOp (sym_link *type)
+{
+ struct dbuf_s dbuf;
+ value *val;
+ int size;
+
+ /* make sure the type is complete and sane */
+ checkTypeSanity (type, "(sizeof)");
+
+ /* get the size and convert it to character */
+ dbuf_init (&dbuf, 128);
+ dbuf_printf (&dbuf, "%d", size = getSize (type));
+ if (!size && !IS_VOID (type))
+ werror (E_SIZEOF_INCOMPLETE_TYPE);
+
+ /* now convert into value */
+ val = constVal (dbuf_c_str (&dbuf));
+ dbuf_destroy (&dbuf);
+ return val;
+}
+
+/*-----------------------------------------------------------------*/
+/* sizeofOp - processes alignment of operation */
+/*-----------------------------------------------------------------*/
+value *
+alignofOp (sym_link *type)
+{
+ value *val;
+
+ /* make sure the type is complete and sane */
+ checkTypeSanity (type, "(_Alignof)");
+
+ val = constVal ("1");
+
+ return val;
+}
+
+/*-----------------------------------------------------------------*/
+/* backPatchLabels - change and or not operators to flow control */
+/*-----------------------------------------------------------------*/
+static ast *
+backPatchLabels (ast * tree, symbol * trueLabel, symbol * falseLabel)
+{
+ if (!tree)
+ return NULL;
+
+ /* while-loops insert a label between the IFX and the condition,
+ therefore look behind the label too */
+ if (tree->opval.op == LABEL && tree->right && IS_ANDORNOT (tree->right))
+ {
+ tree->right = backPatchLabels (tree->right, trueLabel, falseLabel);
+ return tree;
+ }
+
+ if (!(IS_ANDORNOT (tree)))
+ return tree;
+
+ /* if this an and */
+ if (IS_AND (tree))
+ {
+ static int localLbl = 0;
+ symbol *localLabel;
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, 128);
+ dbuf_printf (&dbuf, "_andif_%d", localLbl++);
+ localLabel = newSymbol (dbuf_c_str (&dbuf), NestLevel);
+ dbuf_destroy (&dbuf);
+
+ tree->left = backPatchLabels (tree->left, localLabel, falseLabel);
+
+ /* if left is already a IFX then just change the if true label in that */
+ if (!IS_IFX (tree->left))
+ tree->left = newIfxNode (tree->left, localLabel, falseLabel);
+
+ tree->right = backPatchLabels (tree->right, trueLabel, falseLabel);
+ /* right is a IFX then just join */
+ if (IS_IFX (tree->right))
+ return newNode (NULLOP, tree->left, createLabel (localLabel, tree->right));
+
+ tree->right = newIfxNode (tree->right, trueLabel, falseLabel);
+ tree->right = createLabel (localLabel, tree->right);
+
+ return newNode (NULLOP, tree->left, tree->right);
+ }
+
+ /* if this is an or operation */
+ if (IS_OR (tree))
+ {
+ static int localLbl = 0;
+ symbol *localLabel;
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, 128);
+ dbuf_printf (&dbuf, "_orif_%d", localLbl++);
+ localLabel = newSymbol (dbuf_c_str (&dbuf), NestLevel);
+ dbuf_destroy (&dbuf);
+
+ tree->left = backPatchLabels (tree->left, trueLabel, localLabel);
+
+ /* if left is already a IFX then just change the if true label in that */
+ if (!IS_IFX (tree->left))
+ tree->left = newIfxNode (tree->left, trueLabel, localLabel);
+
+ tree->right = backPatchLabels (tree->right, trueLabel, falseLabel);
+ /* right is a IFX then just join */
+ if (IS_IFX (tree->right))
+ return newNode (NULLOP, tree->left, createLabel (localLabel, tree->right));
+
+ tree->right = newIfxNode (tree->right, trueLabel, falseLabel);
+ tree->right = createLabel (localLabel, tree->right);
+
+ return newNode (NULLOP, tree->left, tree->right);
+ }
+
+ /* change not */
+ if (IS_NOT (tree))
+ {
+ /* call with exchanged labels */
+ tree->left = backPatchLabels (tree->left, falseLabel, trueLabel);
+
+ /* if left isn't already a IFX */
+ if (!IS_IFX (tree->left))
+ {
+ tree->left = newNode (IFX, tree->left, NULL);
+ tree->left->trueLabel = falseLabel;
+ tree->left->falseLabel = trueLabel;
+ }
+ return tree->left;
+ }
+
+ if (IS_IFX (tree))
+ {
+ tree->trueLabel = trueLabel;
+ tree->falseLabel = falseLabel;
+ }
+
+ return tree;
+}
+
+/*-----------------------------------------------------------------*/
+/* createBlock - create expression tree for block */
+/*-----------------------------------------------------------------*/
+ast *
+createBlock (symbol * decl, ast * body)
+{
+ ast *ex;
+
+ /* if the block has nothing */
+ if (!body && !decl)
+ return NULL;
+
+ ex = newNode (BLOCK, NULL, body);
+ ex->values.sym = decl;
+
+ ex->level += LEVEL_UNIT;
+ ex->filename = NULL;
+ ex->lineno = 0;
+ if (body)
+ ex->block = body->block;
+ return ex;
+}
+
+/*-----------------------------------------------------------------*/
+/* createLabel - creates the expression tree for labels */
+/*-----------------------------------------------------------------*/
+ast *
+createLabel (symbol * label, ast * stmnt)
+{
+ symbol *csym;
+ ast *rValue;
+
+ /* must create fresh symbol if the symbol name */
+ /* exists in the symbol table, since there can */
+ /* be a variable with the same name as the labl */
+ if ((csym = findSym (SymbolTab, NULL, label->name)) && (csym->level == label->level))
+ label = newSymbol (label->name, label->level);
+
+ /* put the label in the LabelSymbol table */
+ /* but first check if a label of the same */
+ /* name exists */
+ if ((csym = findSym (LabelTab, NULL, label->name)))
+ werror (E_DUPLICATE_LABEL, label->name);
+ else
+ addSym (LabelTab, label, label->name, label->level, 0, 0);
+
+ label->isitmp = 1;
+ label->islbl = 1;
+ label->key = labelKey++;
+ rValue = newNode (LABEL, newAst_VALUE (symbolVal (label)), stmnt);
+ rValue->filename = NULL;
+ rValue->lineno = 0;
+
+ return rValue;
+}
+
+/*-----------------------------------------------------------------*/
+/* createCase - generates the parsetree for a case statement */
+/*-----------------------------------------------------------------*/
+ast *
+createCase (ast * swStat, ast * caseVal, ast * stmnt)
+{
+ struct dbuf_s dbuf;
+ ast *rexpr;
+ value *val;
+
+ /* if the switch statement does not exist */
+ /* then case is out of context */
+ if (!swStat)
+ {
+ werrorfl (caseVal->filename, caseVal->lineno, E_CASE_CONTEXT);
+ return NULL;
+ }
+
+ caseVal = decorateType (resolveSymbols (caseVal), RESULT_TYPE_NONE);
+ /* if not a constant then error */
+ if (!IS_LITERAL (caseVal->ftype))
+ {
+ werrorfl (caseVal->filename, caseVal->lineno, E_CASE_CONSTANT);
+ return NULL;
+ }
+
+ /* if not a integer than error */
+ if (!IS_INTEGRAL (caseVal->ftype))
+ {
+ werrorfl (caseVal->filename, caseVal->lineno, E_CASE_NON_INTEGER);
+ return NULL;
+ }
+
+ /* find the end of the switch values chain */
+ if (!(val = swStat->values.switchVals.swVals))
+ swStat->values.switchVals.swVals = caseVal->opval.val;
+ else
+ {
+ /* also order the cases according to value */
+ value *pval = NULL;
+ int cVal = (int) ulFromVal (caseVal->opval.val);
+ while (val && (int) ulFromVal (val) < cVal)
+ {
+ pval = val;
+ val = val->next;
+ }
+
+ /* if we reached the end then */
+ if (!val)
+ {
+ pval->next = caseVal->opval.val;
+ }
+ else if ((int) ulFromVal (val) == cVal)
+ {
+ werrorfl (caseVal->filename, caseVal->lineno, E_DUPLICATE_LABEL, "case");
+ return NULL;
+ }
+ else
+ {
+ /* we found a value greater than */
+ /* the current value we must add this */
+ /* before the value */
+ caseVal->opval.val->next = val;
+
+ /* if this was the first in chain */
+ if (swStat->values.switchVals.swVals == val)
+ swStat->values.switchVals.swVals = caseVal->opval.val;
+ else
+ pval->next = caseVal->opval.val;
+ }
+
+ }
+
+ /* create the case label */
+ dbuf_init (&dbuf, 128);
+ dbuf_printf (&dbuf, "_case_%d_%d", swStat->values.switchVals.swNum, (int) ulFromVal (caseVal->opval.val));
+
+ rexpr = createLabel (newSymbol (dbuf_c_str (&dbuf), 0), stmnt);
+ dbuf_destroy (&dbuf);
+ rexpr->filename = 0;
+ rexpr->lineno = 0;
+ return rexpr;
+}
+
+/*-----------------------------------------------------------------*/
+/* createDefault - creates the parse tree for the default statement */
+/*-----------------------------------------------------------------*/
+ast *
+createDefault (ast * swStat, ast * defaultVal, ast * stmnt)
+{
+ struct dbuf_s dbuf;
+ ast *ret;
+
+ /* if the switch statement does not exist */
+ /* then case is out of context */
+ if (!swStat)
+ {
+ werrorfl (defaultVal->filename, defaultVal->lineno, E_CASE_CONTEXT);
+ return NULL;
+ }
+
+ if (swStat->values.switchVals.swDefault)
+ {
+ werrorfl (defaultVal->filename, defaultVal->lineno, E_DUPLICATE_LABEL, "default");
+ return NULL;
+ }
+
+ /* turn on the default flag */
+ swStat->values.switchVals.swDefault = 1;
+
+ /* create the label */
+ dbuf_init (&dbuf, 128);
+ dbuf_printf (&dbuf, "_default_%d", swStat->values.switchVals.swNum);
+ ret = createLabel (newSymbol (dbuf_c_str (&dbuf), 0), stmnt);
+ dbuf_destroy (&dbuf);
+ return ret;
+}
+
+/*-----------------------------------------------------------------*/
+/* createIf - creates the parsetree for the if statement */
+/*-----------------------------------------------------------------*/
+ast *
+createIf (ast * condAst, ast * ifBody, ast * elseBody)
+{
+ static int Lblnum = 0;
+ ast *ifTree;
+ symbol *ifTrue, *ifFalse, *ifEnd;
+ struct dbuf_s dbuf;
+
+ /* if neither exists */
+ if (!elseBody && !ifBody)
+ {
+ // if there are no side effects (i++, j() etc)
+ if (!hasSEFcalls (condAst))
+ {
+ return condAst;
+ }
+ }
+
+ /* create the labels */
+ dbuf_init (&dbuf, 128);
+ dbuf_printf (&dbuf, "__iffalse_%d", Lblnum);
+ ifFalse = newSymbol (dbuf_c_str (&dbuf), NestLevel);
+ dbuf_destroy (&dbuf);
+ /* if no else body then end == false */
+ if (!elseBody)
+ {
+ ifEnd = ifFalse;
+ }
+ else
+ {
+ dbuf_init (&dbuf, 128);
+ dbuf_printf (&dbuf, "__ifend_%d", Lblnum);
+ ifEnd = newSymbol (dbuf_c_str (&dbuf), NestLevel);
+ dbuf_destroy (&dbuf);
+ }
+
+ dbuf_init (&dbuf, 128);
+ dbuf_printf (&dbuf, "__iftrue_%d", Lblnum);
+ ifTrue = newSymbol (dbuf_c_str (&dbuf), NestLevel);
+ dbuf_destroy (&dbuf);
+
+ Lblnum++;
+
+ /* attach the ifTrue label to the top of it body */
+ ifBody = createLabel (ifTrue, ifBody);
+ /* attach a goto end to the ifBody if else is present */
+ if (elseBody)
+ {
+ ifBody = newNode (NULLOP, ifBody, newNode (GOTO, newAst_VALUE (symbolVal (ifEnd)), NULL));
+ /* put the elseLabel on the else body */
+ elseBody = createLabel (ifFalse, elseBody);
+ /* out the end at the end of the body */
+ elseBody = newNode (NULLOP, elseBody, createLabel (ifEnd, NULL));
+ }
+ else
+ {
+ ifBody = newNode (NULLOP, ifBody, createLabel (ifFalse, NULL));
+ }
+ condAst = backPatchLabels (condAst, ifTrue, ifFalse);
+ if (IS_IFX (condAst))
+ ifTree = condAst;
+ else
+ ifTree = newIfxNode (condAst, ifTrue, ifFalse);
+
+ return newNode (NULLOP, ifTree, newNode (NULLOP, ifBody, elseBody));
+
+}
+
+/*-----------------------------------------------------------------*/
+/* createDo - creates parse tree for do */
+/* _dobody_n: */
+/* statements */
+/* _docontinue_n: */
+/* condition_expression +-> trueLabel -> _dobody_n */
+/* | */
+/* +-> falseLabel-> _dobreak_n */
+/* _dobreak_n: */
+/*-----------------------------------------------------------------*/
+ast *
+createDo (symbol * trueLabel, symbol * continueLabel, symbol * falseLabel, ast * condAst, ast * doBody)
+{
+ ast *doTree;
+
+ /* if the body does not exist then it is simple */
+ if (!doBody)
+ {
+ condAst = backPatchLabels (condAst, continueLabel, falseLabel);
+ if (condAst && !IS_IFX (condAst))
+ {
+ condAst = newNode (IFX, condAst, NULL);
+ condAst->trueLabel = continueLabel;
+ condAst->falseLabel = NULL;
+ }
+
+ doTree = createLabel (continueLabel, condAst);
+ doTree = newNode (NULLOP, doTree, createLabel (falseLabel, NULL));
+ return doTree;
+ }
+
+ /* otherwise we have a body */
+ condAst = backPatchLabels (condAst, trueLabel, falseLabel);
+
+ /* attach the body label to the top */
+ doBody = createLabel (trueLabel, doBody);
+ /* attach the continue label to end of body */
+ doBody = newNode (NULLOP, doBody, createLabel (continueLabel, NULL));
+
+ /* now put the break label at the end */
+ if (IS_IFX (condAst))
+ doTree = condAst;
+ else
+ doTree = newIfxNode (condAst, trueLabel, falseLabel);
+
+ doTree = newNode (NULLOP, doTree, createLabel (falseLabel, NULL));
+
+ /* putting it together */
+ return newNode (NULLOP, doBody, doTree);
+}
+
+/*-----------------------------------------------------------------*/
+/* createFor - creates parse tree for 'for' statement */
+/* initExpr */
+/* _forcond_n: */
+/* condExpr +-> trueLabel -> _forbody_n */
+/* | */
+/* +-> falseLabel-> _forbreak_n */
+/* _forbody_n: */
+/* statements */
+/* _forcontinue_n: */
+/* loopExpr */
+/* goto _forcond_n ; */
+/* _forbreak_n: */
+/*-----------------------------------------------------------------*/
+ast *
+createFor (symbol * trueLabel, symbol * continueLabel, symbol * falseLabel,
+ symbol * condLabel, ast * initExpr, ast * condExpr, ast * loopExpr,
+ ast * forBody, ast * continueLabelAst)
+{
+ ast *forTree;
+
+ /* vanilla for statement */
+ condExpr = backPatchLabels (condExpr, trueLabel, falseLabel);
+
+ if (condExpr && !IS_IFX (condExpr))
+ condExpr = newIfxNode (condExpr, trueLabel, falseLabel);
+
+ /* attach body label to body */
+ forBody = createLabel (trueLabel, forBody);
+
+ /* attach condition label to condition */
+ condExpr = createLabel (condLabel, condExpr);
+
+ /* attach continue to forLoop expression & attach */
+ /* goto the forcond @ and of loopExpression */
+ loopExpr = newNode (NULLOP, loopExpr, newNode (GOTO, newAst_VALUE (symbolVal (condLabel)), NULL));
+ if (continueLabelAst)
+ {
+ continueLabelAst->right = loopExpr;
+ loopExpr = continueLabelAst;
+ }
+ else
+ loopExpr = createLabel (continueLabel, loopExpr);
+
+ /* now start putting them together */
+ forTree = newNode (NULLOP, initExpr, condExpr);
+ forTree = newNode (NULLOP, forTree, forBody);
+ forTree = newNode (NULLOP, forTree, loopExpr);
+
+ /* the break label is already in the tree as a sibling */
+ /* to the original FOR node this tree is replacing */
+ return forTree;
+}
+
+/*-----------------------------------------------------------------*/
+/* createWhile - creates parse tree for while statement */
+/* the while statement will be created as follows */
+/* */
+/* _while_continue_n: */
+/* condition_expression +-> trueLabel -> _while_boby_n */
+/* | */
+/* +-> falseLabel -> _while_break_n */
+/* _while_body_n: */
+/* statements */
+/* goto _while_continue_n */
+/* _while_break_n: */
+/*-----------------------------------------------------------------*/
+ast *
+createWhile (symbol * trueLabel, symbol * continueLabel, symbol * falseLabel, ast * condExpr, ast * whileBody)
+{
+ ast *whileTree;
+
+ /* put the continue label */
+ condExpr = backPatchLabels (condExpr, trueLabel, falseLabel);
+ if (condExpr && !IS_IFX (condExpr))
+ {
+ condExpr = newNode (IFX, condExpr, NULL);
+ /* put the true & false labels in place */
+ condExpr->trueLabel = trueLabel;
+ condExpr->falseLabel = falseLabel;
+ }
+ whileTree = createLabel (continueLabel, condExpr);
+ whileTree->filename = NULL;
+ whileTree->lineno = 0;
+
+ /* put the body label in front of the body */
+ whileBody = createLabel (trueLabel, whileBody);
+ whileBody->filename = NULL;
+ whileBody->lineno = 0;
+ /* put a jump to continue at the end of the body */
+ /* and put break label at the end of the body */
+ whileBody = newNode (NULLOP,
+ whileBody, newNode (GOTO, newAst_VALUE (symbolVal (continueLabel)), createLabel (falseLabel, NULL)));
+
+ /* put it all together */
+ return newNode (NULLOP, whileTree, whileBody);
+}
+
+/*-----------------------------------------------------------------*/
+/* isShiftRightLitVal _BitAndLitVal - helper function */
+/*-----------------------------------------------------------------*/
+static ast *
+isShiftRightLitVal_BitAndLitVal (ast * tree)
+{
+ /* if this is not a bit and */
+ if (!IS_BITAND (tree))
+ return NULL;
+
+ /* will look for tree of the form
+ ( expr >> litval2) & litval1 */
+ if (!IS_AST_LIT_VALUE (tree->right))
+ return NULL;
+
+ if (!IS_RIGHT_OP (tree->left))
+ return NULL;
+
+ if (!IS_AST_LIT_VALUE (tree->left->right))
+ return NULL;
+
+ return tree->left->left;
+}
+
+/*-----------------------------------------------------------------*/
+/* isBitAndPowOf2 - helper function */
+/*-----------------------------------------------------------------*/
+static int
+isBitAndPow2 (ast * tree)
+{
+ /* if this is not a bit and */
+ if (!IS_BITAND (tree))
+ return -1;
+
+ /* will look for tree of the form
+ ( expr & (1 << litval) */
+ if (!IS_AST_LIT_VALUE (tree->right))
+ return -1;
+
+ return powof2 (AST_ULONG_VALUE (tree->right));
+}
+
+/*-----------------------------------------------------------------*/
+/* optimizeGetHbit - get highest order bit of the expression */
+/*-----------------------------------------------------------------*/
+ast *
+optimizeGetHbit (ast * tree, RESULT_TYPE resultType)
+{
+ unsigned int bit, msb;
+ ast *expr;
+
+ expr = isShiftRightLitVal_BitAndLitVal (tree);
+ if (expr)
+ {
+ if ((AST_ULONG_VALUE (tree->right) != 1) ||
+ ((bit = AST_ULONG_VALUE (tree->left->right)) != (msb = (bitsForType (TTYPE (expr)) - 1))))
+ expr = NULL;
+ }
+ if (!expr && (resultType == RESULT_TYPE_BOOL))
+ {
+ int bit = isBitAndPow2 (tree);
+ expr = tree->left;
+ msb = bitsForType (TTYPE (expr)) - 1;
+ if ((bit < 0) || (bit != (int) msb))
+ expr = NULL;
+ }
+ if (!expr || IS_BOOLEAN (TTYPE (expr)))
+ return tree;
+
+ /* make sure the port supports GETHBIT */
+ if (port->hasExtBitOp && !port->hasExtBitOp (GETHBIT, getSize (TTYPE (expr))))
+ return tree;
+
+ return decorateType (newNode (GETHBIT, expr, NULL), resultType);
+}
+
+/*-----------------------------------------------------------------*/
+/* optimizeGetAbit - get a single bit of the expression */
+/*-----------------------------------------------------------------*/
+ast *
+optimizeGetAbit (ast * tree, RESULT_TYPE resultType)
+{
+ ast *expr;
+ ast *count = NULL;
+
+ expr = isShiftRightLitVal_BitAndLitVal (tree);
+ if (expr)
+ {
+ if (AST_ULONG_VALUE (tree->right) != 1)
+ expr = NULL;
+ count = tree->left->right;
+ }
+ if (!expr && (resultType == RESULT_TYPE_BOOL))
+ {
+ int p2 = isBitAndPow2 (tree);
+ if (p2 >= 0 && !IS_BOOLEAN (TTYPE (tree->left)))
+ {
+ expr = tree->left;
+ count = newAst_VALUE (valueFromLit (p2));
+ }
+ }
+ if (!expr)
+ return tree;
+
+ /* make sure the port supports GETABIT */
+ if (port->hasExtBitOp && !port->hasExtBitOp (GETABIT, getSize (TTYPE (expr))))
+ return tree;
+
+ return decorateType (newNode (GETABIT, expr, count), resultType);
+}
+
+/*-----------------------------------------------------------------*/
+/* optimizeGetByte - get a byte of the expression */
+/*-----------------------------------------------------------------*/
+ast *
+optimizeGetByte (ast * tree, RESULT_TYPE resultType)
+{
+ unsigned int i = 1;
+ unsigned int size;
+ ast *expr;
+ ast *count = NULL;
+
+ expr = isShiftRightLitVal_BitAndLitVal (tree);
+ if (expr)
+ {
+ i = AST_ULONG_VALUE (tree->left->right);
+ count = tree->left->right;
+ if (AST_ULONG_VALUE (tree->right) != 0xFF)
+ expr = NULL;
+ }
+ if (!expr && resultType == RESULT_TYPE_CHAR)
+ {
+ /* if this is a right shift over a multiple of 8 */
+ if (IS_RIGHT_OP (tree) && IS_AST_LIT_VALUE (tree->right))
+ {
+ i = AST_ULONG_VALUE (tree->right);
+ count = tree->right;
+ expr = tree->left;
+ }
+ }
+ if (!expr || (i % 8))
+ return tree;
+ size = getSize (TTYPE (expr));
+ if ((i >= size * 8) || (size <= 1))
+ return tree;
+
+ /* make sure the port supports GETBYTE */
+ if (port->hasExtBitOp && !port->hasExtBitOp (GETBYTE, size))
+ return tree;
+
+ return decorateType (newNode (GETBYTE, expr, count), RESULT_TYPE_NONE);
+}
+
+/*-----------------------------------------------------------------*/
+/* optimizeGetWord - get two bytes of the expression */
+/*-----------------------------------------------------------------*/
+ast *
+optimizeGetWord (ast *tree, RESULT_TYPE resultType)
+{
+ unsigned int i = 1;
+ unsigned int size;
+ ast *expr;
+ ast *count = NULL;
+
+ expr = isShiftRightLitVal_BitAndLitVal (tree);
+
+ if (expr)
+ {
+ i = AST_ULONG_VALUE (tree->left->right);
+ count = tree->left->right;
+ if (AST_ULONG_VALUE (tree->right) != 0xFFFF)
+ expr = NULL;
+ }
+ if (!expr && resultType == RESULT_TYPE_INT)
+ {
+ /* if this is a right shift over a multiple of 8 */
+ if (IS_RIGHT_OP (tree) && IS_AST_LIT_VALUE (tree->right))
+ {
+ i = AST_ULONG_VALUE (tree->right);
+ count = tree->right;
+ expr = tree->left;
+ }
+ }
+ if (!expr || (i % 8))
+ return tree;
+ size = getSize (TTYPE (expr));
+ if ((i >= (size - 1) * 8) || (size <= 2))
+ return tree;
+
+ /* make sure the port supports GETWORD */
+ if (port->hasExtBitOp && !port->hasExtBitOp (GETWORD, size))
+ return tree;
+
+ return decorateType (newNode (GETWORD, expr, count), RESULT_TYPE_NONE);
+}
+
+/*-----------------------------------------------------------------*/
+/* optimizeRRCRLC :- optimize for Rotate Left/Right with carry */
+/*-----------------------------------------------------------------*/
+ast *
+optimizeRRCRLC (ast * root)
+{
+ /* will look for trees of the form
+ (?expr << 1) | (?expr >> 7) or
+ (?expr >> 7) | (?expr << 1) will make that
+ into a RLC : operation ..
+ Will also look for
+ (?expr >> 1) | (?expr << 7) or
+ (?expr << 7) | (?expr >> 1) will make that
+ into a RRC operation
+ note : by 7 I mean (number of bits required to hold the
+ variable -1 ) */
+ /* if the root operation is not a | operation then not */
+ if (!IS_BITOR (root))
+ return root;
+
+ /* I have to think of a better way to match patterns this sucks */
+ /* that aside let's start looking for the first case : I use a
+ negative check a lot to improve the efficiency */
+ /* (?expr << 1) | (?expr >> 7) */
+ if (IS_LEFT_OP (root->left) && IS_RIGHT_OP (root->right))
+ {
+
+ if (!SPEC_USIGN (TETYPE (root->left->left)))
+ return root;
+
+ if (!IS_AST_LIT_VALUE (root->left->right) || !IS_AST_LIT_VALUE (root->right->right))
+ goto tryNext0;
+
+ /* make sure it is the same expression */
+ if (!isAstEqual (root->left->left, root->right->left))
+ goto tryNext0;
+
+ if (AST_ULONG_VALUE (root->left->right) != 1)
+ goto tryNext0;
+
+ if (AST_ULONG_VALUE (root->right->right) != (getSize (TTYPE (root->left->left)) * 8 - 1))
+ goto tryNext0;
+
+ /* make sure the port supports RLC */
+ if (port->hasExtBitOp && !port->hasExtBitOp (RLC, getSize (TTYPE (root->left->left))))
+ return root;
+
+ /* whew got the first case : create the AST */
+ return newNode (RLC, root->left->left, NULL);
+ }
+
+tryNext0:
+ /* check for second case */
+ /* (?expr >> 7) | (?expr << 1) */
+ if (IS_LEFT_OP (root->right) && IS_RIGHT_OP (root->left))
+ {
+
+ if (!SPEC_USIGN (TETYPE (root->left->left)))
+ return root;
+
+ if (!IS_AST_LIT_VALUE (root->left->right) || !IS_AST_LIT_VALUE (root->right->right))
+ goto tryNext1;
+
+ /* make sure it is the same symbol */
+ if (!isAstEqual (root->left->left, root->right->left))
+ goto tryNext1;
+
+ if (AST_ULONG_VALUE (root->right->right) != 1)
+ goto tryNext1;
+
+ if (AST_ULONG_VALUE (root->left->right) != (getSize (TTYPE (root->left->left)) * 8 - 1))
+ goto tryNext1;
+
+ /* make sure the port supports RLC */
+ if (port->hasExtBitOp && !port->hasExtBitOp (RLC, getSize (TTYPE (root->left->left))))
+ return root;
+
+ /* whew got the first case : create the AST */
+ return newNode (RLC, root->left->left, NULL);
+
+ }
+
+tryNext1:
+ /* third case for RRC */
+ /* (?symbol >> 1) | (?symbol << 7) */
+ if (IS_LEFT_OP (root->right) && IS_RIGHT_OP (root->left))
+ {
+
+ if (!SPEC_USIGN (TETYPE (root->left->left)))
+ return root;
+
+ if (!IS_AST_LIT_VALUE (root->left->right) || !IS_AST_LIT_VALUE (root->right->right))
+ goto tryNext2;
+
+ /* make sure it is the same symbol */
+ if (!isAstEqual (root->left->left, root->right->left))
+ goto tryNext2;
+
+ if (AST_ULONG_VALUE (root->left->right) != 1)
+ goto tryNext2;
+
+ if (AST_ULONG_VALUE (root->right->right) != (getSize (TTYPE (root->left->left)) * 8 - 1))
+ goto tryNext2;
+
+ /* make sure the port supports RRC */
+ if (port->hasExtBitOp && !port->hasExtBitOp (RRC, getSize (TTYPE (root->left->left))))
+ return root;
+
+ /* whew got the first case : create the AST */
+ return newNode (RRC, root->left->left, NULL);
+
+ }
+tryNext2:
+ /* fourth and last case for now */
+ /* (?symbol << 7) | (?symbol >> 1) */
+ if (IS_RIGHT_OP (root->right) && IS_LEFT_OP (root->left))
+ {
+ if (!SPEC_USIGN (TETYPE (root->left->left)))
+ return root;
+
+ if (!IS_AST_LIT_VALUE (root->left->right) || !IS_AST_LIT_VALUE (root->right->right))
+ return root;
+
+ /* make sure it is the same symbol */
+ if (!isAstEqual (root->left->left, root->right->left))
+ return root;
+
+ if (AST_ULONG_VALUE (root->right->right) != 1)
+ return root;
+
+ if (AST_ULONG_VALUE (root->left->right) != (getSize (TTYPE (root->left->left)) * 8 - 1))
+ return root;
+
+ /* make sure the port supports RRC */
+ if (port->hasExtBitOp && !port->hasExtBitOp (RRC, getSize (TTYPE (root->left->left))))
+ return root;
+
+ /* whew got the first case : create the AST */
+ return newNode (RRC, root->left->left, NULL);
+ }
+
+ /* not found return root */
+ return root;
+}
+
+/*-----------------------------------------------------------------*/
+/* optimizeSWAP :- optimize for nibble/byte/word swaps */
+/*-----------------------------------------------------------------*/
+ast *
+optimizeSWAP (ast * root)
+{
+ /* will look for trees of the form
+ (?expr << 4) | (?expr >> 4) or
+ (?expr >> 4) | (?expr << 4) will make that
+ into a SWAP : operation ..
+ note : by 4 I mean (number of bits required to hold the
+ variable /2 ) */
+ /* if the root operation is not a | operation then not */
+ if (!IS_BITOR (root))
+ return root;
+
+ /* (?expr << 4) | (?expr >> 4) */
+ if ((IS_LEFT_OP (root->left) && IS_RIGHT_OP (root->right)) || (IS_RIGHT_OP (root->left) && IS_LEFT_OP (root->right)))
+ {
+
+ if (!SPEC_USIGN (TETYPE (root->left->left)))
+ return root;
+
+ if (!IS_AST_LIT_VALUE (root->left->right) || !IS_AST_LIT_VALUE (root->right->right))
+ return root;
+
+ /* make sure it is the same expression */
+ if (!isAstEqual (root->left->left, root->right->left))
+ return root;
+
+ if (AST_ULONG_VALUE (root->left->right) != (getSize (TTYPE (root->left->left)) * 4))
+ return root;
+
+ if (AST_ULONG_VALUE (root->right->right) != (getSize (TTYPE (root->left->left)) * 4))
+ return root;
+
+ /* make sure the port supports SWAP */
+ if (port->hasExtBitOp && !port->hasExtBitOp (SWAP, getSize (TTYPE (root->left->left))))
+ return root;
+
+ /* found it : create the AST */
+ return newNode (SWAP, root->left->left, NULL);
+ }
+
+ /* not found return root */
+ return root;
+}
+
+/*-----------------------------------------------------------------*/
+/* optimizeCompare - optimizes compares for bit variables */
+/*-----------------------------------------------------------------*/
+static ast *
+optimizeCompare (ast * root)
+{
+ ast *optExpr = NULL;
+ value *vleft;
+ value *vright;
+ unsigned int litValue;
+
+ /* if nothing then return nothing */
+ if (!root)
+ return NULL;
+
+ /* if not a compare op then do leaves */
+ if (!IS_COMPARE_OP (root))
+ {
+ root->left = optimizeCompare (root->left);
+ root->right = optimizeCompare (root->right);
+ return root;
+ }
+
+ /* if left & right are the same then depending
+ of the operation do */
+ if (isAstEqual (root->left, root->right) && !hasSEFcalls (root))
+ {
+ switch (root->opval.op)
+ {
+ case '>':
+ case '<':
+ case NE_OP:
+ optExpr = newAst_VALUE (constBoolVal (0));
+ break;
+ case GE_OP:
+ case LE_OP:
+ case EQ_OP:
+ optExpr = newAst_VALUE (constBoolVal (1));
+ break;
+ }
+
+ return decorateType (optExpr, RESULT_TYPE_NONE);
+ }
+
+ vleft = (root->left->type == EX_VALUE ? root->left->opval.val : NULL);
+
+ vright = (root->right->type == EX_VALUE ? root->right->opval.val : NULL);
+
+ /* if left is a BITVAR in BITSPACE */
+ /* and right is a LITERAL then */
+ /* optimize else do nothing */
+ if (vleft && vright && IS_BITVAR (vleft->etype) && IN_BITSPACE (SPEC_OCLS (vleft->etype)) && IS_LITERAL (vright->etype))
+ {
+ /* if right side > 1 then comparison may never succeed */
+ if ((litValue = (int) ulFromVal (vright)) > 1)
+ {
+ werror (W_BAD_COMPARE);
+ goto noOptimize;
+ }
+
+ if (litValue)
+ {
+ switch (root->opval.op)
+ {
+ case '>': /* bit value greater than 1 cannot be */
+ werror (W_BAD_COMPARE);
+ goto noOptimize;
+ break;
+
+ case '<': /* bit value < 1 means 0 */
+ case NE_OP:
+ optExpr = newNode ('!', newAst_VALUE (vleft), NULL);
+ break;
+
+ case LE_OP: /* bit value <= 1 means no check */
+ optExpr = newAst_VALUE (vright);
+ break;
+
+ case GE_OP: /* bit value >= 1 means only check for = */
+ case EQ_OP:
+ optExpr = newAst_VALUE (vleft);
+ break;
+ }
+ }
+ else
+ { /* literal is zero */
+ switch (root->opval.op)
+ {
+ case '<': /* bit value < 0 cannot be */
+ werror (W_BAD_COMPARE);
+ goto noOptimize;
+ break;
+
+ case '>': /* bit value > 0 means 1 */
+ case NE_OP:
+ optExpr = newAst_VALUE (vleft);
+ break;
+
+ case LE_OP: /* bit value <= 0 means no check */
+ case GE_OP: /* bit value >= 0 means no check */
+ werror (W_BAD_COMPARE);
+ goto noOptimize;
+ break;
+
+ case EQ_OP: /* bit == 0 means ! of bit */
+ optExpr = newNode ('!', newAst_VALUE (vleft), NULL);
+ break;
+ }
+ }
+ return decorateType (resolveSymbols (optExpr), RESULT_TYPE_NONE);
+ } /* end-of-if of BITVAR */
+
+noOptimize:
+ return root;
+}
+
+/*-----------------------------------------------------------------*/
+/* addSymToBlock : adds the symbol to the first block we find */
+/*-----------------------------------------------------------------*/
+void
+addSymToBlock (symbol * sym, ast * tree)
+{
+ /* reached end of tree or a leaf */
+ if (!tree || IS_AST_LINK (tree) || IS_AST_VALUE (tree))
+ return;
+
+ /* found a block */
+ if (IS_AST_OP (tree) && tree->opval.op == BLOCK)
+ {
+ symbol *lsym = copySymbol (sym);
+
+ lsym->next = AST_VALUES (tree, sym);
+ AST_VALUES (tree, sym) = lsym;
+ return;
+ }
+
+ addSymToBlock (sym, tree->left);
+ addSymToBlock (sym, tree->right);
+}
+
+/*-----------------------------------------------------------------*/
+/* processRegParms - do processing for register parameters */
+/*-----------------------------------------------------------------*/
+static void
+processRegParms (value * args, ast * body)
+{
+ while (args)
+ {
+ if (IS_REGPARM (args->etype))
+ addSymToBlock (args->sym, body);
+ args = args->next;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* resetParmKey - resets the operandkeys for the symbols */
+/*-----------------------------------------------------------------*/
+DEFSETFUNC (resetParmKey)
+{
+ symbol *sym = item;
+
+ sym->key = 0;
+ sym->defs = NULL;
+ sym->uses = NULL;
+ sym->remat = 0;
+ return 1;
+}
+
+/*------------------------------------------------------------------*/
+/* fixupInlineLabel - change a label in an inlined function so that */
+/* it is always unique no matter how many times */
+/* the function is inlined. */
+/*------------------------------------------------------------------*/
+static void
+fixupInlineLabel (symbol * sym)
+{
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, 128);
+ dbuf_printf (&dbuf, "%s_%d", sym->name, inlineState.count);
+ strncpyz (sym->name, dbuf_c_str (&dbuf), SDCC_NAME_MAX);
+ dbuf_destroy (&dbuf);
+}
+
+/*------------------------------------------------------------------*/
+/* copyAstLoc - copy location information (file, line, block, etc.) */
+/* from one ast node to another */
+/*------------------------------------------------------------------*/
+static void
+copyAstLoc (ast * dest, ast * src)
+{
+ dest->filename = src->filename;
+ dest->lineno = src->lineno;
+ dest->level = src->level;
+ dest->block = src->block;
+ dest->seqPoint = src->seqPoint;
+}
+
+static void fixupInline (ast * tree, long level);
+
+/*-----------------------------------------------------------------*/
+/* fixupInlineInDeclarators - recursively perform various fixups */
+/* on an inline function tree */
+/*-----------------------------------------------------------------*/
+static void
+fixupInlineInDeclarators (struct initList *ival, long level)
+{
+ for (; ival; ival = ival->next)
+ {
+ switch (ival->type)
+ {
+ case INIT_NODE:
+ fixupInline (ival->init.node, level);
+ break;
+ case INIT_DEEP:
+ fixupInlineInDeclarators (ival->init.deep, level);
+ break;
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* fixupInline - perform various fixups on an inline function tree */
+/* to take into account that it is no longer a */
+/* stand-alone function. */
+/*-----------------------------------------------------------------*/
+static void
+fixupInline (ast * tree, long level)
+{
+ int savedBlockno = currBlockno;
+
+ if (IS_AST_OP (tree) && (tree->opval.op == BLOCK))
+ {
+ symbol *decls;
+
+ int thisBlockBlockno;
+
+ btree_add_child(currBlockno, ++blockNo);
+ thisBlockBlockno = blockNo;
+
+ level += LEVEL_UNIT;
+
+ /* Add any declared variables back into the symbol table */
+ for (decls = tree->values.sym; decls; decls = decls->next)
+ {
+ decls->level = level;
+ decls->block = currBlockno = thisBlockBlockno;
+ addSym (SymbolTab, decls, decls->name, decls->level, decls->block, 0);
+
+ if (decls->ival)
+ fixupInlineInDeclarators (decls->ival, level);
+ }
+
+ currBlockno = thisBlockBlockno;
+ }
+
+ tree->level = level;
+ tree->block = currBlockno;
+
+ /* Update symbols */
+ if (IS_AST_VALUE (tree) && tree->opval.val->sym)
+ {
+ symbol *sym = tree->opval.val->sym;
+
+ sym->level = level;
+ sym->block = currBlockno;
+
+ sym->reqv = NULL;
+ SYM_SPIL_LOC (sym) = NULL;
+ sym->key = 0;
+
+ /* If the symbol is a label, we need to renumber it */
+ if (sym->islbl)
+ fixupInlineLabel (sym);
+ }
+
+ /* Update IFX target labels */
+ if (tree->type == EX_OP && tree->opval.op == IFX)
+ {
+ if (tree->trueLabel)
+ fixupInlineLabel (tree->trueLabel);
+ if (tree->falseLabel)
+ fixupInlineLabel (tree->falseLabel);
+ }
+
+ /* Replace RETURN with optional assignment and a GOTO to the end */
+ /* of the inlined function */
+ if (tree->type == EX_OP && tree->opval.op == RETURN)
+ {
+ ast *assignTree = NULL;
+ ast *gotoTree;
+
+ if (inlineState.retsym && tree->right)
+ {
+ assignTree = newNode ('=', newAst_VALUE (symbolVal (copySymbol (inlineState.retsym))), tree->right);
+ copyAstLoc (assignTree, tree);
+ }
+
+ gotoTree = newNode (GOTO, newAst_VALUE (symbolVal (inlineState.retlab)), NULL);
+ copyAstLoc (gotoTree, tree);
+
+ tree->opval.op = NULLOP;
+ tree->left = assignTree;
+ tree->right = gotoTree;
+ }
+
+ /* Update any children */
+ if (tree->left)
+ fixupInline (tree->left, level);
+ if (tree->right)
+ fixupInline (tree->right, level);
+
+ /* Update SWITCH branches */
+ if (tree->type == EX_OP && tree->opval.op == SWITCH)
+ {
+ struct dbuf_s dbuf;
+ const char *oldsuff = tree->values.switchVals.swSuffix;
+
+ dbuf_init (&dbuf, 128);
+ dbuf_printf (&dbuf, "%s_%d", oldsuff ? oldsuff : "", inlineState.count);
+ tree->values.switchVals.swSuffix = dbuf_detach (&dbuf);
+ }
+
+ /* Update FOR expression */
+ if (tree->type == EX_OP && tree->opval.op == FOR)
+ {
+ if (AST_FOR (tree, initExpr))
+ fixupInline (AST_FOR (tree, initExpr), level);
+ if (AST_FOR (tree, condExpr))
+ fixupInline (AST_FOR (tree, condExpr), level);
+ if (AST_FOR (tree, loopExpr))
+ fixupInline (AST_FOR (tree, loopExpr), level);
+
+ if (AST_FOR (tree, trueLabel))
+ fixupInlineLabel (AST_FOR (tree, trueLabel));
+ if (AST_FOR (tree, continueLabel))
+ fixupInlineLabel (AST_FOR (tree, continueLabel));
+ if (AST_FOR (tree, falseLabel))
+ fixupInlineLabel (AST_FOR (tree, falseLabel));
+ if (AST_FOR (tree, condLabel))
+ fixupInlineLabel (AST_FOR (tree, condLabel));
+ }
+
+ if (IS_AST_OP (tree) && (tree->opval.op == LABEL))
+ {
+ symbol *label = tree->left->opval.val->sym;
+
+ label->key = labelKey++;
+ /* Add this label back into the symbol table */
+ addSym (LabelTab, label, label->name, label->level, 0, 0);
+ }
+
+ if (IS_AST_OP (tree) && (tree->opval.op == BLOCK))
+ {
+ level -= LEVEL_UNIT;
+ currBlockno = savedBlockno;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* inlineAddDecl - add a variable declaration to an ast block. It */
+/* is also added to the symbol table if addSymTab */
+/* is nonzero. */
+/*-----------------------------------------------------------------*/
+static void
+inlineAddDecl (symbol * sym, ast * block, int addSymTab, int toFront)
+{
+ sym->reqv = NULL;
+ SYM_SPIL_LOC (sym) = NULL;
+ sym->key = 0;
+ if (block != NULL)
+ {
+ symbol **decl = &(block->values.sym);
+
+ sym->level = block->level;
+ sym->block = block->block;
+
+ while (*decl)
+ {
+ if (strcmp ((*decl)->name, sym->name) == 0)
+ return;
+ decl = &((*decl)->next);
+ }
+
+ if (toFront)
+ {
+ sym->next = block->values.sym;
+ block->values.sym = sym;
+ }
+ else
+ *decl = sym;
+
+ if (addSymTab)
+ addSym (SymbolTab, sym, sym->name, sym->level, sym->block, 0);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* inlineTempVar - create a temporary variable for inlining */
+/*-----------------------------------------------------------------*/
+static symbol *
+inlineTempVar (sym_link * type, long level)
+{
+ symbol *sym;
+
+ sym = newSymbol (genSymName (level), level);
+ sym->type = copyLinkChain (type);
+ sym->etype = getSpec (sym->type);
+ SPEC_SCLS (sym->etype) = S_AUTO;
+ SPEC_OCLS (sym->etype) = NULL;
+ SPEC_EXTR (sym->etype) = 0;
+ SPEC_STAT (sym->etype) = 0;
+ if (IS_SPEC (sym->type))
+ {
+ SPEC_VOLATILE (sym->type) = 0;
+ SPEC_ADDRSPACE (sym->type) = 0;
+ }
+ else
+ {
+ DCL_PTR_VOLATILE (sym->type) = 0;
+ DCL_PTR_ADDRSPACE (sym->type) = 0;
+ }
+ SPEC_ABSA (sym->etype) = 0;
+
+ return sym;
+}
+
+/*-----------------------------------------------------------------*/
+/* inlineFindParm - search an ast tree of parameters to find one */
+/* at a particular index (0=first parameter). */
+/* Returns 0 if not found. */
+/*-----------------------------------------------------------------*/
+static ast *
+inlineFindParm (ast *parms, int index)
+{
+ if (!parms)
+ return 0;
+
+ if (parms->type == EX_OP && parms->opval.op == PARAM)
+ {
+ ast *p;
+
+ if (p = inlineFindParm (parms->left, index))
+ return p;
+
+ if (p = inlineFindParm (parms->right, index - 1))
+ return p;
+ }
+
+ return (index ? 0 : parms);
+}
+
+static void expandInlineFuncs (ast * tree, ast * block);
+
+/*-----------------------------------------------------------------*/
+/* expandInlineFuncsInDeclarators - recursively replace calls to */
+/* inline functions */
+/*-----------------------------------------------------------------*/
+static void
+expandInlineFuncsInDeclarators (struct initList *ival, ast * block)
+{
+ for (; ival; ival = ival->next)
+ {
+ switch (ival->type)
+ {
+ case INIT_NODE:
+ expandInlineFuncs (ival->init.node, block);
+ break;
+ case INIT_DEEP:
+ expandInlineFuncsInDeclarators (ival->init.deep, block);
+ break;
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* expandInlineFuncs - replace calls to inline functions with the */
+/* function itself */
+/*-----------------------------------------------------------------*/
+static void
+expandInlineFuncs (ast * tree, ast * block)
+{
+ if (IS_AST_OP (tree) && (tree->opval.op == CALL) && tree->left && IS_AST_VALUE (tree->left) && tree->left->opval.val->sym)
+ {
+ int savedBlockno = currBlockno;
+ symbol *func = tree->left->opval.val->sym;
+ symbol *csym;
+
+ currBlockno = tree->block;
+
+ /* The symbol is probably not bound yet, so find the real one */
+ csym = findSymWithLevel (SymbolTab, func);
+ if (csym)
+ func = csym;
+
+ if ((inCriticalFunction || inCriticalBlock) && IFFUNC_ISCRITICAL (func->type))
+ werrorfl (tree->left->filename, tree->left->lineno, E_INVALID_CRITICAL);
+
+ /* Is this an inline function that we can inline? */
+ if (IFFUNC_ISINLINE (func->type) && !IFFUNC_HASVARARGS(func->type) && func->funcTree)
+ {
+ symbol *retsym = NULL;
+ symbol *retlab;
+ ast *inlinetree;
+ ast *inlinetree2;
+ ast *temptree;
+ value *args;
+ int argIndex;
+
+ /* Generate a label for the inlined function to branch to */
+ /* in case it contains a return statement */
+ retlab = newSymbol (genSymName (tree->level + LEVEL_UNIT), tree->level + LEVEL_UNIT);
+ retlab->isitmp = 1;
+ retlab->islbl = 1;
+ inlineState.retlab = retlab;
+
+ /* Build the subtree for the inlined function in the form: */
+ /* { //inlinetree block */
+ /* { //inlinetree2 block */
+ /* inline_function_code; */
+ /* retlab: */
+ /* } */
+ /* } */
+ temptree = newNode (LABEL, newAst_VALUE (symbolVal (retlab)), NULL);
+ copyAstLoc (temptree, tree);
+ temptree = newNode (NULLOP, copyAst (func->funcTree), temptree);
+ copyAstLoc (temptree, tree);
+ temptree = newNode (BLOCK, NULL, temptree);
+ copyAstLoc (temptree, tree);
+ inlinetree2 = temptree;
+ inlinetree2->level += 2 * LEVEL_UNIT;
+ inlinetree2->block = blockNo+2;
+
+ /* Handle the return type */
+ if (!IS_VOID (func->type->next))
+ {
+ /* Create a temporary symbol to hold the return value and */
+ /* join it with the inlined function using the comma */
+ /* operator. The fixupInline function will take care of */
+ /* changing return statements into assignments to retsym. */
+ /* (parameter passing and return label omitted for clarity) */
+ /* rettype retsym; */
+ /* ... */
+ /* {{inline_function_code}}, retsym */
+
+ retsym = inlineTempVar (func->type->next, block->level);
+ SPEC_SCLS (retsym->etype) = S_FIXED;
+ inlineAddDecl (retsym, block, TRUE, TRUE);
+ }
+
+ inlinetree = newNode (BLOCK, NULL, inlinetree2);
+ copyAstLoc (inlinetree, tree);
+ inlinetree2->level += LEVEL_UNIT;
+ inlinetree2->block = blockNo+1;
+
+ /* To pass parameters to the inlined function, we need some */
+ /* intermediate variables. This avoids scoping problems */
+ /* when the parameter declaration names are used differently */
+ /* during the function call. For example, a function */
+ /* declared as func(int x, int y) but called as func(y,x). */
+ /* { //inlinetree block */
+ /* type1 temparg1 = argument1; */
+ /* ... */
+ /* typen tempargn = argumentn; */
+ /* { //inlinetree2 block */
+ /* type1 param1 = temparg1; */
+ /* ... */
+ /* typen paramn = tempargn; */
+ /* inline_function_code; */
+ /* retlab: */
+ /* } */
+ /* } */
+ args = FUNC_ARGS (func->type);
+ argIndex = 0;
+
+ while (args)
+ {
+ symbol *temparg;
+ ast *assigntree;
+ symbol *parm;
+ ast *passedarg = inlineFindParm (tree->right, argIndex);
+
+ if (!passedarg)
+ {
+ werror (E_TOO_FEW_PARMS);
+ break;
+ }
+
+ temparg = inlineTempVar (args->sym->type, tree->level + LEVEL_UNIT);
+ inlineAddDecl (copySymbol (temparg), inlinetree, FALSE, FALSE);
+
+ assigntree = newNode ('=', newAst_VALUE (symbolVal (temparg)), passedarg);
+ assigntree->initMode = 1; // tell that assignment is initializer
+ inlinetree->right = newNode (NULLOP, assigntree, inlinetree->right);
+
+ parm = copySymbol (args->sym);
+ inlineAddDecl (parm, inlinetree2, FALSE, FALSE);
+ parm->_isparm = 0;
+
+ assigntree = newNode ('=', newAst_VALUE (symbolVal (parm)), newAst_VALUE (symbolVal (temparg)));
+ assigntree->initMode = 1; // tell that assignment is initializer
+ inlinetree2->right = newNode (NULLOP, assigntree, inlinetree2->right);
+ parm->onStack = 0; // stack usage will be recomputed later
+
+ args = args->next;
+ argIndex++;
+ }
+
+ if (inlineFindParm (tree->right, argIndex) && !IFFUNC_HASVARARGS (func->type))
+ werror (E_TOO_MANY_PARMS);
+
+ /* Handle the return type */
+ if (!IS_VOID (func->type->next))
+ {
+ /* Generate return symbol coma statement; */
+ /* ... */
+ /* {{inline_function_code}}, retsym */
+
+ tree->opval.op = ',';
+ if (IFFUNC_ISCRITICAL (func->type))
+ inlinetree = newNode (CRITICAL, inlinetree, NULL);
+ tree->left = inlinetree;
+ tree->right = newAst_VALUE (symbolVal (retsym));
+ }
+ else
+ {
+ tree->opval.op = NULLOP;
+ if (IFFUNC_ISCRITICAL (func->type))
+ inlinetree = newNode (CRITICAL, inlinetree, NULL);
+ tree->left = NULL;
+ tree->right = inlinetree;
+ }
+ inlineState.retsym = retsym;
+
+ /* Renumber the various internal counters on the inlined */
+ /* function's tree nodes and symbols. Add the inlined */
+ /* function's local variables to the appropriate scope(s). */
+ /* Convert inlined return statements to an assignment to */
+ /* retsym (if needed) and a goto retlab. */
+ fixupInline (inlinetree, inlinetree->level);
+ inlineState.count++;
+ }
+ currBlockno = savedBlockno;
+ }
+
+ /* Recursively continue to search for functions to inline. */
+ if (IS_AST_OP (tree))
+ {
+ if (tree->opval.op == BLOCK)
+ {
+ struct symbol *decls;
+
+ block = tree;
+
+ for (decls = block->values.sym; decls; decls = decls->next)
+ {
+ if (decls->ival)
+ expandInlineFuncsInDeclarators (decls->ival, block);
+ }
+ }
+
+ if (tree->opval.op == FOR)
+ {
+ if (AST_FOR (tree, initExpr))
+ expandInlineFuncs (AST_FOR (tree, initExpr), block);
+ if (AST_FOR (tree, condExpr))
+ expandInlineFuncs (AST_FOR (tree, condExpr), block);
+ if (AST_FOR (tree, loopExpr))
+ expandInlineFuncs (AST_FOR (tree, loopExpr), block);
+ }
+
+ if (tree->left)
+ expandInlineFuncs (tree->left, block);
+ if (tree->right)
+ expandInlineFuncs (tree->right, block);
+ }
+}
+
+/*------------------------------------------------------------*/
+/* createFunctionDecl - Handle all of a function declaration */
+/* except for the function body. */
+/*------------------------------------------------------------*/
+symbol *
+createFunctionDecl (symbol *name)
+{
+ symbol *csym;
+ value *args;
+ sym_link *type;
+
+ /* This change would be done by addSymChain() below anyway.
+ But we need to do it here to avoid checkFunction() to report
+ a mismatch with an earlier declaration (that already underwent the change).
+ Fixed bug #2556. */
+ changePointer (name->type);
+
+ /* if check function return 0 then some problem */
+ if (checkFunction (name, NULL) == 0)
+ return NULL;
+
+ /* Find the arguments in this declaration, if any */
+ type = name->type;
+ while (type && !IS_FUNC(type))
+ type = type->next;
+ assert (type);
+ args = FUNC_ARGS (type);
+
+ /* check if the function name already in the symbol table */
+ if ((csym = findSym (SymbolTab, NULL, name->name)))
+ {
+ name = csym;
+ /* special case for compiler defined functions
+ we need to add the name to the publics list : this
+ actually means we are now compiling the compiler
+ support routine */
+ if (name->cdef)
+ {
+ addSet (&publics, name);
+ }
+ }
+ else
+ {
+ addSymChain (&name);
+ allocVariables (name);
+ }
+
+ /* Now that the function name is in the symbol table, */
+ /* add the names of the arguments */
+ while (args)
+ {
+ if (args->sym)
+ addSymChain (&args->sym);
+ args = args->next;
+ }
+
+ return name;
+}
+
+/*-----------------------------------------------------------------*/
+/* createFunction - This is the key node that calls the iCode for */
+/* generating the code for a function. Note code */
+/* is generated function by function, later when */
+/* add inter-procedural analysis this will change */
+/*-----------------------------------------------------------------*/
+ast *
+createFunction (symbol * name, ast * body)
+{
+ ast *ex;
+ int stack = 0;
+ sym_link *fetype;
+ iCode *piCode = NULL;
+
+ if (!name)
+ return NULL;
+
+ if (getenv ("SDCC_DEBUG_FUNCTION_POINTERS"))
+ fprintf (stderr, "SDCCast.c:createFunction(%s)\n", name->name);
+
+ /* create a dummy block if none exists */
+ if (!body)
+ {
+ body = newNode (BLOCK, NULL, NULL);
+ body->block = ++blockNo;
+ }
+
+ noLineno++;
+
+ name->lastLine = lexLineno;
+ currFunc = name;
+
+ /* set the stack pointer */
+ stackPtr = -port->stack.direction * port->stack.call_overhead;
+ xstackPtr = 0;
+
+ if (IFFUNC_ISISR (name->type))
+ stackPtr -= port->stack.direction * port->stack.isr_overhead;
+
+ if (IFFUNC_ISREENT (name->type) || options.stackAuto)
+ {
+ if (options.useXstack)
+ xstackPtr -= port->stack.direction * port->stack.reent_overhead;
+ else
+ stackPtr -= port->stack.direction * port->stack.reent_overhead;
+ }
+
+ if (IFFUNC_ISBANKEDCALL (name->type))
+ stackPtr -= port->stack.direction * port->stack.banked_overhead;
+
+ fetype = getSpec (name->type); /* get the specifier for the function */
+ /* if this is a reentrant function then */
+ if (IFFUNC_ISREENT (name->type))
+ reentrant++;
+
+ if (FUNC_ISINLINE (name->type) && FUNC_ISNAKED (name->type))
+ werrorfl (name->fileDef, name->lineDef, W_INLINE_NAKED, name->name);
+
+ inlineState.count = 0;
+ expandInlineFuncs (body, NULL);
+
+ if (FUNC_ISINLINE (name->type))
+ name->funcTree = copyAst (body);
+
+ allocParms (FUNC_ARGS (name->type), IFFUNC_ISSMALLC (name->type)); /* allocate the parameters */
+
+ /* do processing for parameters that are passed in registers */
+ processRegParms (FUNC_ARGS (name->type), body);
+
+ /* set the stack pointer */
+ stackPtr = 0;
+ xstackPtr = -1;
+
+ gatherImplicitVariables (body, NULL); /* move implicit variables into blocks */
+
+ /* allocate & autoinit the block variables */
+ processBlockVars (body, &stack, ALLOCATE);
+
+ /* name needs to be mangled */
+ SNPRINTF (name->rname, sizeof (name->rname), "%s%s", port->fun_prefix, name->name);
+
+ body = resolveSymbols (body); /* resolve the symbols */
+ body = decorateType (body, RESULT_TYPE_NONE); /* propagateType & do semantic checks */
+
+ /* save the stack information */
+ if (options.useXstack)
+ name->xstack = SPEC_STAK (fetype) = stack;
+ else
+ name->stack = SPEC_STAK (fetype) = stack;
+
+ ex = newAst_VALUE (symbolVal (name)); /* create name */
+ ex = newNode (FUNCTION, ex, body);
+ ex->block = body->block;
+ ex->values.args = FUNC_ARGS (name->type);
+ ex->decorated = 1;
+ if (options.dump_ast)
+ PA (ex);
+ if (fatalError)
+ goto skipall;
+
+ /* Do not generate code for inline functions unless extern also. */
+#if 0
+ if (FUNC_ISINLINE (name->type) && !IS_EXTERN (fetype))
+ goto skipall;
+#else
+ /* Temporary hack: always generate code for static inline functions. */
+ /* Ideally static inline functions should only be generated if needed. */
+ if (FUNC_ISINLINE (name->type) && !IS_EXTERN (fetype) && !IS_STATIC (fetype))
+ goto skipall;
+#endif
+
+ /* create the node & generate intermediate code */
+ GcurMemmap = code;
+ codeOutBuf = &code->oBuf;
+ piCode = iCodeFromAst (ex);
+ name->generated = 1;
+
+ if (fatalError)
+ goto skipall;
+
+ eBBlockFromiCode (piCode);
+
+ /* if there are any statics then do them */
+ if (staticAutos)
+ {
+ GcurMemmap = statsg;
+ codeOutBuf = &statsg->oBuf;
+ eBBlockFromiCode (iCodeFromAst (decorateType (resolveSymbols (staticAutos), RESULT_TYPE_NONE)));
+ staticAutos = NULL;
+ }
+
+skipall:
+ /* dealloc the block variables */
+ processBlockVars (body, &stack, DEALLOCATE);
+ if (!fatalError)
+ outputDebugStackSymbols ();
+ /* deallocate paramaters */
+ deallocParms (FUNC_ARGS (name->type));
+
+ if (IFFUNC_ISREENT (name->type))
+ reentrant--;
+
+ /* we are done freeup memory & cleanup */
+ noLineno--;
+ if (port->reset_labelKey)
+ labelKey = 1;
+ name->key = 0;
+ FUNC_HASBODY (name->type) = 1;
+ addSet (&operKeyReset, name);
+ applyToSet (operKeyReset, resetParmKey);
+
+ if (options.debug)
+ cdbStructBlock (1);
+
+ cleanUpLevel (LabelTab, 0);
+ cleanUpBlock (StructTab, 1);
+ cleanUpBlock (TypedefTab, 1);
+ cleanUpBlock (AddrspaceTab, 1);
+
+ if (xstack)
+ xstack->syms = NULL;
+ istack->syms = NULL;
+ currFunc = NULL;
+ return NULL;
+}
+
+#define INDENT(x,f) do { fprintf (f, "%s:%d:", tree->filename, tree->lineno); fprintf (f, "%*s", (x) & 0xff, ""); } while (0)
+/*-----------------------------------------------------------------*/
+/* ast_print : prints the ast (for debugging purposes) */
+/*-----------------------------------------------------------------*/
+
+void
+ast_print (ast * tree, FILE * outfile, int indent)
+{
+ if (!tree)
+ return;
+
+ /* can print only decorated trees */
+ if (!tree->decorated)
+ {
+ fprintf (outfile, "tree (%p) not decorated\n", tree);
+ return;
+ }
+
+ /* if any child is an error | this one is an error do nothing */
+ if (tree->isError || (tree->left && tree->left->isError) || (tree->right && tree->right->isError))
+ {
+ fprintf (outfile, "ERROR_NODE(%p)\n", tree);
+ }
+
+ if (tree->opval.op == FUNCTION)
+ {
+ int arg = 0;
+ value *args;
+
+ assert (tree->left != NULL);
+ assert (tree->left->opval.val != NULL);
+
+ args = FUNC_ARGS (tree->left->opval.val->type);
+ fprintf (outfile, "FUNCTION (%s=%p) type (", tree->left->opval.val->name, tree);
+ printTypeChain (tree->left->opval.val->type->next, outfile);
+ fprintf (outfile, ") args (");
+ do
+ {
+ if (arg)
+ {
+ fprintf (outfile, ", ");
+ }
+ printTypeChain (args ? args->type : NULL, outfile);
+ arg++;
+ args = args ? args->next : NULL;
+ }
+ while (args);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent);
+ ast_print (tree->right, outfile, indent);
+ return;
+ }
+ if (tree->opval.op == BLOCK)
+ {
+ symbol *decls = tree->values.sym;
+ INDENT (indent, outfile);
+ fprintf (outfile, "{ L%ld:%ld B%d\n", tree->level / LEVEL_UNIT, tree->level % LEVEL_UNIT, tree->block);
+ while (decls)
+ {
+ INDENT (indent + 2, outfile);
+ fprintf (outfile, "DECLARE SYMBOL (L%ld:%ld B%d %s=%p) type (",
+ decls->level / LEVEL_UNIT, decls->level % LEVEL_UNIT, decls->block, decls->name, decls);
+ printTypeChain (decls->type, outfile);
+ fprintf (outfile, ")");
+ if (decls->ival)
+ {
+ struct initList *ival = decls->ival;
+ fprintf (outfile, " = \n");
+ for (; ival; ival = ival->next)
+ {
+ if (ival->type == INIT_NODE)
+ {
+ ast_print (ival->init.node, outfile, indent + 4);
+ }
+ else
+ {
+ INDENT (indent + 4, outfile);
+ fprintf (outfile, "HUGE initializer skipped\n");
+ }
+ }
+ }
+ else
+ {
+ fprintf (outfile, "\n");
+ }
+
+ decls = decls->next;
+ }
+ ast_print (tree->right, outfile, indent + 2);
+ INDENT (indent, outfile);
+ fprintf (outfile, "}\n");
+ return;
+ }
+ if (tree->opval.op == NULLOP)
+ {
+ ast_print (tree->left, outfile, indent);
+ ast_print (tree->right, outfile, indent);
+ return;
+ }
+ INDENT (indent, outfile);
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* leaf has been reached */
+ /*----------------------------*/
+ /* if this is of type value */
+ /* just get the type */
+ if (tree->type == EX_VALUE)
+ {
+ if (IS_LITERAL (tree->opval.val->etype))
+ {
+ fprintf (outfile, "CONSTANT (%p) value = ", tree);
+ if (SPEC_LONGLONG (tree->opval.val->etype))
+ {
+ unsigned long long ull = ullFromVal (tree->opval.val);
+
+ if (SPEC_USIGN (tree->opval.val->etype))
+ fprintf (outfile, "%llu, 0x%llx", ull, ull);
+ else
+ fprintf (outfile, "%lld, 0x%llx", (signed long long) ull, ull);
+ }
+ else
+ {
+ unsigned long ul = ulFromVal (tree->opval.val);
+
+ if (SPEC_USIGN (tree->opval.val->etype))
+ fprintf (outfile, "%lu", ul);
+ else
+ fprintf (outfile, "%ld", (signed long) ul);
+ fprintf (outfile, ", 0x%lx, %f", ul, floatFromVal (tree->opval.val));
+ }
+ }
+ else if (tree->opval.val->sym)
+ {
+ /* if the undefined flag is set then give error message */
+ if (tree->opval.val->sym->undefined)
+ {
+ fprintf (outfile, "UNDEFINED SYMBOL ");
+ }
+ else
+ {
+ fprintf (outfile, "SYMBOL ");
+ }
+ fprintf (outfile, "(L%ld:%ld B%d %s=%p @ %p)",
+ tree->opval.val->sym->level / LEVEL_UNIT, tree->opval.val->sym->level % LEVEL_UNIT,
+ tree->opval.val->sym->block, tree->opval.val->sym->name, tree, tree->opval.val->sym);
+ }
+ if (tree->ftype)
+ {
+ fprintf (outfile, " type (");
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ }
+ else
+ {
+ fprintf (outfile, "\n");
+ }
+ return;
+ }
+
+ /* if type link for the case of cast */
+ if (tree->type == EX_LINK)
+ {
+ fprintf (outfile, "TYPENODE (%p) type = (", tree);
+ printTypeChain (tree->opval.lnk, outfile);
+ fprintf (outfile, ")\n");
+ return;
+ }
+
+ /* depending on type of operator do */
+ switch (tree->opval.op)
+ {
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* array node */
+ /*----------------------------*/
+ case '[':
+ fprintf (outfile, "ARRAY_OP (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* struct/union */
+ /*----------------------------*/
+ case '.':
+ fprintf (outfile, "STRUCT_ACCESS (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* struct/union pointer */
+ /*----------------------------*/
+ case PTR_OP:
+ fprintf (outfile, "PTR_ACCESS (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* ++/-- operation */
+ /*----------------------------*/
+ case INC_OP:
+ if (tree->left)
+ fprintf (outfile, "post-");
+ else
+ fprintf (outfile, "pre-");
+ fprintf (outfile, "INC_OP (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2); /* postincrement case */
+ ast_print (tree->right, outfile, indent + 2); /* preincrement case */
+ return;
+
+ case DEC_OP:
+ if (tree->left)
+ fprintf (outfile, "post-");
+ else
+ fprintf (outfile, "pre-");
+ fprintf (outfile, "DEC_OP (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2); /* postdecrement case */
+ ast_print (tree->right, outfile, indent + 2); /* predecrement case */
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* bitwise and */
+ /*----------------------------*/
+ case '&':
+ if (tree->right)
+ {
+ fprintf (outfile, "& (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ }
+ else
+ {
+ fprintf (outfile, "ADDRESS_OF (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ }
+ return;
+
+ /*----------------------------*/
+ /* bitwise or */
+ /*----------------------------*/
+ case '|':
+ fprintf (outfile, "OR (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* bitwise xor */
+ /*----------------------------*/
+ case '^':
+ fprintf (outfile, "XOR (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* division */
+ /*----------------------------*/
+ case '/':
+ fprintf (outfile, "DIV (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* modulus */
+ /*----------------------------*/
+ case '%':
+ fprintf (outfile, "MOD (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* address dereference */
+ /*----------------------------*/
+ case '*': /* can be unary : if right is null then unary operation */
+ if (!tree->right)
+ {
+ fprintf (outfile, "DEREF (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ return;
+ }
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* multiplication */
+ /*----------------------------*/
+ fprintf (outfile, "MULT (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* unary '+' operator */
+ /*----------------------------*/
+ case '+':
+ /* if unary plus */
+ if (!tree->right)
+ {
+ fprintf (outfile, "UPLUS (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ }
+ else
+ {
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* addition */
+ /*----------------------------*/
+ fprintf (outfile, "ADD (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ }
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* unary '-' */
+ /*----------------------------*/
+ case '-': /* can be unary */
+ if (!tree->right)
+ {
+ fprintf (outfile, "UMINUS (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ }
+ else
+ {
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* subtraction */
+ /*----------------------------*/
+ fprintf (outfile, "SUB (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ }
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* complement */
+ /*----------------------------*/
+ case '~':
+ fprintf (outfile, "COMPL (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* not */
+ /*----------------------------*/
+ case '!':
+ fprintf (outfile, "NOT (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* shift */
+ /*----------------------------*/
+ case RRC:
+ fprintf (outfile, "RRC (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ return;
+
+ case RLC:
+ fprintf (outfile, "RLC (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ return;
+
+ case SWAP:
+ fprintf (outfile, "SWAP (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ return;
+
+ case GETHBIT:
+ fprintf (outfile, "GETHBIT (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ return;
+
+ case GETABIT:
+ fprintf (outfile, "GETABIT (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ case GETBYTE:
+ fprintf (outfile, "GETBYTE (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ case GETWORD:
+ fprintf (outfile, "GETWORD (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ case LEFT_OP:
+ fprintf (outfile, "LEFT_SHIFT (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ case RIGHT_OP:
+ fprintf (outfile, "RIGHT_SHIFT (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* casting */
+ /*----------------------------*/
+ case CAST: /* change the type */
+ fprintf (outfile, "CAST (%p) from type (", tree);
+ assert (tree->right != NULL);
+ printTypeChain (tree->right->ftype, outfile);
+ fprintf (outfile, ") to type (");
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ case AND_OP:
+ fprintf (outfile, "ANDAND (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ case OR_OP:
+ fprintf (outfile, "OROR (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* comparison operators */
+ /*----------------------------*/
+ case '>':
+ fprintf (outfile, "GT(>) (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ case '<':
+ fprintf (outfile, "LT(<) (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ case LE_OP:
+ fprintf (outfile, "LE(<=) (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ case GE_OP:
+ fprintf (outfile, "GE(>=) (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ case EQ_OP:
+ fprintf (outfile, "EQ(==) (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ case NE_OP:
+ fprintf (outfile, "NE(!=) (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* sizeof */
+ /*----------------------------*/
+ case SIZEOF: /* evaluate wihout code generation */
+ fprintf (outfile, "SIZEOF %d\n", (getSize (tree->right->ftype)));
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* conditional operator '?' */
+ /*----------------------------*/
+ case '?':
+ fprintf (outfile, "QUEST(?) (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ case ':':
+ fprintf (outfile, "COLON(:) (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* assignment operators */
+ /*----------------------------*/
+ case MUL_ASSIGN:
+ fprintf (outfile, "MULASS(*=) (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ case DIV_ASSIGN:
+ fprintf (outfile, "DIVASS(/=) (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ case AND_ASSIGN:
+ fprintf (outfile, "ANDASS(&=) (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ case OR_ASSIGN:
+ fprintf (outfile, "ORASS(|=) (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ case XOR_ASSIGN:
+ fprintf (outfile, "XORASS(^=) (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ case RIGHT_ASSIGN:
+ fprintf (outfile, "RSHFTASS(>>=) (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ case LEFT_ASSIGN:
+ fprintf (outfile, "LSHFTASS(<<=) (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* -= operator */
+ /*----------------------------*/
+ case SUB_ASSIGN:
+ fprintf (outfile, "SUBASS(-=) (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* += operator */
+ /*----------------------------*/
+ case ADD_ASSIGN:
+ fprintf (outfile, "ADDASS(+=) (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* straight assignemnt */
+ /*----------------------------*/
+ case '=':
+ fprintf (outfile, "ASSIGN(=) (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* comma operator */
+ /*----------------------------*/
+ case ',':
+ fprintf (outfile, "COMMA(,) (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* function call */
+ /*----------------------------*/
+ case CALL:
+ case PCALL:
+ fprintf (outfile, "CALL (%p) type (", tree);
+ printTypeChain (tree->ftype, outfile);
+ fprintf (outfile, ")\n");
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ case PARAM:
+ fprintf (outfile, "PARMS\n");
+ ast_print (tree->left, outfile, indent + 2);
+ if (tree->right /*&& !IS_AST_PARAM(tree->right) */ )
+ {
+ ast_print (tree->right, outfile, indent + 2);
+ }
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* return statement */
+ /*----------------------------*/
+ case RETURN:
+ fprintf (outfile, "RETURN (%p) type (", tree);
+ if (tree->right)
+ {
+ printTypeChain (tree->right->ftype, outfile);
+ }
+ fprintf (outfile, ")\n");
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* label statement */
+ /*----------------------------*/
+ case LABEL:
+ fprintf (outfile, "LABEL (%p)\n", tree);
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent);
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* switch statement */
+ /*----------------------------*/
+ case SWITCH:
+ {
+ value *val;
+ fprintf (outfile, "SWITCH (%p) ", tree);
+ ast_print (tree->left, outfile, 0);
+ for (val = tree->values.switchVals.swVals; val; val = val->next)
+ {
+ INDENT (indent + 2, outfile);
+ fprintf (outfile, "CASE 0x%x GOTO _case_%d_%d%s\n",
+ (int) ulFromVal (val),
+ tree->values.switchVals.swNum,
+ (int) ulFromVal (val), tree->values.switchVals.swSuffix ? tree->values.switchVals.swSuffix : "");
+ }
+ ast_print (tree->right, outfile, indent);
+ }
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* ifx Statement */
+ /*----------------------------*/
+ case IFX:
+ fprintf (outfile, "IF (%p) \n", tree);
+ ast_print (tree->left, outfile, indent + 2);
+ if (tree->trueLabel)
+ {
+ INDENT (indent + 2, outfile);
+ fprintf (outfile, "NE(!=) 0 goto %s\n", tree->trueLabel->name);
+ }
+ if (tree->falseLabel)
+ {
+ INDENT (indent + 2, outfile);
+ fprintf (outfile, "EQ(==) 0 goto %s\n", tree->falseLabel->name);
+ }
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ /*----------------------------*/
+ /* goto Statement */
+ /*----------------------------*/
+ case GOTO:
+ fprintf (outfile, "GOTO (%p) \n", tree);
+ ast_print (tree->left, outfile, indent + 2);
+ ast_print (tree->right, outfile, indent + 2);
+ return;
+
+ /*------------------------------------------------------------------*/
+ /*----------------------------*/
+ /* for Statement */
+ /*----------------------------*/
+ case FOR:
+ fprintf (outfile, "FOR (%p) \n", tree);
+ if (AST_FOR (tree, initExpr))
+ {
+ INDENT (indent + 2, outfile);
+ fprintf (outfile, "INIT EXPR ");
+ ast_print (AST_FOR (tree, initExpr), outfile, indent + 2);
+ }
+ if (AST_FOR (tree, condExpr))
+ {
+ INDENT (indent + 2, outfile);
+ fprintf (outfile, "COND EXPR ");
+ ast_print (AST_FOR (tree, condExpr), outfile, indent + 2);
+ }
+ if (AST_FOR (tree, loopExpr))
+ {
+ INDENT (indent + 2, outfile);
+ fprintf (outfile, "LOOP EXPR ");
+ ast_print (AST_FOR (tree, loopExpr), outfile, indent + 2);
+ }
+ fprintf (outfile, "FOR LOOP BODY \n");
+ ast_print (tree->left, outfile, indent + 2);
+ return;
+
+ case CRITICAL:
+ fprintf (outfile, "CRITICAL (%p) \n", tree);
+ ast_print (tree->left, outfile, indent + 2);
+ default:
+ return;
+ }
+}
+
+void
+PA (ast * t)
+{
+ ast_print (t, stdout, 0);
+}
+
+/*-----------------------------------------------------------------*/
+/* astErrors : returns non-zero if errors present in tree */
+/*-----------------------------------------------------------------*/
+int
+astErrors (ast * t)
+{
+ int errors = 0;
+
+ if (t)
+ {
+ if (t->isError)
+ errors++;
+
+ if (t->type == EX_VALUE && t->opval.val->sym && t->opval.val->sym->undefined)
+ errors++;
+
+ errors += astErrors (t->left);
+ errors += astErrors (t->right);
+ }
+
+ return errors;
+}
+
+/*-----------------------------------------------------------------------------
+ * verbatim copy from the gnu gcc-4.1 info page
+ * >
+ * > info node: (gcc-4.1)Offsetof
+ * >
+ * > primary:
+ * > "__builtin_offsetof" "(" `typename' "," offsetof_member_designator ")"
+ * >
+ * > offsetof_member_designator:
+ * > `identifier'
+ * > | offsetof_member_designator "." `identifier'
+ * > | offsetof_member_designator "[" `expr' "]"
+ * >
+ * > This extension is sufficient such that
+ * >
+ * > #define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
+ * > ...
+ *
+ * Note:
+ * `expr', here is indeed any expr valid, not only constants.
+ * `typename', gcc supports typeof(...) here, but the sdcc typeof has
+ * a completely different semantic, more sort of typeid
+ *
+ */
+
+static ast *
+offsetofOp_rec (sym_link * type, ast * snd, sym_link ** result_type)
+{
+ /* make sure the type is complete and sane */
+ checkTypeSanity (type, "(offsetofOp)");
+
+ /* offsetof can only be applied to structs/unions */
+ if (!IS_STRUCT (type))
+ {
+ werrorfl (snd->filename, snd->lineno, E_OFFSETOF_TYPE);
+ *result_type = NULL;
+ return NULL;
+ }
+
+ /* offsetof(struct_type, symbol); */
+ if (IS_AST_SYM_VALUE (snd))
+ {
+ structdef *structdef = SPEC_STRUCT (type);
+ symbol *element = getStructElement (structdef, AST_SYMBOL (snd));
+ *result_type = element->type;
+ return newAst_VALUE (valueFromLit (element->offset));
+ }
+
+ /* offsetof(struct_type, a.something); */
+ if (IS_AST_OP (snd) && snd->opval.op == '.')
+ {
+ sym_link *tmp;
+ ast *o = offsetofOp_rec (type, snd->left, &tmp);
+ return newNode ('+', o, offsetofOp_rec (tmp, snd->right, result_type));
+ }
+
+ /* offsetof(struct_type, a[expr]); */
+ if (IS_ARRAY_OP (snd))
+ {
+ sym_link *tmp;
+ ast *o = offsetofOp_rec (type, snd->left, &tmp);
+ *result_type = tmp->next;
+ return newNode ('+', o, newNode ('*', newAst_VALUE (valueFromLit (getSize (tmp->next))), snd->right));
+ }
+
+ wassertl (0, "this should never have happened");
+ exit (1);
+}
+
+ast *
+offsetofOp (sym_link * type, ast * snd)
+{
+ sym_link *result_type;
+ return offsetofOp_rec (type, snd, &result_type);
+}