* as/z80/asexpr.c: fixed bug #1829678: Z-80 CP A,<xxx> assembly
[fw/sdcc] / as / z80 / asexpr.c
index 2664550db4d31b42763ae8ef2cb8eaabcf85c05b..f9bda739d79d6c9c3b0b41c1235225cbd78db8ae 100644 (file)
@@ -1,13 +1,20 @@
-/* asexpr.c */
+/* asexpr.c
 
-/*
- * (C) Copyright 1989-1995
- * All Rights Reserved
- *
- * Alan R. Baldwin
- * 721 Berkeley St.
- * Kent, Ohio  44240
- */
+   Copyright (C) 1989-1995 Alan R. Baldwin
+   721 Berkeley St., Kent, Ohio 44240
+
+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 3, 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, see <http://www.gnu.org/licenses/>. */
 
 #include <stdio.h>
 #include <setjmp.h>
 
 #include "asm.h"
 
-/*)Module      asexpr.c
- *
- *     The module asexpr.c contains the routines to evaluate
- *     arithmetic/numerical expressions.  The functions in
- *     asexpr.c perform a recursive evaluation of the arithmetic
- *     expression read from the assembler-source text line.
- *     The expression may include binary/unary operators, brackets,
- *     symbols, labels, and constants in hexadecimal, decimal, octal
- *     and binary.  Arithmetic operations are prioritized and
- *     evaluated by normal arithmetic conventions.
- *
- *     asexpr.c contains the following functions:
- *             VOID    abscheck()
- *             Addr_T  absexpr()
- *             VOID    clrexpr()
- *             int     digit()
- *             VOID    expr()
- *             int     oprio()
- *             VOID    term()
- *
- *     asexpr.c contains no local/static variables
+/*)Module       asexpr.c
+ *
+ *      The module asexpr.c contains the routines to evaluate
+ *      arithmetic/numerical expressions.  The functions in
+ *      asexpr.c perform a recursive evaluation of the arithmetic
+ *      expression read from the assembler-source text line.
+ *      The expression may include binary/unary operators, brackets,
+ *      symbols, labels, and constants in hexadecimal, decimal, octal
+ *      and binary.  Arithmetic operations are prioritized and
+ *      evaluated by normal arithmetic conventions.
+ *
+ *      asexpr.c contains the following functions:
+ *              VOID    abscheck()
+ *              Addr_T  absexpr()
+ *              VOID    clrexpr()
+ *              int     digit()
+ *              VOID    expr()
+ *              int     oprio()
+ *              VOID    term()
+ *
+ *      asexpr.c contains no local/static variables
  */
 
-/*)Function    VOID    expr(esp, n)
- *
- *             expr *  esp             pointer to an expr structure
- *             int     n               a firewall priority; all top
- *                                     level calls (from the user)
- *                                     should be made with n set to 0.
- *
- *     The function expr() evaluates an expression and
- *     stores its value and relocation information into
- *     the expr structure supplied by the user.
- *
- *     local variables:
- *             int     c               current assembler-source
- *                                     text character
- *             int     p               current operator priority
- *             area *  ap              pointer to an area structure
- *             exp     re              internal expr structure
- *
- *     global variables:
- *             char    ctype[]         array of character types, one per
- *                                     ASCII character
- *
- *     functions called:
- *             VOID    abscheck()      asexpr.c
- *             VOID    clrexpr()       asexpr.c
- *             VOID    expr()          asexpr.c
- *             int     getnb()         aslex.c
- *             int     oprio()         asexpr.c
- *             VOID    qerr()          assubr.c
- *             VOID    rerr()          assubr.c
- *             VOID    term()          asexpr.c
- *             VOID    unget()         aslex.c
- *
- *
- *     side effects:
- *             An expression is evaluated modifying the user supplied
- *             expr structure, a sym structure maybe created for an
- *             undefined symbol, and the parse of the expression may
- *             terminate if a 'q' error occurs.
+/*)Function     VOID    expr(esp, n)
+ *
+ *              expr *  esp             pointer to an expr structure
+ *              int     n               a firewall priority; all top
+ *                                      level calls (from the user)
+ *                                      should be made with n set to 0.
+ *
+ *      The function expr() evaluates an expression and
+ *      stores its value and relocation information into
+ *      the expr structure supplied by the user.
+ *
+ *      local variables:
+ *              int     c               current assembler-source
+ *                                      text character
+ *              int     p               current operator priority
+ *              area *  ap              pointer to an area structure
+ *              exp     re              internal expr structure
+ *
+ *      global variables:
+ *              char    ctype[]         array of character types, one per
+ *                                      ASCII character
+ *
+ *      functions called:
+ *              VOID    abscheck()      asexpr.c
+ *              VOID    clrexpr()       asexpr.c
+ *              VOID    expr()          asexpr.c
+ *              int     getnb()         aslex.c
+ *              int     oprio()         asexpr.c
+ *              VOID    qerr()          assubr.c
+ *              VOID    rerr()          assubr.c
+ *              VOID    term()          asexpr.c
+ *              VOID    unget()         aslex.c
+ *
+ *
+ *      side effects:
+ *              An expression is evaluated modifying the user supplied
+ *              expr structure, a sym structure maybe created for an
+ *              undefined symbol, and the parse of the expression may
+ *              terminate if a 'q' error occurs.
  */
 
 VOID
@@ -90,31 +97,31 @@ int n;
 
         term(esp);
         while (ctype[c = getnb()] & BINOP) {
-               /*
-                * Handle binary operators + - * / & | % ^ << >>
-                */
+                /*
+                 * Handle binary operators + - * / & | % ^ << >>
+                 */
                 if ((p = oprio(c)) <= n)
                         break;
                 if ((c == '>' || c == '<') && c != get())
                         qerr();
-               clrexpr(&re);
+                clrexpr(&re);
                 expr(&re, p);
-               esp->e_rlcf |= re.e_rlcf;
+                esp->e_rlcf |= re.e_rlcf;
                 if (c == '+') {
-                       /*
-                        * esp + re, at least one must be absolute
-                        */
+                        /*
+                         * esp + re, at least one must be absolute
+                         */
                         if (esp->e_base.e_ap == NULL) {
-                               /*
-                                * esp is absolute (constant),
-                                * use area from re
-                                */
+                                /*
+                                 * esp is absolute (constant),
+                                 * use area from re
+                                 */
                                 esp->e_base.e_ap = re.e_base.e_ap;
                         } else
                         if (re.e_base.e_ap) {
-                               /*
-                                * re should be absolute (constant)
-                                */
+                                /*
+                                 * re should be absolute (constant)
+                                 */
                                 rerr();
                         }
                         if (esp->e_flag && re.e_flag)
@@ -124,9 +131,9 @@ int n;
                         esp->e_addr += re.e_addr;
                 } else
                 if (c == '-') {
-                       /*
-                        * esp - re
-                        */
+                        /*
+                         * esp - re
+                         */
                         if ((ap = re.e_base.e_ap) != NULL) {
                                 if (esp->e_base.e_ap == ap) {
                                         esp->e_base.e_ap = NULL;
@@ -138,9 +145,9 @@ int n;
                                 rerr();
                         esp->e_addr -= re.e_addr;
                 } else {
-                       /*
-                        * Both operands (esp and re) must be constants
-                        */
+                        /*
+                         * Both operands (esp and re) must be constants
+                         */
                         abscheck(esp);
                         abscheck(&re);
                         switch (c) {
@@ -177,35 +184,35 @@ int n;
                                 esp->e_addr >>= re.e_addr;
                                 break;
 
-                       default:
-                               qerr();
-                               break;
+                        default:
+                                qerr();
+                                break;
                         }
                 }
         }
         unget(c);
 }
 
-/*)Function    Addr_T  absexpr()
+/*)Function     Addr_T  absexpr()
  *
- *     The function absexpr() evaluates an expression, verifies it
- *     is absolute (i.e. not position dependent or relocatable), and
- *     returns its value.
+ *      The function absexpr() evaluates an expression, verifies it
+ *      is absolute (i.e. not position dependent or relocatable), and
+ *      returns its value.
  *
- *     local variables:
- *             expr    e               expr structure
+ *      local variables:
+ *              expr    e               expr structure
  *
- *     global variables:
- *             none
+ *      global variables:
+ *              none
  *
- *     functions called:
- *             VOID    abscheck()      asexpr.c
- *             VOID    clrexpr()       asexpr.c
- *             VOID    expr()          asexpr.c
+ *      functions called:
+ *              VOID    abscheck()      asexpr.c
+ *              VOID    clrexpr()       asexpr.c
+ *              VOID    expr()          asexpr.c
  *
- *     side effects:
- *             If the expression is not absolute then
- *             a 'r' error is reported.
+ *      side effects:
+ *              If the expression is not absolute then
+ *              a 'r' error is reported.
  */
 
 Addr_T
@@ -213,55 +220,55 @@ absexpr()
 {
         struct expr e;
 
-       clrexpr(&e);
-       expr(&e, 0);
-       abscheck(&e);
-       return (e.e_addr);
+        clrexpr(&e);
+        expr(&e, 0);
+        abscheck(&e);
+        return (e.e_addr);
 }
 
-/*)Function    VOID    term(esp)
- *
- *             expr *  esp             pointer to an expr structure
- *
- *     The function term() evaluates a single constant
- *     or symbol value prefaced by any unary operator
- *     ( +, -, ~, ', ", >, or < ).  This routine is also
- *     responsible for setting the relocation type to symbol
- *     based (e.flag != 0) on global references.
- *
- *     local variables:
- *             int     c               current character
- *             char    id[]            symbol name
- *             char *  jp              pointer to assembler-source text
- *             int     n               constant evaluation running sum
- *             int     r               current evaluation radix
- *             sym *   sp              pointer to a sym structure
- *             tsym *  tp              pointer to a tsym structure
- *             int     v               current digit evaluation
- *
- *     global variables:
- *             char    ctype[]         array of character types, one per
- *                                     ASCII character
- *             sym *   symp            pointer to a symbol structure
- *
- *     functions called:
- *             VOID    abscheck()      asexpr.c
- *             int     digit()         asexpr.c
- *             VOID    err()           assubr.c
- *             VOID    expr()          asexpr.c
- *             int     is_abs()        asexpr.c
- *             int     get()           aslex.c
- *             VOID    getid()         aslex.c
- *             int     getmap()        aslex.c
- *             int     getnb()         aslex.c
- *             sym *   lookup()        assym.c
- *             VOID    qerr()          assubr.c
- *             VOID    unget()         aslex.c
- *
- *     side effects:
- *             An arithmetic term is evaluated, a symbol structure
- *             may be created, term evaluation may be terminated
- *             by a 'q' error.
+/*)Function     VOID    term(esp)
+ *
+ *              expr *  esp             pointer to an expr structure
+ *
+ *      The function term() evaluates a single constant
+ *      or symbol value prefaced by any unary operator
+ *      ( +, -, ~, ', ", >, or < ).  This routine is also
+ *      responsible for setting the relocation type to symbol
+ *      based (e.flag != 0) on global references.
+ *
+ *      local variables:
+ *              int     c               current character
+ *              char    id[]            symbol name
+ *              char *  jp              pointer to assembler-source text
+ *              int     n               constant evaluation running sum
+ *              int     r               current evaluation radix
+ *              sym *   sp              pointer to a sym structure
+ *              tsym *  tp              pointer to a tsym structure
+ *              int     v               current digit evaluation
+ *
+ *      global variables:
+ *              char    ctype[]         array of character types, one per
+ *                                      ASCII character
+ *              sym *   symp            pointer to a symbol structure
+ *
+ *      functions called:
+ *              VOID    abscheck()      asexpr.c
+ *              int     digit()         asexpr.c
+ *              VOID    err()           assubr.c
+ *              VOID    expr()          asexpr.c
+ *              int     is_abs()        asexpr.c
+ *              int     get()           aslex.c
+ *              VOID    getid()         aslex.c
+ *              int     getmap()        aslex.c
+ *              int     getnb()         aslex.c
+ *              sym *   lookup()        assym.c
+ *              VOID    qerr()          assubr.c
+ *              VOID    unget()         aslex.c
+ *
+ *      side effects:
+ *              An arithmetic term is evaluated, a symbol structure
+ *              may be created, term evaluation may be terminated
+ *              by a 'q' error.
  */
 
 VOID
@@ -269,23 +276,23 @@ term(esp)
 register struct expr *esp;
 {
         register int c, n;
-        register char *jp;
+        register const char *jp;
         char id[NCPS];
         struct sym  *sp;
         struct tsym *tp;
         int r = 0, v;
 
         c = getnb();
-       /*
-        * Discard the unary '+' at this point and
-        * also any reference to numerical arguments
-        * associated with the '#' prefix.
-        */
+        /*
+         * Discard the unary '+' at this point and
+         * also any reference to numerical arguments
+         * associated with the '#' prefix.
+         */
         while (c == '+' || c == '#') { c = getnb(); }
-       /*
-        * Evaluate all binary operators
-        * by recursively calling expr().
-        */
+        /*
+         * Evaluate all binary operators
+         * by recursively calling expr().
+         */
         if (c == LFTERM) {
                 expr(esp, 0);
                 if (getnb() != RTTERM)
@@ -322,28 +329,28 @@ register struct expr *esp;
         }
         if (c == '>' || c == '<') {
                 expr(esp, 100);
-               if (is_abs (esp)) {
-                       /*
-                        * evaluate msb/lsb directly
-                        */
-                       if (c == '>')
-                               esp->e_addr >>= 8;
-                       esp->e_addr &= 0377;
-                       return;
-               } else {
-                       /*
-                        * let linker perform msb/lsb, lsb is default
-                        */
-                       esp->e_rlcf |= R_BYT2;
-                       if (c == '>')
-                               esp->e_rlcf |= R_MSB;
-                       return;
-               }
+                if (is_abs (esp)) {
+                        /*
+                         * evaluate msb/lsb directly
+                         */
+                        if (c == '>')
+                                esp->e_addr >>= 8;
+                        esp->e_addr &= 0377;
+                        return;
+                } else {
+                        /*
+                         * let linker perform msb/lsb, lsb is default
+                         */
+                        esp->e_rlcf |= R_BYT2;
+                        if (c == '>')
+                                esp->e_rlcf |= R_MSB;
+                        return;
+                }
         }
-       /*
-        * Evaluate digit sequences as local symbols
-        * if followed by a '$' or as constants.
-        */
+        /*
+         * Evaluate digit sequences as local symbols
+         * if followed by a '$' or as constants.
+         */
         if (ctype[c] & DIGIT) {
                 esp->e_mode = S_USER;
                 jp = ip;
@@ -409,57 +416,58 @@ register struct expr *esp;
                 esp->e_addr = n;
                 return;
         }
-       /*
-        * Evaluate '$' sequences as a temporary radix
-        * if followed by a '%', '&', '#', or '$'.
-        */
+        /*
+         * Evaluate '$' sequences as a temporary radix
+         * if followed by a '%', '&', '#', or '$'.
+         */
         if (c == '$') {
                 c = get();
                 if (c == '%' || c == '&' || c == '#' || c == '$') {
-                       switch (c) {
-                               case '%':
-                                       r = 2;
-                                       break;
-                               case '&':
-                                       r = 8;
-                                       break;
-                               case '#':
-                                       r = 10;
-                                       break;
-                               case '$':
-                                       r = 16;                         
-                                       break;
-                               default:
-                                       break;
-                       }
-                       c = get();
-                       n = 0;
-                       while ((v = digit(c, r)) >= 0) {
-                               n = r*n + v;
-                               c = get();
-                       }
-                       unget(c);
-                       esp->e_mode = S_USER;
-                       esp->e_addr = n;
-                       return;
-               }
-               unget(c);
-               c = '$';
+                        switch (c) {
+                                case '%':
+                                        r = 2;
+                                        break;
+                                case '&':
+                                        r = 8;
+                                        break;
+                                case '#':
+                                        r = 10;
+                                        break;
+                                case '$':
+                                        r = 16;
+                                        break;
+                                default:
+                                        break;
+                        }
+                        c = get();
+                        n = 0;
+                        while ((v = digit(c, r)) >= 0) {
+                                n = r*n + v;
+                                c = get();
+                        }
+                        unget(c);
+                        esp->e_mode = S_USER;
+                        esp->e_addr = n;
+                        return;
+                }
+                unget(c);
+                c = '$';
         }
-       /*
-        * Evaluate symbols and labels
-        */
+        /*
+         * Evaluate symbols and labels
+         */
         if (ctype[c] & LETTER) {
                 esp->e_mode = S_USER;
                 getid(id, c);
                 sp = lookup(id);
                 if (sp->s_type == S_NEW) {
-                       if (sp->s_flag&S_GBL) {
-                               esp->e_flag = 1;
-                               esp->e_base.e_sp = sp;
-                               return;
-                       }
-                       err('u');
+                        esp->e_addr = 0;
+                        if (sp->s_flag&S_GBL) {
+                                esp->e_flag = 1;
+                                esp->e_base.e_sp = sp;
+                                return;
+                        }
+                        err('u');
                 } else {
                         esp->e_mode = sp->s_type;
                         esp->e_addr = sp->s_addr;
@@ -467,33 +475,33 @@ register struct expr *esp;
                 }
                 return;
         }
-       /*
-        * Else not a term.
-        */
+        /*
+         * Else not a term.
+         */
         qerr();
 }
 
-/*)Function    int     digit(c, r)
+/*)Function     int     digit(c, r)
  *
- *             int     c               digit character
- *             int     r               current radix
+ *              int     c               digit character
+ *              int     r               current radix
  *
- *     The function digit() returns the value of c
- *     in the current radix r.  If the c value is not
- *     a number of the current radix then a -1 is returned.
+ *      The function digit() returns the value of c
+ *      in the current radix r.  If the c value is not
+ *      a number of the current radix then a -1 is returned.
  *
- *     local variables:
- *             none
+ *      local variables:
+ *              none
  *
- *     global variables:
- *             char    ctype[]         array of character types, one per
- *                                     ASCII character
+ *      global variables:
+ *              char    ctype[]         array of character types, one per
+ *                                      ASCII character
  *
- *     functions called:
- *             none
+ *      functions called:
+ *              none
  *
- *     side effects:
- *             none
+ *      side effects:
+ *              none
  */
 
 int
@@ -524,31 +532,31 @@ register int c, r;
         return (-1);
 }
 
-/*)Function    VOID    abscheck(esp)
+/*)Function     VOID    abscheck(esp)
  *
- *             expr *  esp             pointer to an expr structure
+ *              expr *  esp             pointer to an expr structure
  *
- *     The function abscheck() tests the evaluation of an
- *     expression to verify it is absolute.  If the evaluation
- *     is relocatable then an 'r' error is noted and the expression
- *     made absolute.
+ *      The function abscheck() tests the evaluation of an
+ *      expression to verify it is absolute.  If the evaluation
+ *      is relocatable then an 'r' error is noted and the expression
+ *      made absolute.
  *
- *     Note:   The area type (i.e. ABS) is not checked because
- *             the linker can be told to explicitly relocate an
- *             absolute area.
+ *      Note:   The area type (i.e. ABS) is not checked because
+ *              the linker can be told to explicitly relocate an
+ *              absolute area.
  *
- *     local variables:
- *             none
+ *      local variables:
+ *              none
  *
- *     global variables:
- *             none
+ *      global variables:
+ *              none
  *
- *     functions called:
- *             VOID    rerr()          assubr.c
+ *      functions called:
+ *              VOID    rerr()          assubr.c
  *
- *     side effects:
- *             The expression may be changed to absolute and the
- *             'r' error invoked.
+ *      side effects:
+ *              The expression may be changed to absolute and the
+ *              'r' error invoked.
  */
 
 VOID
@@ -562,29 +570,29 @@ register struct expr *esp;
         }
 }
 
-/*)Function    int     is_abs(esp)
+/*)Function     int     is_abs(esp)
  *
- *             expr *  esp             pointer to an expr structure
+ *              expr *  esp             pointer to an expr structure
  *
- *     The function is_abs() tests the evaluation of an
- *     expression to verify it is absolute.  If the evaluation
- *     is absolute then 1 is returned, else 0 is returned.
+ *      The function is_abs() tests the evaluation of an
+ *      expression to verify it is absolute.  If the evaluation
+ *      is absolute then 1 is returned, else 0 is returned.
  *
- *     Note:   The area type (i.e. ABS) is not checked because
- *             the linker can be told to explicitly relocate an
- *             absolute area.
+ *      Note:   The area type (i.e. ABS) is not checked because
+ *              the linker can be told to explicitly relocate an
+ *              absolute area.
  *
- *     local variables:
- *             none
+ *      local variables:
+ *              none
  *
- *     global variables:
- *             none
+ *      global variables:
+ *              none
  *
- *     functions called:
- *             none
+ *      functions called:
+ *              none
  *
- *     side effects:
- *             none
+ *      side effects:
+ *              none
  */
 
 int
@@ -592,31 +600,31 @@ is_abs (esp)
 register struct expr *esp;
 {
         if (esp->e_flag || esp->e_base.e_ap) {
-               return(0);
+                return(0);
         }
-       return(1);
+        return(1);
 }
 
-/*)Function    int     oprio(c)
+/*)Function     int     oprio(c)
  *
- *             int     c               operator character
+ *              int     c               operator character
  *
- *     The function oprio() returns a relative priority
- *     for all valid unary and binary operators.
+ *      The function oprio() returns a relative priority
+ *      for all valid unary and binary operators.
  *
- *     local variables:
- *             none
+ *      local variables:
+ *              none
  *
- *     global variables:
- *             none
+ *      global variables:
+ *              none
  *
- *     functions called:
- *             none
+ *      functions called:
+ *              none
  *
- *     side effects:
- *             none
+ *      side effects:
+ *              none
  */
+
 int
 oprio(c)
 register int c;
@@ -636,32 +644,32 @@ register int c;
         return (0);
 }
 
-/*)Function    VOID    clrexpr(esp)
+/*)Function     VOID    clrexpr(esp)
  *
- *             expr *  esp             pointer to expression structure
+ *              expr *  esp             pointer to expression structure
  *
- *     The function clrexpr() clears the expression structure.
+ *      The function clrexpr() clears the expression structure.
  *
- *     local variables:
- *             none
+ *      local variables:
+ *              none
  *
- *     global variables:
- *             none
+ *      global variables:
+ *              none
  *
- *     functions called:
- *             none
+ *      functions called:
+ *              none
  *
- *     side effects:
- *             expression structure cleared.
+ *      side effects:
+ *              expression structure cleared.
  */
+
 VOID
 clrexpr(esp)
 register struct expr *esp;
 {
-       esp->e_mode = 0;
-       esp->e_flag = 0;
-       esp->e_addr = 0;
-       esp->e_base.e_ap = NULL;
-       esp->e_rlcf = 0;
+        esp->e_mode = 0;
+        esp->e_flag = 0;
+        esp->e_addr = 0;
+        esp->e_base.e_ap = NULL;
+        esp->e_rlcf = 0;
 }