* as/z80/asexpr.c: fixed bug #1829678: Z-80 CP A,<xxx> assembly
[fw/sdcc] / as / z80 / asexpr.c
1 /* asexpr.c
2
3    Copyright (C) 1989-1995 Alan R. Baldwin
4    721 Berkeley St., Kent, Ohio 44240
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 3, or (at your option) any
9 later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
18
19 #include <stdio.h>
20 #include <setjmp.h>
21 #include <string.h>
22
23 #include "asm.h"
24
25 /*)Module       asexpr.c
26  *
27  *      The module asexpr.c contains the routines to evaluate
28  *      arithmetic/numerical expressions.  The functions in
29  *      asexpr.c perform a recursive evaluation of the arithmetic
30  *      expression read from the assembler-source text line.
31  *      The expression may include binary/unary operators, brackets,
32  *      symbols, labels, and constants in hexadecimal, decimal, octal
33  *      and binary.  Arithmetic operations are prioritized and
34  *      evaluated by normal arithmetic conventions.
35  *
36  *      asexpr.c contains the following functions:
37  *              VOID    abscheck()
38  *              Addr_T  absexpr()
39  *              VOID    clrexpr()
40  *              int     digit()
41  *              VOID    expr()
42  *              int     oprio()
43  *              VOID    term()
44  *
45  *      asexpr.c contains no local/static variables
46  */
47
48 /*)Function     VOID    expr(esp, n)
49  *
50  *              expr *  esp             pointer to an expr structure
51  *              int     n               a firewall priority; all top
52  *                                      level calls (from the user)
53  *                                      should be made with n set to 0.
54  *
55  *      The function expr() evaluates an expression and
56  *      stores its value and relocation information into
57  *      the expr structure supplied by the user.
58  *
59  *      local variables:
60  *              int     c               current assembler-source
61  *                                      text character
62  *              int     p               current operator priority
63  *              area *  ap              pointer to an area structure
64  *              exp     re              internal expr structure
65  *
66  *      global variables:
67  *              char    ctype[]         array of character types, one per
68  *                                      ASCII character
69  *
70  *      functions called:
71  *              VOID    abscheck()      asexpr.c
72  *              VOID    clrexpr()       asexpr.c
73  *              VOID    expr()          asexpr.c
74  *              int     getnb()         aslex.c
75  *              int     oprio()         asexpr.c
76  *              VOID    qerr()          assubr.c
77  *              VOID    rerr()          assubr.c
78  *              VOID    term()          asexpr.c
79  *              VOID    unget()         aslex.c
80  *
81  *
82  *      side effects:
83  *              An expression is evaluated modifying the user supplied
84  *              expr structure, a sym structure maybe created for an
85  *              undefined symbol, and the parse of the expression may
86  *              terminate if a 'q' error occurs.
87  */
88
89 VOID
90 expr(esp, n)
91 register struct expr *esp;
92 int n;
93 {
94         register int c, p;
95         struct area *ap;
96         struct expr re;
97
98         term(esp);
99         while (ctype[c = getnb()] & BINOP) {
100                 /*
101                  * Handle binary operators + - * / & | % ^ << >>
102                  */
103                 if ((p = oprio(c)) <= n)
104                         break;
105                 if ((c == '>' || c == '<') && c != get())
106                         qerr();
107                 clrexpr(&re);
108                 expr(&re, p);
109                 esp->e_rlcf |= re.e_rlcf;
110                 if (c == '+') {
111                         /*
112                          * esp + re, at least one must be absolute
113                          */
114                         if (esp->e_base.e_ap == NULL) {
115                                 /*
116                                  * esp is absolute (constant),
117                                  * use area from re
118                                  */
119                                 esp->e_base.e_ap = re.e_base.e_ap;
120                         } else
121                         if (re.e_base.e_ap) {
122                                 /*
123                                  * re should be absolute (constant)
124                                  */
125                                 rerr();
126                         }
127                         if (esp->e_flag && re.e_flag)
128                                 rerr();
129                         if (re.e_flag)
130                                 esp->e_flag = 1;
131                         esp->e_addr += re.e_addr;
132                 } else
133                 if (c == '-') {
134                         /*
135                          * esp - re
136                          */
137                         if ((ap = re.e_base.e_ap) != NULL) {
138                                 if (esp->e_base.e_ap == ap) {
139                                         esp->e_base.e_ap = NULL;
140                                 } else {
141                                         rerr();
142                                 }
143                         }
144                         if (re.e_flag)
145                                 rerr();
146                         esp->e_addr -= re.e_addr;
147                 } else {
148                         /*
149                          * Both operands (esp and re) must be constants
150                          */
151                         abscheck(esp);
152                         abscheck(&re);
153                         switch (c) {
154
155                         case '*':
156                                 esp->e_addr *= re.e_addr;
157                                 break;
158
159                         case '/':
160                                 esp->e_addr /= re.e_addr;
161                                 break;
162
163                         case '&':
164                                 esp->e_addr &= re.e_addr;
165                                 break;
166
167                         case '|':
168                                 esp->e_addr |= re.e_addr;
169                                 break;
170
171                         case '%':
172                                 esp->e_addr %= re.e_addr;
173                                 break;
174
175                         case '^':
176                                 esp->e_addr ^= re.e_addr;
177                                 break;
178
179                         case '<':
180                                 esp->e_addr <<= re.e_addr;
181                                 break;
182
183                         case '>':
184                                 esp->e_addr >>= re.e_addr;
185                                 break;
186
187                         default:
188                                 qerr();
189                                 break;
190                         }
191                 }
192         }
193         unget(c);
194 }
195
196 /*)Function     Addr_T  absexpr()
197  *
198  *      The function absexpr() evaluates an expression, verifies it
199  *      is absolute (i.e. not position dependent or relocatable), and
200  *      returns its value.
201  *
202  *      local variables:
203  *              expr    e               expr structure
204  *
205  *      global variables:
206  *              none
207  *
208  *      functions called:
209  *              VOID    abscheck()      asexpr.c
210  *              VOID    clrexpr()       asexpr.c
211  *              VOID    expr()          asexpr.c
212  *
213  *      side effects:
214  *              If the expression is not absolute then
215  *              a 'r' error is reported.
216  */
217
218 Addr_T
219 absexpr()
220 {
221         struct expr e;
222
223         clrexpr(&e);
224         expr(&e, 0);
225         abscheck(&e);
226         return (e.e_addr);
227 }
228
229 /*)Function     VOID    term(esp)
230  *
231  *              expr *  esp             pointer to an expr structure
232  *
233  *      The function term() evaluates a single constant
234  *      or symbol value prefaced by any unary operator
235  *      ( +, -, ~, ', ", >, or < ).  This routine is also
236  *      responsible for setting the relocation type to symbol
237  *      based (e.flag != 0) on global references.
238  *
239  *      local variables:
240  *              int     c               current character
241  *              char    id[]            symbol name
242  *              char *  jp              pointer to assembler-source text
243  *              int     n               constant evaluation running sum
244  *              int     r               current evaluation radix
245  *              sym *   sp              pointer to a sym structure
246  *              tsym *  tp              pointer to a tsym structure
247  *              int     v               current digit evaluation
248  *
249  *      global variables:
250  *              char    ctype[]         array of character types, one per
251  *                                      ASCII character
252  *              sym *   symp            pointer to a symbol structure
253  *
254  *      functions called:
255  *              VOID    abscheck()      asexpr.c
256  *              int     digit()         asexpr.c
257  *              VOID    err()           assubr.c
258  *              VOID    expr()          asexpr.c
259  *              int     is_abs()        asexpr.c
260  *              int     get()           aslex.c
261  *              VOID    getid()         aslex.c
262  *              int     getmap()        aslex.c
263  *              int     getnb()         aslex.c
264  *              sym *   lookup()        assym.c
265  *              VOID    qerr()          assubr.c
266  *              VOID    unget()         aslex.c
267  *
268  *      side effects:
269  *              An arithmetic term is evaluated, a symbol structure
270  *              may be created, term evaluation may be terminated
271  *              by a 'q' error.
272  */
273
274 VOID
275 term(esp)
276 register struct expr *esp;
277 {
278         register int c, n;
279         register const char *jp;
280         char id[NCPS];
281         struct sym  *sp;
282         struct tsym *tp;
283         int r = 0, v;
284
285         c = getnb();
286         /*
287          * Discard the unary '+' at this point and
288          * also any reference to numerical arguments
289          * associated with the '#' prefix.
290          */
291         while (c == '+' || c == '#') { c = getnb(); }
292         /*
293          * Evaluate all binary operators
294          * by recursively calling expr().
295          */
296         if (c == LFTERM) {
297                 expr(esp, 0);
298                 if (getnb() != RTTERM)
299                         qerr();
300                 return;
301         }
302         if (c == '-') {
303                 expr(esp, 100);
304                 abscheck(esp);
305                 esp->e_addr = 0 - esp->e_addr;
306                 return;
307         }
308         if (c == '~') {
309                 expr(esp, 100);
310                 abscheck(esp);
311                 esp->e_addr = ~esp->e_addr;
312                 return;
313         }
314         if (c == '\'') {
315                 esp->e_mode = S_USER;
316                 esp->e_addr = getmap(-1)&0377;
317                 return;
318         }
319         if (c == '\"') {
320                 esp->e_mode = S_USER;
321                 if (hilo) {
322                     esp->e_addr  = (getmap(-1)&0377)<<8;
323                     esp->e_addr |= (getmap(-1)&0377);
324                 } else {
325                     esp->e_addr  = (getmap(-1)&0377);
326                     esp->e_addr |= (getmap(-1)&0377)<<8;
327                 }
328                 return;
329         }
330         if (c == '>' || c == '<') {
331                 expr(esp, 100);
332                 if (is_abs (esp)) {
333                         /*
334                          * evaluate msb/lsb directly
335                          */
336                         if (c == '>')
337                                 esp->e_addr >>= 8;
338                         esp->e_addr &= 0377;
339                         return;
340                 } else {
341                         /*
342                          * let linker perform msb/lsb, lsb is default
343                          */
344                         esp->e_rlcf |= R_BYT2;
345                         if (c == '>')
346                                 esp->e_rlcf |= R_MSB;
347                         return;
348                 }
349         }
350         /*
351          * Evaluate digit sequences as local symbols
352          * if followed by a '$' or as constants.
353          */
354         if (ctype[c] & DIGIT) {
355                 esp->e_mode = S_USER;
356                 jp = ip;
357                  while (ctype[(unsigned char)(*jp)] & RAD10) {
358                         jp++;
359                 }
360                 if (*jp == '$') {
361                         n = 0;
362                         while ((v = digit(c, 10)) >= 0) {
363                                 n = 10*n + v;
364                                 c = get();
365                         }
366                         tp = symp->s_tsym;
367                         while (tp) {
368                                 if (n == tp->t_num) {
369                                         esp->e_base.e_ap = tp->t_area;
370                                         esp->e_addr = tp->t_addr;
371                                         return;
372                                 }
373                                 tp = tp->t_lnk;
374                         }
375                         err('u');
376                         return;
377                 }
378                 r = radix;
379                 if (c == '0') {
380                         c = get();
381                         switch (c) {
382                                 case 'b':
383                                 case 'B':
384                                         r = 2;
385                                         c = get();
386                                         break;
387                                 case 'o':
388                                 case 'O':
389                                 case 'q':
390                                 case 'Q':
391                                         r = 8;
392                                         c = get();
393                                         break;
394                                 case 'd':
395                                 case 'D':
396                                         r = 10;
397                                         c = get();
398                                         break;
399                                 case 'h':
400                                 case 'H':
401                                 case 'x':
402                                 case 'X':
403                                         r = 16;
404                                         c = get();
405                                         break;
406                                 default:
407                                         break;
408                         }
409                 }
410                 n = 0;
411                 while ((v = digit(c, r)) >= 0) {
412                         n = r*n + v;
413                         c = get();
414                 }
415                 unget(c);
416                 esp->e_addr = n;
417                 return;
418         }
419         /*
420          * Evaluate '$' sequences as a temporary radix
421          * if followed by a '%', '&', '#', or '$'.
422          */
423         if (c == '$') {
424                 c = get();
425                 if (c == '%' || c == '&' || c == '#' || c == '$') {
426                         switch (c) {
427                                 case '%':
428                                         r = 2;
429                                         break;
430                                 case '&':
431                                         r = 8;
432                                         break;
433                                 case '#':
434                                         r = 10;
435                                         break;
436                                 case '$':
437                                         r = 16;
438                                         break;
439                                 default:
440                                         break;
441                         }
442                         c = get();
443                         n = 0;
444                         while ((v = digit(c, r)) >= 0) {
445                                 n = r*n + v;
446                                 c = get();
447                         }
448                         unget(c);
449                         esp->e_mode = S_USER;
450                         esp->e_addr = n;
451                         return;
452                 }
453                 unget(c);
454                 c = '$';
455         }
456         /*
457          * Evaluate symbols and labels
458          */
459         if (ctype[c] & LETTER) {
460                 esp->e_mode = S_USER;
461                 getid(id, c);
462                 sp = lookup(id);
463                 if (sp->s_type == S_NEW) {
464                         esp->e_addr = 0;
465                         if (sp->s_flag&S_GBL) {
466                                 esp->e_flag = 1;
467                                 esp->e_base.e_sp = sp;
468                                 return;
469                         }
470                         err('u');
471                 } else {
472                         esp->e_mode = sp->s_type;
473                         esp->e_addr = sp->s_addr;
474                         esp->e_base.e_ap = sp->s_area;
475                 }
476                 return;
477         }
478         /*
479          * Else not a term.
480          */
481         qerr();
482 }
483
484 /*)Function     int     digit(c, r)
485  *
486  *              int     c               digit character
487  *              int     r               current radix
488  *
489  *      The function digit() returns the value of c
490  *      in the current radix r.  If the c value is not
491  *      a number of the current radix then a -1 is returned.
492  *
493  *      local variables:
494  *              none
495  *
496  *      global variables:
497  *              char    ctype[]         array of character types, one per
498  *                                      ASCII character
499  *
500  *      functions called:
501  *              none
502  *
503  *      side effects:
504  *              none
505  */
506
507 int
508 digit(c, r)
509 register int c, r;
510 {
511         if (r == 16) {
512                 if (ctype[c] & RAD16) {
513                         if (c >= 'A' && c <= 'F')
514                                 return (c - 'A' + 10);
515                         if (c >= 'a' && c <= 'f')
516                                 return (c - 'a' + 10);
517                         return (c - '0');
518                 }
519         } else
520         if (r == 10) {
521                 if (ctype[c] & RAD10)
522                         return (c - '0');
523         } else
524         if (r == 8) {
525                 if (ctype[c] & RAD8)
526                         return (c - '0');
527         } else
528         if (r == 2) {
529                 if (ctype[c] & RAD2)
530                         return (c - '0');
531         }
532         return (-1);
533 }
534
535 /*)Function     VOID    abscheck(esp)
536  *
537  *              expr *  esp             pointer to an expr structure
538  *
539  *      The function abscheck() tests the evaluation of an
540  *      expression to verify it is absolute.  If the evaluation
541  *      is relocatable then an 'r' error is noted and the expression
542  *      made absolute.
543  *
544  *      Note:   The area type (i.e. ABS) is not checked because
545  *              the linker can be told to explicitly relocate an
546  *              absolute area.
547  *
548  *      local variables:
549  *              none
550  *
551  *      global variables:
552  *              none
553  *
554  *      functions called:
555  *              VOID    rerr()          assubr.c
556  *
557  *      side effects:
558  *              The expression may be changed to absolute and the
559  *              'r' error invoked.
560  */
561
562 VOID
563 abscheck(esp)
564 register struct expr *esp;
565 {
566         if (esp->e_flag || esp->e_base.e_ap) {
567                 esp->e_flag = 0;
568                 esp->e_base.e_ap = NULL;
569                 rerr();
570         }
571 }
572
573 /*)Function     int     is_abs(esp)
574  *
575  *              expr *  esp             pointer to an expr structure
576  *
577  *      The function is_abs() tests the evaluation of an
578  *      expression to verify it is absolute.  If the evaluation
579  *      is absolute then 1 is returned, else 0 is returned.
580  *
581  *      Note:   The area type (i.e. ABS) is not checked because
582  *              the linker can be told to explicitly relocate an
583  *              absolute area.
584  *
585  *      local variables:
586  *              none
587  *
588  *      global variables:
589  *              none
590  *
591  *      functions called:
592  *              none
593  *
594  *      side effects:
595  *              none
596  */
597
598 int
599 is_abs (esp)
600 register struct expr *esp;
601 {
602         if (esp->e_flag || esp->e_base.e_ap) {
603                 return(0);
604         }
605         return(1);
606 }
607
608 /*)Function     int     oprio(c)
609  *
610  *              int     c               operator character
611  *
612  *      The function oprio() returns a relative priority
613  *      for all valid unary and binary operators.
614  *
615  *      local variables:
616  *              none
617  *
618  *      global variables:
619  *              none
620  *
621  *      functions called:
622  *              none
623  *
624  *      side effects:
625  *              none
626  */
627
628 int
629 oprio(c)
630 register int c;
631 {
632         if (c == '*' || c == '/' || c == '%')
633                 return (10);
634         if (c == '+' || c == '-')
635                 return (7);
636         if (c == '<' || c == '>')
637                 return (5);
638         if (c == '^')
639                 return (4);
640         if (c == '&')
641                 return (3);
642         if (c == '|')
643                 return (1);
644         return (0);
645 }
646
647 /*)Function     VOID    clrexpr(esp)
648  *
649  *              expr *  esp             pointer to expression structure
650  *
651  *      The function clrexpr() clears the expression structure.
652  *
653  *      local variables:
654  *              none
655  *
656  *      global variables:
657  *              none
658  *
659  *      functions called:
660  *              none
661  *
662  *      side effects:
663  *              expression structure cleared.
664  */
665
666 VOID
667 clrexpr(esp)
668 register struct expr *esp;
669 {
670         esp->e_mode = 0;
671         esp->e_flag = 0;
672         esp->e_addr = 0;
673         esp->e_base.e_ap = NULL;
674         esp->e_rlcf = 0;
675 }