]> granicus.if.org Git - yasm/commitdiff
Initial checkin of expression handling.
authorMichael Urman <mu@tortall.net>
Thu, 5 Jul 2001 06:28:54 +0000 (06:28 -0000)
committerMichael Urman <mu@tortall.net>
Thu, 5 Jul 2001 06:28:54 +0000 (06:28 -0000)
svn path=/trunk/yasm/; revision=106

include/Makefile.am
include/expr.h [new file with mode: 0644]
libyasm/expr.c [new file with mode: 0644]
libyasm/expr.h [new file with mode: 0644]
modules/arch/x86/expr.c [new file with mode: 0644]
modules/arch/x86/x86expr.c [new file with mode: 0644]
src/Makefile.am
src/arch/x86/expr.c [new file with mode: 0644]
src/arch/x86/x86expr.c [new file with mode: 0644]
src/expr.c [new file with mode: 0644]
src/expr.h [new file with mode: 0644]

index 07b5cc1673cd53ded7fec6d1348d56ea6a763877..62832edd361f945a2b8cebbd8852268b1e3e2f63 100644 (file)
@@ -1,6 +1,7 @@
 EXTRA_DIST = \
        bytecode.h  \
        errwarn.h   \
+       expr.h      \
        globals.h   \
        section.h   \
        symrec.h    \
diff --git a/include/expr.h b/include/expr.h
new file mode 100644 (file)
index 0000000..18d6eee
--- /dev/null
@@ -0,0 +1,72 @@
+/* $Id: expr.h,v 1.1 2001/07/05 06:28:54 mu Exp $
+ * Expression handling header file
+ *
+ *  Copyright (C) 2001  Michael Urman
+ *
+ *  This file is part of YASM.
+ *
+ *  YASM 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  YASM 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, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef _EXPR_H_
+#define _EXPR_H_
+
+typedef enum {
+    EXPR_ADD,
+    EXPR_SUB,
+    EXPR_MUL,
+    EXPR_DIV,
+    EXPR_MOD,
+    EXPR_NEG,
+    EXPR_NOT,
+    EXPR_OR,
+    EXPR_AND,
+    EXPR_XOR,
+    EXPR_SHL,
+    EXPR_SHR,
+    EXPR_LOR,
+    EXPR_LAND,
+    EXPR_LNOT,
+    EXPR_LT,
+    EXPR_GT,
+    EXPR_EQ,
+    EXPR_LE,
+    EXPR_GE,
+    EXPR_NE,
+    EXPR_IDENT     /* if right is IDENT, then the entire expr is just a num */
+} ExprOp;
+
+typedef enum {
+    EXPR_NONE,     /* for left side of a NOT, NEG, etc. */
+    EXPR_NUM,
+    EXPR_EXPR,
+    EXPR_SYM
+} ExprType;
+
+typedef union expritem_u {
+    struct symrec_s *sym;
+    struct expr_s *expr;
+    int num;
+} ExprItem;
+
+typedef struct expr_s {
+    ExprType ltype, rtype;
+    ExprItem left, right;
+    ExprOp op;
+} expr;
+
+expr *expr_new (ExprType, ExprItem, ExprOp, ExprType, ExprItem);
+int expr_simplify (expr *);
+
+#endif
diff --git a/libyasm/expr.c b/libyasm/expr.c
new file mode 100644 (file)
index 0000000..e621095
--- /dev/null
@@ -0,0 +1,191 @@
+/* $Id: expr.c,v 1.1 2001/07/05 06:28:54 mu Exp $
+ * Expression handling
+ *
+ *  Copyright (C) 2001  Michael Urman
+ *
+ *  This file is part of YASM.
+ *
+ *  YASM 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  YASM 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, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <stdlib.h>
+#include <string.h>
+#include "expr.h"
+#include "symrec.h"
+#include "globals.h"
+#include "errwarn.h"
+
+/* allocate a new expression node, with children as defined.
+ * If it's a unary operator, put the element on the right */
+expr *expr_new (ExprType ltype,
+               ExprItem left,
+               ExprOp op,
+               ExprType rtype,
+               ExprItem right)
+{
+    expr *ptr;
+    ptr = malloc (sizeof (expr));
+    if (ptr == NULL) Fatal (FATAL_NOMEM);
+    ptr->ltype = ltype;
+    ptr->op = op;
+    ptr->rtype = rtype;
+    switch (ltype)
+    {
+       case EXPR_NUM:
+       case EXPR_SYM:
+       case EXPR_EXPR:
+           memcpy (&ptr->left, &left, sizeof (ExprItem));
+           break;
+       case EXPR_NONE: break;
+    }
+    switch (rtype)
+    {
+       case EXPR_NUM:
+       case EXPR_SYM:
+       case EXPR_EXPR:
+           memcpy (&ptr->right, &right, sizeof (ExprItem));
+           break;
+       case EXPR_NONE:
+           Fatal (FATAL_UNKNOWN); /* TODO: better error? */
+           break;
+    }
+    return ptr;
+}
+
+/* get rid of unnecessary branches if possible.  report. */
+int expr_simplify (expr *e)
+{
+    int simplified = 0;
+
+    /* try to simplify the left side */
+    if (e->ltype == EXPR_EXPR)
+    {
+       /* if the left subexpr isn't an IDENT, recurse simplification */
+       if (e->left.expr->op != EXPR_IDENT)
+           simplified |= expr_simplify (e->left.expr);
+
+       /* if the left subexpr is just an IDENT (or string thereof),
+        * pull it up into the current node */
+       while (e->ltype == EXPR_EXPR && e->left.expr->op == EXPR_IDENT)
+       {
+           ExprItem tmp;
+           e->ltype = e->left.expr->rtype;
+           memcpy (&tmp, &(e->left.expr->right), sizeof (ExprItem));
+           free (e->left.expr);
+           memcpy (&(e->left.num), &tmp, sizeof (ExprItem));
+           simplified = 1;
+       }
+    }
+    else if (e->ltype == EXPR_SYM)
+    {
+       /* if it's a symbol that has a defined value, turn it into a
+        * number */
+       if (e->left.sym->status & SYM_VALUED)
+       {
+           e->ltype = EXPR_NUM;
+           /* don't try to free the symrec here. */
+           e->left.num = e->left.sym->value;
+           simplified = 1;
+       }
+    }
+
+    /* ditto on the right */
+    if (e->rtype == EXPR_EXPR)
+    {
+       if (e->right.expr->op != EXPR_IDENT)
+           simplified |= expr_simplify (e->right.expr);
+
+       while (e->rtype == EXPR_EXPR && e->right.expr->op == EXPR_IDENT)
+       {
+           ExprItem tmp;
+           e->rtype = e->right.expr->rtype;
+           memcpy (&tmp, &(e->right.expr->right), sizeof (ExprItem));
+           free (e->right.expr);
+           memcpy (&(e->right.num), &tmp, sizeof (ExprItem));
+           simplified = 1;
+       }
+    }
+    else if (e->rtype == EXPR_SYM)
+    {
+       if (e->right.sym->status & SYM_VALUED)
+       {
+           e->rtype = EXPR_NUM;
+           /* don't try to free the symrec here. */
+           e->right.num = e->right.sym->value;
+           simplified = 1;
+       }
+    }
+
+    if ((e->ltype == EXPR_NUM || e->ltype == EXPR_NONE)
+       && e->rtype == EXPR_NUM
+       && e->op != EXPR_IDENT)
+    {
+       switch (e->op)
+       {
+           case EXPR_ADD: e->right.num = e->left.num + e->right.num; break;
+           case EXPR_SUB: e->right.num = e->left.num - e->right.num; break;
+           case EXPR_MUL: e->right.num = e->left.num * e->right.num; break;
+           case EXPR_DIV: e->right.num = e->left.num / e->right.num; break;
+           case EXPR_MOD: e->right.num = e->left.num % e->right.num; break;
+           case EXPR_NEG: e->right.num = -(e->right.num); break;
+           case EXPR_NOT: e->right.num = ~(e->right.num); break;
+           case EXPR_OR:  e->right.num = e->left.num | e->right.num; break;
+           case EXPR_AND: e->right.num = e->left.num & e->right.num; break;
+           case EXPR_XOR: e->right.num = e->left.num ^ e->right.num; break;
+           case EXPR_SHL: e->right.num = e->right.num << e->left.num; break;
+           case EXPR_SHR: e->right.num = e->right.num << e->left.num; break;
+           case EXPR_LOR: e->right.num = e->left.num || e->right.num; break;
+           case EXPR_LAND: e->right.num = e->left.num && e->right.num; break;
+           case EXPR_LNOT: e->right.num = !e->right.num; break;
+           case EXPR_EQ: e->right.num = e->right.num == e->left.num; break;
+           case EXPR_LT: e->right.num = e->right.num < e->left.num; break;
+           case EXPR_GT: e->right.num = e->right.num > e->left.num; break;
+           case EXPR_LE: e->right.num = e->right.num <= e->left.num; break;
+           case EXPR_GE: e->right.num = e->right.num >= e->left.num; break;
+           case EXPR_NE: e->right.num = e->right.num != e->left.num; break;
+           case EXPR_IDENT: break;
+       }
+       e->op = EXPR_IDENT;
+       simplified = 1;
+    }
+
+    /* catch simple identities like 0+x, 1*x, etc., for x not a num */
+    else if (e->ltype == EXPR_NUM
+            && ((e->left.num == 1 && e->op == EXPR_MUL)
+                ||(e->left.num == 0 && e->op == EXPR_ADD)
+                ||(e->left.num == -1 && e->op == EXPR_AND)
+                ||(e->left.num == 0 && e->op == EXPR_OR)))
+    {
+       e->op = EXPR_IDENT;
+       simplified = 1;
+    }
+    /* and the corresponding x+|-0, x*&/1 */
+    else if (e->rtype == EXPR_NUM
+            && ((e->right.num == 1 && e->op == EXPR_MUL)
+                ||(e->right.num == 1 && e->op == EXPR_DIV)
+                ||(e->right.num == 0 && e->op == EXPR_ADD)
+                ||(e->right.num == 0 && e->op == EXPR_SUB)
+                ||(e->right.num == -1 && e->op == EXPR_AND)
+                ||(e->right.num == 0 && e->op == EXPR_OR)
+                ||(e->right.num == 0 && e->op == EXPR_SHL)
+                ||(e->right.num == 0 && e->op == EXPR_SHR)))
+    {
+       e->op = EXPR_IDENT;
+       e->rtype = e->ltype;
+       memcpy (&e->right, &e->left, sizeof (ExprItem));
+       simplified = 1;
+    }
+
+    return simplified;
+}
diff --git a/libyasm/expr.h b/libyasm/expr.h
new file mode 100644 (file)
index 0000000..18d6eee
--- /dev/null
@@ -0,0 +1,72 @@
+/* $Id: expr.h,v 1.1 2001/07/05 06:28:54 mu Exp $
+ * Expression handling header file
+ *
+ *  Copyright (C) 2001  Michael Urman
+ *
+ *  This file is part of YASM.
+ *
+ *  YASM 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  YASM 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, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef _EXPR_H_
+#define _EXPR_H_
+
+typedef enum {
+    EXPR_ADD,
+    EXPR_SUB,
+    EXPR_MUL,
+    EXPR_DIV,
+    EXPR_MOD,
+    EXPR_NEG,
+    EXPR_NOT,
+    EXPR_OR,
+    EXPR_AND,
+    EXPR_XOR,
+    EXPR_SHL,
+    EXPR_SHR,
+    EXPR_LOR,
+    EXPR_LAND,
+    EXPR_LNOT,
+    EXPR_LT,
+    EXPR_GT,
+    EXPR_EQ,
+    EXPR_LE,
+    EXPR_GE,
+    EXPR_NE,
+    EXPR_IDENT     /* if right is IDENT, then the entire expr is just a num */
+} ExprOp;
+
+typedef enum {
+    EXPR_NONE,     /* for left side of a NOT, NEG, etc. */
+    EXPR_NUM,
+    EXPR_EXPR,
+    EXPR_SYM
+} ExprType;
+
+typedef union expritem_u {
+    struct symrec_s *sym;
+    struct expr_s *expr;
+    int num;
+} ExprItem;
+
+typedef struct expr_s {
+    ExprType ltype, rtype;
+    ExprItem left, right;
+    ExprOp op;
+} expr;
+
+expr *expr_new (ExprType, ExprItem, ExprOp, ExprType, ExprItem);
+int expr_simplify (expr *);
+
+#endif
diff --git a/modules/arch/x86/expr.c b/modules/arch/x86/expr.c
new file mode 100644 (file)
index 0000000..e621095
--- /dev/null
@@ -0,0 +1,191 @@
+/* $Id: expr.c,v 1.1 2001/07/05 06:28:54 mu Exp $
+ * Expression handling
+ *
+ *  Copyright (C) 2001  Michael Urman
+ *
+ *  This file is part of YASM.
+ *
+ *  YASM 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  YASM 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, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <stdlib.h>
+#include <string.h>
+#include "expr.h"
+#include "symrec.h"
+#include "globals.h"
+#include "errwarn.h"
+
+/* allocate a new expression node, with children as defined.
+ * If it's a unary operator, put the element on the right */
+expr *expr_new (ExprType ltype,
+               ExprItem left,
+               ExprOp op,
+               ExprType rtype,
+               ExprItem right)
+{
+    expr *ptr;
+    ptr = malloc (sizeof (expr));
+    if (ptr == NULL) Fatal (FATAL_NOMEM);
+    ptr->ltype = ltype;
+    ptr->op = op;
+    ptr->rtype = rtype;
+    switch (ltype)
+    {
+       case EXPR_NUM:
+       case EXPR_SYM:
+       case EXPR_EXPR:
+           memcpy (&ptr->left, &left, sizeof (ExprItem));
+           break;
+       case EXPR_NONE: break;
+    }
+    switch (rtype)
+    {
+       case EXPR_NUM:
+       case EXPR_SYM:
+       case EXPR_EXPR:
+           memcpy (&ptr->right, &right, sizeof (ExprItem));
+           break;
+       case EXPR_NONE:
+           Fatal (FATAL_UNKNOWN); /* TODO: better error? */
+           break;
+    }
+    return ptr;
+}
+
+/* get rid of unnecessary branches if possible.  report. */
+int expr_simplify (expr *e)
+{
+    int simplified = 0;
+
+    /* try to simplify the left side */
+    if (e->ltype == EXPR_EXPR)
+    {
+       /* if the left subexpr isn't an IDENT, recurse simplification */
+       if (e->left.expr->op != EXPR_IDENT)
+           simplified |= expr_simplify (e->left.expr);
+
+       /* if the left subexpr is just an IDENT (or string thereof),
+        * pull it up into the current node */
+       while (e->ltype == EXPR_EXPR && e->left.expr->op == EXPR_IDENT)
+       {
+           ExprItem tmp;
+           e->ltype = e->left.expr->rtype;
+           memcpy (&tmp, &(e->left.expr->right), sizeof (ExprItem));
+           free (e->left.expr);
+           memcpy (&(e->left.num), &tmp, sizeof (ExprItem));
+           simplified = 1;
+       }
+    }
+    else if (e->ltype == EXPR_SYM)
+    {
+       /* if it's a symbol that has a defined value, turn it into a
+        * number */
+       if (e->left.sym->status & SYM_VALUED)
+       {
+           e->ltype = EXPR_NUM;
+           /* don't try to free the symrec here. */
+           e->left.num = e->left.sym->value;
+           simplified = 1;
+       }
+    }
+
+    /* ditto on the right */
+    if (e->rtype == EXPR_EXPR)
+    {
+       if (e->right.expr->op != EXPR_IDENT)
+           simplified |= expr_simplify (e->right.expr);
+
+       while (e->rtype == EXPR_EXPR && e->right.expr->op == EXPR_IDENT)
+       {
+           ExprItem tmp;
+           e->rtype = e->right.expr->rtype;
+           memcpy (&tmp, &(e->right.expr->right), sizeof (ExprItem));
+           free (e->right.expr);
+           memcpy (&(e->right.num), &tmp, sizeof (ExprItem));
+           simplified = 1;
+       }
+    }
+    else if (e->rtype == EXPR_SYM)
+    {
+       if (e->right.sym->status & SYM_VALUED)
+       {
+           e->rtype = EXPR_NUM;
+           /* don't try to free the symrec here. */
+           e->right.num = e->right.sym->value;
+           simplified = 1;
+       }
+    }
+
+    if ((e->ltype == EXPR_NUM || e->ltype == EXPR_NONE)
+       && e->rtype == EXPR_NUM
+       && e->op != EXPR_IDENT)
+    {
+       switch (e->op)
+       {
+           case EXPR_ADD: e->right.num = e->left.num + e->right.num; break;
+           case EXPR_SUB: e->right.num = e->left.num - e->right.num; break;
+           case EXPR_MUL: e->right.num = e->left.num * e->right.num; break;
+           case EXPR_DIV: e->right.num = e->left.num / e->right.num; break;
+           case EXPR_MOD: e->right.num = e->left.num % e->right.num; break;
+           case EXPR_NEG: e->right.num = -(e->right.num); break;
+           case EXPR_NOT: e->right.num = ~(e->right.num); break;
+           case EXPR_OR:  e->right.num = e->left.num | e->right.num; break;
+           case EXPR_AND: e->right.num = e->left.num & e->right.num; break;
+           case EXPR_XOR: e->right.num = e->left.num ^ e->right.num; break;
+           case EXPR_SHL: e->right.num = e->right.num << e->left.num; break;
+           case EXPR_SHR: e->right.num = e->right.num << e->left.num; break;
+           case EXPR_LOR: e->right.num = e->left.num || e->right.num; break;
+           case EXPR_LAND: e->right.num = e->left.num && e->right.num; break;
+           case EXPR_LNOT: e->right.num = !e->right.num; break;
+           case EXPR_EQ: e->right.num = e->right.num == e->left.num; break;
+           case EXPR_LT: e->right.num = e->right.num < e->left.num; break;
+           case EXPR_GT: e->right.num = e->right.num > e->left.num; break;
+           case EXPR_LE: e->right.num = e->right.num <= e->left.num; break;
+           case EXPR_GE: e->right.num = e->right.num >= e->left.num; break;
+           case EXPR_NE: e->right.num = e->right.num != e->left.num; break;
+           case EXPR_IDENT: break;
+       }
+       e->op = EXPR_IDENT;
+       simplified = 1;
+    }
+
+    /* catch simple identities like 0+x, 1*x, etc., for x not a num */
+    else if (e->ltype == EXPR_NUM
+            && ((e->left.num == 1 && e->op == EXPR_MUL)
+                ||(e->left.num == 0 && e->op == EXPR_ADD)
+                ||(e->left.num == -1 && e->op == EXPR_AND)
+                ||(e->left.num == 0 && e->op == EXPR_OR)))
+    {
+       e->op = EXPR_IDENT;
+       simplified = 1;
+    }
+    /* and the corresponding x+|-0, x*&/1 */
+    else if (e->rtype == EXPR_NUM
+            && ((e->right.num == 1 && e->op == EXPR_MUL)
+                ||(e->right.num == 1 && e->op == EXPR_DIV)
+                ||(e->right.num == 0 && e->op == EXPR_ADD)
+                ||(e->right.num == 0 && e->op == EXPR_SUB)
+                ||(e->right.num == -1 && e->op == EXPR_AND)
+                ||(e->right.num == 0 && e->op == EXPR_OR)
+                ||(e->right.num == 0 && e->op == EXPR_SHL)
+                ||(e->right.num == 0 && e->op == EXPR_SHR)))
+    {
+       e->op = EXPR_IDENT;
+       e->rtype = e->ltype;
+       memcpy (&e->right, &e->left, sizeof (ExprItem));
+       simplified = 1;
+    }
+
+    return simplified;
+}
diff --git a/modules/arch/x86/x86expr.c b/modules/arch/x86/x86expr.c
new file mode 100644 (file)
index 0000000..f653822
--- /dev/null
@@ -0,0 +1,191 @@
+/* $Id: x86expr.c,v 1.1 2001/07/05 06:28:54 mu Exp $
+ * Expression handling
+ *
+ *  Copyright (C) 2001  Michael Urman
+ *
+ *  This file is part of YASM.
+ *
+ *  YASM 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  YASM 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, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <stdlib.h>
+#include <string.h>
+#include "expr.h"
+#include "symrec.h"
+#include "globals.h"
+#include "errwarn.h"
+
+/* allocate a new expression node, with children as defined.
+ * If it's a unary operator, put the element on the right */
+expr *expr_new (ExprType ltype,
+               ExprItem left,
+               ExprOp op,
+               ExprType rtype,
+               ExprItem right)
+{
+    expr *ptr;
+    ptr = malloc (sizeof (expr));
+    if (ptr == NULL) Fatal (FATAL_NOMEM);
+    ptr->ltype = ltype;
+    ptr->op = op;
+    ptr->rtype = rtype;
+    switch (ltype)
+    {
+       case EXPR_NUM:
+       case EXPR_SYM:
+       case EXPR_EXPR:
+           memcpy (&ptr->left, &left, sizeof (ExprItem));
+           break;
+       case EXPR_NONE: break;
+    }
+    switch (rtype)
+    {
+       case EXPR_NUM:
+       case EXPR_SYM:
+       case EXPR_EXPR:
+           memcpy (&ptr->right, &right, sizeof (ExprItem));
+           break;
+       case EXPR_NONE:
+           Fatal (FATAL_UNKNOWN); /* TODO: better error? */
+           break;
+    }
+    return ptr;
+}
+
+/* get rid of unnecessary branches if possible.  report. */
+int expr_simplify (expr *e)
+{
+    int simplified = 0;
+
+    /* try to simplify the left side */
+    if (e->ltype == EXPR_EXPR)
+    {
+       /* if the left subexpr isn't an IDENT, recurse simplification */
+       if (e->left.expr->op != EXPR_IDENT)
+           simplified |= expr_simplify (e->left.expr);
+
+       /* if the left subexpr is just an IDENT (or string thereof),
+        * pull it up into the current node */
+       while (e->ltype == EXPR_EXPR && e->left.expr->op == EXPR_IDENT)
+       {
+           ExprItem tmp;
+           e->ltype = e->left.expr->rtype;
+           memcpy (&tmp, &(e->left.expr->right), sizeof (ExprItem));
+           free (e->left.expr);
+           memcpy (&(e->left.num), &tmp, sizeof (ExprItem));
+           simplified = 1;
+       }
+    }
+    else if (e->ltype == EXPR_SYM)
+    {
+       /* if it's a symbol that has a defined value, turn it into a
+        * number */
+       if (e->left.sym->status & SYM_VALUED)
+       {
+           e->ltype = EXPR_NUM;
+           /* don't try to free the symrec here. */
+           e->left.num = e->left.sym->value;
+           simplified = 1;
+       }
+    }
+
+    /* ditto on the right */
+    if (e->rtype == EXPR_EXPR)
+    {
+       if (e->right.expr->op != EXPR_IDENT)
+           simplified |= expr_simplify (e->right.expr);
+
+       while (e->rtype == EXPR_EXPR && e->right.expr->op == EXPR_IDENT)
+       {
+           ExprItem tmp;
+           e->rtype = e->right.expr->rtype;
+           memcpy (&tmp, &(e->right.expr->right), sizeof (ExprItem));
+           free (e->right.expr);
+           memcpy (&(e->right.num), &tmp, sizeof (ExprItem));
+           simplified = 1;
+       }
+    }
+    else if (e->rtype == EXPR_SYM)
+    {
+       if (e->right.sym->status & SYM_VALUED)
+       {
+           e->rtype = EXPR_NUM;
+           /* don't try to free the symrec here. */
+           e->right.num = e->right.sym->value;
+           simplified = 1;
+       }
+    }
+
+    if ((e->ltype == EXPR_NUM || e->ltype == EXPR_NONE)
+       && e->rtype == EXPR_NUM
+       && e->op != EXPR_IDENT)
+    {
+       switch (e->op)
+       {
+           case EXPR_ADD: e->right.num = e->left.num + e->right.num; break;
+           case EXPR_SUB: e->right.num = e->left.num - e->right.num; break;
+           case EXPR_MUL: e->right.num = e->left.num * e->right.num; break;
+           case EXPR_DIV: e->right.num = e->left.num / e->right.num; break;
+           case EXPR_MOD: e->right.num = e->left.num % e->right.num; break;
+           case EXPR_NEG: e->right.num = -(e->right.num); break;
+           case EXPR_NOT: e->right.num = ~(e->right.num); break;
+           case EXPR_OR:  e->right.num = e->left.num | e->right.num; break;
+           case EXPR_AND: e->right.num = e->left.num & e->right.num; break;
+           case EXPR_XOR: e->right.num = e->left.num ^ e->right.num; break;
+           case EXPR_SHL: e->right.num = e->right.num << e->left.num; break;
+           case EXPR_SHR: e->right.num = e->right.num << e->left.num; break;
+           case EXPR_LOR: e->right.num = e->left.num || e->right.num; break;
+           case EXPR_LAND: e->right.num = e->left.num && e->right.num; break;
+           case EXPR_LNOT: e->right.num = !e->right.num; break;
+           case EXPR_EQ: e->right.num = e->right.num == e->left.num; break;
+           case EXPR_LT: e->right.num = e->right.num < e->left.num; break;
+           case EXPR_GT: e->right.num = e->right.num > e->left.num; break;
+           case EXPR_LE: e->right.num = e->right.num <= e->left.num; break;
+           case EXPR_GE: e->right.num = e->right.num >= e->left.num; break;
+           case EXPR_NE: e->right.num = e->right.num != e->left.num; break;
+           case EXPR_IDENT: break;
+       }
+       e->op = EXPR_IDENT;
+       simplified = 1;
+    }
+
+    /* catch simple identities like 0+x, 1*x, etc., for x not a num */
+    else if (e->ltype == EXPR_NUM
+            && ((e->left.num == 1 && e->op == EXPR_MUL)
+                ||(e->left.num == 0 && e->op == EXPR_ADD)
+                ||(e->left.num == -1 && e->op == EXPR_AND)
+                ||(e->left.num == 0 && e->op == EXPR_OR)))
+    {
+       e->op = EXPR_IDENT;
+       simplified = 1;
+    }
+    /* and the corresponding x+|-0, x*&/1 */
+    else if (e->rtype == EXPR_NUM
+            && ((e->right.num == 1 && e->op == EXPR_MUL)
+                ||(e->right.num == 1 && e->op == EXPR_DIV)
+                ||(e->right.num == 0 && e->op == EXPR_ADD)
+                ||(e->right.num == 0 && e->op == EXPR_SUB)
+                ||(e->right.num == -1 && e->op == EXPR_AND)
+                ||(e->right.num == 0 && e->op == EXPR_OR)
+                ||(e->right.num == 0 && e->op == EXPR_SHL)
+                ||(e->right.num == 0 && e->op == EXPR_SHR)))
+    {
+       e->op = EXPR_IDENT;
+       e->rtype = e->ltype;
+       memcpy (&e->right, &e->left, sizeof (ExprItem));
+       simplified = 1;
+    }
+
+    return simplified;
+}
index 78d7f25356c34e3730560f7c28da274aa5cc3b0d..80eacbb7299af0d8854d54b51ca904677501c838 100644 (file)
@@ -5,6 +5,7 @@ yasm_SOURCES = \
        token.l                 \
        bytecode.c              \
        errwarn.c               \
+       expr.c                  \
        main.c                  \
        symrec.c
 
diff --git a/src/arch/x86/expr.c b/src/arch/x86/expr.c
new file mode 100644 (file)
index 0000000..e621095
--- /dev/null
@@ -0,0 +1,191 @@
+/* $Id: expr.c,v 1.1 2001/07/05 06:28:54 mu Exp $
+ * Expression handling
+ *
+ *  Copyright (C) 2001  Michael Urman
+ *
+ *  This file is part of YASM.
+ *
+ *  YASM 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  YASM 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, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <stdlib.h>
+#include <string.h>
+#include "expr.h"
+#include "symrec.h"
+#include "globals.h"
+#include "errwarn.h"
+
+/* allocate a new expression node, with children as defined.
+ * If it's a unary operator, put the element on the right */
+expr *expr_new (ExprType ltype,
+               ExprItem left,
+               ExprOp op,
+               ExprType rtype,
+               ExprItem right)
+{
+    expr *ptr;
+    ptr = malloc (sizeof (expr));
+    if (ptr == NULL) Fatal (FATAL_NOMEM);
+    ptr->ltype = ltype;
+    ptr->op = op;
+    ptr->rtype = rtype;
+    switch (ltype)
+    {
+       case EXPR_NUM:
+       case EXPR_SYM:
+       case EXPR_EXPR:
+           memcpy (&ptr->left, &left, sizeof (ExprItem));
+           break;
+       case EXPR_NONE: break;
+    }
+    switch (rtype)
+    {
+       case EXPR_NUM:
+       case EXPR_SYM:
+       case EXPR_EXPR:
+           memcpy (&ptr->right, &right, sizeof (ExprItem));
+           break;
+       case EXPR_NONE:
+           Fatal (FATAL_UNKNOWN); /* TODO: better error? */
+           break;
+    }
+    return ptr;
+}
+
+/* get rid of unnecessary branches if possible.  report. */
+int expr_simplify (expr *e)
+{
+    int simplified = 0;
+
+    /* try to simplify the left side */
+    if (e->ltype == EXPR_EXPR)
+    {
+       /* if the left subexpr isn't an IDENT, recurse simplification */
+       if (e->left.expr->op != EXPR_IDENT)
+           simplified |= expr_simplify (e->left.expr);
+
+       /* if the left subexpr is just an IDENT (or string thereof),
+        * pull it up into the current node */
+       while (e->ltype == EXPR_EXPR && e->left.expr->op == EXPR_IDENT)
+       {
+           ExprItem tmp;
+           e->ltype = e->left.expr->rtype;
+           memcpy (&tmp, &(e->left.expr->right), sizeof (ExprItem));
+           free (e->left.expr);
+           memcpy (&(e->left.num), &tmp, sizeof (ExprItem));
+           simplified = 1;
+       }
+    }
+    else if (e->ltype == EXPR_SYM)
+    {
+       /* if it's a symbol that has a defined value, turn it into a
+        * number */
+       if (e->left.sym->status & SYM_VALUED)
+       {
+           e->ltype = EXPR_NUM;
+           /* don't try to free the symrec here. */
+           e->left.num = e->left.sym->value;
+           simplified = 1;
+       }
+    }
+
+    /* ditto on the right */
+    if (e->rtype == EXPR_EXPR)
+    {
+       if (e->right.expr->op != EXPR_IDENT)
+           simplified |= expr_simplify (e->right.expr);
+
+       while (e->rtype == EXPR_EXPR && e->right.expr->op == EXPR_IDENT)
+       {
+           ExprItem tmp;
+           e->rtype = e->right.expr->rtype;
+           memcpy (&tmp, &(e->right.expr->right), sizeof (ExprItem));
+           free (e->right.expr);
+           memcpy (&(e->right.num), &tmp, sizeof (ExprItem));
+           simplified = 1;
+       }
+    }
+    else if (e->rtype == EXPR_SYM)
+    {
+       if (e->right.sym->status & SYM_VALUED)
+       {
+           e->rtype = EXPR_NUM;
+           /* don't try to free the symrec here. */
+           e->right.num = e->right.sym->value;
+           simplified = 1;
+       }
+    }
+
+    if ((e->ltype == EXPR_NUM || e->ltype == EXPR_NONE)
+       && e->rtype == EXPR_NUM
+       && e->op != EXPR_IDENT)
+    {
+       switch (e->op)
+       {
+           case EXPR_ADD: e->right.num = e->left.num + e->right.num; break;
+           case EXPR_SUB: e->right.num = e->left.num - e->right.num; break;
+           case EXPR_MUL: e->right.num = e->left.num * e->right.num; break;
+           case EXPR_DIV: e->right.num = e->left.num / e->right.num; break;
+           case EXPR_MOD: e->right.num = e->left.num % e->right.num; break;
+           case EXPR_NEG: e->right.num = -(e->right.num); break;
+           case EXPR_NOT: e->right.num = ~(e->right.num); break;
+           case EXPR_OR:  e->right.num = e->left.num | e->right.num; break;
+           case EXPR_AND: e->right.num = e->left.num & e->right.num; break;
+           case EXPR_XOR: e->right.num = e->left.num ^ e->right.num; break;
+           case EXPR_SHL: e->right.num = e->right.num << e->left.num; break;
+           case EXPR_SHR: e->right.num = e->right.num << e->left.num; break;
+           case EXPR_LOR: e->right.num = e->left.num || e->right.num; break;
+           case EXPR_LAND: e->right.num = e->left.num && e->right.num; break;
+           case EXPR_LNOT: e->right.num = !e->right.num; break;
+           case EXPR_EQ: e->right.num = e->right.num == e->left.num; break;
+           case EXPR_LT: e->right.num = e->right.num < e->left.num; break;
+           case EXPR_GT: e->right.num = e->right.num > e->left.num; break;
+           case EXPR_LE: e->right.num = e->right.num <= e->left.num; break;
+           case EXPR_GE: e->right.num = e->right.num >= e->left.num; break;
+           case EXPR_NE: e->right.num = e->right.num != e->left.num; break;
+           case EXPR_IDENT: break;
+       }
+       e->op = EXPR_IDENT;
+       simplified = 1;
+    }
+
+    /* catch simple identities like 0+x, 1*x, etc., for x not a num */
+    else if (e->ltype == EXPR_NUM
+            && ((e->left.num == 1 && e->op == EXPR_MUL)
+                ||(e->left.num == 0 && e->op == EXPR_ADD)
+                ||(e->left.num == -1 && e->op == EXPR_AND)
+                ||(e->left.num == 0 && e->op == EXPR_OR)))
+    {
+       e->op = EXPR_IDENT;
+       simplified = 1;
+    }
+    /* and the corresponding x+|-0, x*&/1 */
+    else if (e->rtype == EXPR_NUM
+            && ((e->right.num == 1 && e->op == EXPR_MUL)
+                ||(e->right.num == 1 && e->op == EXPR_DIV)
+                ||(e->right.num == 0 && e->op == EXPR_ADD)
+                ||(e->right.num == 0 && e->op == EXPR_SUB)
+                ||(e->right.num == -1 && e->op == EXPR_AND)
+                ||(e->right.num == 0 && e->op == EXPR_OR)
+                ||(e->right.num == 0 && e->op == EXPR_SHL)
+                ||(e->right.num == 0 && e->op == EXPR_SHR)))
+    {
+       e->op = EXPR_IDENT;
+       e->rtype = e->ltype;
+       memcpy (&e->right, &e->left, sizeof (ExprItem));
+       simplified = 1;
+    }
+
+    return simplified;
+}
diff --git a/src/arch/x86/x86expr.c b/src/arch/x86/x86expr.c
new file mode 100644 (file)
index 0000000..f653822
--- /dev/null
@@ -0,0 +1,191 @@
+/* $Id: x86expr.c,v 1.1 2001/07/05 06:28:54 mu Exp $
+ * Expression handling
+ *
+ *  Copyright (C) 2001  Michael Urman
+ *
+ *  This file is part of YASM.
+ *
+ *  YASM 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  YASM 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, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <stdlib.h>
+#include <string.h>
+#include "expr.h"
+#include "symrec.h"
+#include "globals.h"
+#include "errwarn.h"
+
+/* allocate a new expression node, with children as defined.
+ * If it's a unary operator, put the element on the right */
+expr *expr_new (ExprType ltype,
+               ExprItem left,
+               ExprOp op,
+               ExprType rtype,
+               ExprItem right)
+{
+    expr *ptr;
+    ptr = malloc (sizeof (expr));
+    if (ptr == NULL) Fatal (FATAL_NOMEM);
+    ptr->ltype = ltype;
+    ptr->op = op;
+    ptr->rtype = rtype;
+    switch (ltype)
+    {
+       case EXPR_NUM:
+       case EXPR_SYM:
+       case EXPR_EXPR:
+           memcpy (&ptr->left, &left, sizeof (ExprItem));
+           break;
+       case EXPR_NONE: break;
+    }
+    switch (rtype)
+    {
+       case EXPR_NUM:
+       case EXPR_SYM:
+       case EXPR_EXPR:
+           memcpy (&ptr->right, &right, sizeof (ExprItem));
+           break;
+       case EXPR_NONE:
+           Fatal (FATAL_UNKNOWN); /* TODO: better error? */
+           break;
+    }
+    return ptr;
+}
+
+/* get rid of unnecessary branches if possible.  report. */
+int expr_simplify (expr *e)
+{
+    int simplified = 0;
+
+    /* try to simplify the left side */
+    if (e->ltype == EXPR_EXPR)
+    {
+       /* if the left subexpr isn't an IDENT, recurse simplification */
+       if (e->left.expr->op != EXPR_IDENT)
+           simplified |= expr_simplify (e->left.expr);
+
+       /* if the left subexpr is just an IDENT (or string thereof),
+        * pull it up into the current node */
+       while (e->ltype == EXPR_EXPR && e->left.expr->op == EXPR_IDENT)
+       {
+           ExprItem tmp;
+           e->ltype = e->left.expr->rtype;
+           memcpy (&tmp, &(e->left.expr->right), sizeof (ExprItem));
+           free (e->left.expr);
+           memcpy (&(e->left.num), &tmp, sizeof (ExprItem));
+           simplified = 1;
+       }
+    }
+    else if (e->ltype == EXPR_SYM)
+    {
+       /* if it's a symbol that has a defined value, turn it into a
+        * number */
+       if (e->left.sym->status & SYM_VALUED)
+       {
+           e->ltype = EXPR_NUM;
+           /* don't try to free the symrec here. */
+           e->left.num = e->left.sym->value;
+           simplified = 1;
+       }
+    }
+
+    /* ditto on the right */
+    if (e->rtype == EXPR_EXPR)
+    {
+       if (e->right.expr->op != EXPR_IDENT)
+           simplified |= expr_simplify (e->right.expr);
+
+       while (e->rtype == EXPR_EXPR && e->right.expr->op == EXPR_IDENT)
+       {
+           ExprItem tmp;
+           e->rtype = e->right.expr->rtype;
+           memcpy (&tmp, &(e->right.expr->right), sizeof (ExprItem));
+           free (e->right.expr);
+           memcpy (&(e->right.num), &tmp, sizeof (ExprItem));
+           simplified = 1;
+       }
+    }
+    else if (e->rtype == EXPR_SYM)
+    {
+       if (e->right.sym->status & SYM_VALUED)
+       {
+           e->rtype = EXPR_NUM;
+           /* don't try to free the symrec here. */
+           e->right.num = e->right.sym->value;
+           simplified = 1;
+       }
+    }
+
+    if ((e->ltype == EXPR_NUM || e->ltype == EXPR_NONE)
+       && e->rtype == EXPR_NUM
+       && e->op != EXPR_IDENT)
+    {
+       switch (e->op)
+       {
+           case EXPR_ADD: e->right.num = e->left.num + e->right.num; break;
+           case EXPR_SUB: e->right.num = e->left.num - e->right.num; break;
+           case EXPR_MUL: e->right.num = e->left.num * e->right.num; break;
+           case EXPR_DIV: e->right.num = e->left.num / e->right.num; break;
+           case EXPR_MOD: e->right.num = e->left.num % e->right.num; break;
+           case EXPR_NEG: e->right.num = -(e->right.num); break;
+           case EXPR_NOT: e->right.num = ~(e->right.num); break;
+           case EXPR_OR:  e->right.num = e->left.num | e->right.num; break;
+           case EXPR_AND: e->right.num = e->left.num & e->right.num; break;
+           case EXPR_XOR: e->right.num = e->left.num ^ e->right.num; break;
+           case EXPR_SHL: e->right.num = e->right.num << e->left.num; break;
+           case EXPR_SHR: e->right.num = e->right.num << e->left.num; break;
+           case EXPR_LOR: e->right.num = e->left.num || e->right.num; break;
+           case EXPR_LAND: e->right.num = e->left.num && e->right.num; break;
+           case EXPR_LNOT: e->right.num = !e->right.num; break;
+           case EXPR_EQ: e->right.num = e->right.num == e->left.num; break;
+           case EXPR_LT: e->right.num = e->right.num < e->left.num; break;
+           case EXPR_GT: e->right.num = e->right.num > e->left.num; break;
+           case EXPR_LE: e->right.num = e->right.num <= e->left.num; break;
+           case EXPR_GE: e->right.num = e->right.num >= e->left.num; break;
+           case EXPR_NE: e->right.num = e->right.num != e->left.num; break;
+           case EXPR_IDENT: break;
+       }
+       e->op = EXPR_IDENT;
+       simplified = 1;
+    }
+
+    /* catch simple identities like 0+x, 1*x, etc., for x not a num */
+    else if (e->ltype == EXPR_NUM
+            && ((e->left.num == 1 && e->op == EXPR_MUL)
+                ||(e->left.num == 0 && e->op == EXPR_ADD)
+                ||(e->left.num == -1 && e->op == EXPR_AND)
+                ||(e->left.num == 0 && e->op == EXPR_OR)))
+    {
+       e->op = EXPR_IDENT;
+       simplified = 1;
+    }
+    /* and the corresponding x+|-0, x*&/1 */
+    else if (e->rtype == EXPR_NUM
+            && ((e->right.num == 1 && e->op == EXPR_MUL)
+                ||(e->right.num == 1 && e->op == EXPR_DIV)
+                ||(e->right.num == 0 && e->op == EXPR_ADD)
+                ||(e->right.num == 0 && e->op == EXPR_SUB)
+                ||(e->right.num == -1 && e->op == EXPR_AND)
+                ||(e->right.num == 0 && e->op == EXPR_OR)
+                ||(e->right.num == 0 && e->op == EXPR_SHL)
+                ||(e->right.num == 0 && e->op == EXPR_SHR)))
+    {
+       e->op = EXPR_IDENT;
+       e->rtype = e->ltype;
+       memcpy (&e->right, &e->left, sizeof (ExprItem));
+       simplified = 1;
+    }
+
+    return simplified;
+}
diff --git a/src/expr.c b/src/expr.c
new file mode 100644 (file)
index 0000000..e621095
--- /dev/null
@@ -0,0 +1,191 @@
+/* $Id: expr.c,v 1.1 2001/07/05 06:28:54 mu Exp $
+ * Expression handling
+ *
+ *  Copyright (C) 2001  Michael Urman
+ *
+ *  This file is part of YASM.
+ *
+ *  YASM 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  YASM 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, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <stdlib.h>
+#include <string.h>
+#include "expr.h"
+#include "symrec.h"
+#include "globals.h"
+#include "errwarn.h"
+
+/* allocate a new expression node, with children as defined.
+ * If it's a unary operator, put the element on the right */
+expr *expr_new (ExprType ltype,
+               ExprItem left,
+               ExprOp op,
+               ExprType rtype,
+               ExprItem right)
+{
+    expr *ptr;
+    ptr = malloc (sizeof (expr));
+    if (ptr == NULL) Fatal (FATAL_NOMEM);
+    ptr->ltype = ltype;
+    ptr->op = op;
+    ptr->rtype = rtype;
+    switch (ltype)
+    {
+       case EXPR_NUM:
+       case EXPR_SYM:
+       case EXPR_EXPR:
+           memcpy (&ptr->left, &left, sizeof (ExprItem));
+           break;
+       case EXPR_NONE: break;
+    }
+    switch (rtype)
+    {
+       case EXPR_NUM:
+       case EXPR_SYM:
+       case EXPR_EXPR:
+           memcpy (&ptr->right, &right, sizeof (ExprItem));
+           break;
+       case EXPR_NONE:
+           Fatal (FATAL_UNKNOWN); /* TODO: better error? */
+           break;
+    }
+    return ptr;
+}
+
+/* get rid of unnecessary branches if possible.  report. */
+int expr_simplify (expr *e)
+{
+    int simplified = 0;
+
+    /* try to simplify the left side */
+    if (e->ltype == EXPR_EXPR)
+    {
+       /* if the left subexpr isn't an IDENT, recurse simplification */
+       if (e->left.expr->op != EXPR_IDENT)
+           simplified |= expr_simplify (e->left.expr);
+
+       /* if the left subexpr is just an IDENT (or string thereof),
+        * pull it up into the current node */
+       while (e->ltype == EXPR_EXPR && e->left.expr->op == EXPR_IDENT)
+       {
+           ExprItem tmp;
+           e->ltype = e->left.expr->rtype;
+           memcpy (&tmp, &(e->left.expr->right), sizeof (ExprItem));
+           free (e->left.expr);
+           memcpy (&(e->left.num), &tmp, sizeof (ExprItem));
+           simplified = 1;
+       }
+    }
+    else if (e->ltype == EXPR_SYM)
+    {
+       /* if it's a symbol that has a defined value, turn it into a
+        * number */
+       if (e->left.sym->status & SYM_VALUED)
+       {
+           e->ltype = EXPR_NUM;
+           /* don't try to free the symrec here. */
+           e->left.num = e->left.sym->value;
+           simplified = 1;
+       }
+    }
+
+    /* ditto on the right */
+    if (e->rtype == EXPR_EXPR)
+    {
+       if (e->right.expr->op != EXPR_IDENT)
+           simplified |= expr_simplify (e->right.expr);
+
+       while (e->rtype == EXPR_EXPR && e->right.expr->op == EXPR_IDENT)
+       {
+           ExprItem tmp;
+           e->rtype = e->right.expr->rtype;
+           memcpy (&tmp, &(e->right.expr->right), sizeof (ExprItem));
+           free (e->right.expr);
+           memcpy (&(e->right.num), &tmp, sizeof (ExprItem));
+           simplified = 1;
+       }
+    }
+    else if (e->rtype == EXPR_SYM)
+    {
+       if (e->right.sym->status & SYM_VALUED)
+       {
+           e->rtype = EXPR_NUM;
+           /* don't try to free the symrec here. */
+           e->right.num = e->right.sym->value;
+           simplified = 1;
+       }
+    }
+
+    if ((e->ltype == EXPR_NUM || e->ltype == EXPR_NONE)
+       && e->rtype == EXPR_NUM
+       && e->op != EXPR_IDENT)
+    {
+       switch (e->op)
+       {
+           case EXPR_ADD: e->right.num = e->left.num + e->right.num; break;
+           case EXPR_SUB: e->right.num = e->left.num - e->right.num; break;
+           case EXPR_MUL: e->right.num = e->left.num * e->right.num; break;
+           case EXPR_DIV: e->right.num = e->left.num / e->right.num; break;
+           case EXPR_MOD: e->right.num = e->left.num % e->right.num; break;
+           case EXPR_NEG: e->right.num = -(e->right.num); break;
+           case EXPR_NOT: e->right.num = ~(e->right.num); break;
+           case EXPR_OR:  e->right.num = e->left.num | e->right.num; break;
+           case EXPR_AND: e->right.num = e->left.num & e->right.num; break;
+           case EXPR_XOR: e->right.num = e->left.num ^ e->right.num; break;
+           case EXPR_SHL: e->right.num = e->right.num << e->left.num; break;
+           case EXPR_SHR: e->right.num = e->right.num << e->left.num; break;
+           case EXPR_LOR: e->right.num = e->left.num || e->right.num; break;
+           case EXPR_LAND: e->right.num = e->left.num && e->right.num; break;
+           case EXPR_LNOT: e->right.num = !e->right.num; break;
+           case EXPR_EQ: e->right.num = e->right.num == e->left.num; break;
+           case EXPR_LT: e->right.num = e->right.num < e->left.num; break;
+           case EXPR_GT: e->right.num = e->right.num > e->left.num; break;
+           case EXPR_LE: e->right.num = e->right.num <= e->left.num; break;
+           case EXPR_GE: e->right.num = e->right.num >= e->left.num; break;
+           case EXPR_NE: e->right.num = e->right.num != e->left.num; break;
+           case EXPR_IDENT: break;
+       }
+       e->op = EXPR_IDENT;
+       simplified = 1;
+    }
+
+    /* catch simple identities like 0+x, 1*x, etc., for x not a num */
+    else if (e->ltype == EXPR_NUM
+            && ((e->left.num == 1 && e->op == EXPR_MUL)
+                ||(e->left.num == 0 && e->op == EXPR_ADD)
+                ||(e->left.num == -1 && e->op == EXPR_AND)
+                ||(e->left.num == 0 && e->op == EXPR_OR)))
+    {
+       e->op = EXPR_IDENT;
+       simplified = 1;
+    }
+    /* and the corresponding x+|-0, x*&/1 */
+    else if (e->rtype == EXPR_NUM
+            && ((e->right.num == 1 && e->op == EXPR_MUL)
+                ||(e->right.num == 1 && e->op == EXPR_DIV)
+                ||(e->right.num == 0 && e->op == EXPR_ADD)
+                ||(e->right.num == 0 && e->op == EXPR_SUB)
+                ||(e->right.num == -1 && e->op == EXPR_AND)
+                ||(e->right.num == 0 && e->op == EXPR_OR)
+                ||(e->right.num == 0 && e->op == EXPR_SHL)
+                ||(e->right.num == 0 && e->op == EXPR_SHR)))
+    {
+       e->op = EXPR_IDENT;
+       e->rtype = e->ltype;
+       memcpy (&e->right, &e->left, sizeof (ExprItem));
+       simplified = 1;
+    }
+
+    return simplified;
+}
diff --git a/src/expr.h b/src/expr.h
new file mode 100644 (file)
index 0000000..18d6eee
--- /dev/null
@@ -0,0 +1,72 @@
+/* $Id: expr.h,v 1.1 2001/07/05 06:28:54 mu Exp $
+ * Expression handling header file
+ *
+ *  Copyright (C) 2001  Michael Urman
+ *
+ *  This file is part of YASM.
+ *
+ *  YASM 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  YASM 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, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef _EXPR_H_
+#define _EXPR_H_
+
+typedef enum {
+    EXPR_ADD,
+    EXPR_SUB,
+    EXPR_MUL,
+    EXPR_DIV,
+    EXPR_MOD,
+    EXPR_NEG,
+    EXPR_NOT,
+    EXPR_OR,
+    EXPR_AND,
+    EXPR_XOR,
+    EXPR_SHL,
+    EXPR_SHR,
+    EXPR_LOR,
+    EXPR_LAND,
+    EXPR_LNOT,
+    EXPR_LT,
+    EXPR_GT,
+    EXPR_EQ,
+    EXPR_LE,
+    EXPR_GE,
+    EXPR_NE,
+    EXPR_IDENT     /* if right is IDENT, then the entire expr is just a num */
+} ExprOp;
+
+typedef enum {
+    EXPR_NONE,     /* for left side of a NOT, NEG, etc. */
+    EXPR_NUM,
+    EXPR_EXPR,
+    EXPR_SYM
+} ExprType;
+
+typedef union expritem_u {
+    struct symrec_s *sym;
+    struct expr_s *expr;
+    int num;
+} ExprItem;
+
+typedef struct expr_s {
+    ExprType ltype, rtype;
+    ExprItem left, right;
+    ExprOp op;
+} expr;
+
+expr *expr_new (ExprType, ExprItem, ExprOp, ExprType, ExprItem);
+int expr_simplify (expr *);
+
+#endif