* asranlib/asranlib.c, link/lkar.h, link/lkar.c:
[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                         if (sp->s_flag&S_GBL) {
465                                 esp->e_flag = 1;
466                                 esp->e_base.e_sp = sp;
467                                 return;
468                         }
469                         err('u');
470                 } else {
471                         esp->e_mode = sp->s_type;
472                         esp->e_addr = sp->s_addr;
473                         esp->e_base.e_ap = sp->s_area;
474                 }
475                 return;
476         }
477         /*
478          * Else not a term.
479          */
480         qerr();
481 }
482
483 /*)Function     int     digit(c, r)
484  *
485  *              int     c               digit character
486  *              int     r               current radix
487  *
488  *      The function digit() returns the value of c
489  *      in the current radix r.  If the c value is not
490  *      a number of the current radix then a -1 is returned.
491  *
492  *      local variables:
493  *              none
494  *
495  *      global variables:
496  *              char    ctype[]         array of character types, one per
497  *                                      ASCII character
498  *
499  *      functions called:
500  *              none
501  *
502  *      side effects:
503  *              none
504  */
505
506 int
507 digit(c, r)
508 register int c, r;
509 {
510         if (r == 16) {
511                 if (ctype[c] & RAD16) {
512                         if (c >= 'A' && c <= 'F')
513                                 return (c - 'A' + 10);
514                         if (c >= 'a' && c <= 'f')
515                                 return (c - 'a' + 10);
516                         return (c - '0');
517                 }
518         } else
519         if (r == 10) {
520                 if (ctype[c] & RAD10)
521                         return (c - '0');
522         } else
523         if (r == 8) {
524                 if (ctype[c] & RAD8)
525                         return (c - '0');
526         } else
527         if (r == 2) {
528                 if (ctype[c] & RAD2)
529                         return (c - '0');
530         }
531         return (-1);
532 }
533
534 /*)Function     VOID    abscheck(esp)
535  *
536  *              expr *  esp             pointer to an expr structure
537  *
538  *      The function abscheck() tests the evaluation of an
539  *      expression to verify it is absolute.  If the evaluation
540  *      is relocatable then an 'r' error is noted and the expression
541  *      made absolute.
542  *
543  *      Note:   The area type (i.e. ABS) is not checked because
544  *              the linker can be told to explicitly relocate an
545  *              absolute area.
546  *
547  *      local variables:
548  *              none
549  *
550  *      global variables:
551  *              none
552  *
553  *      functions called:
554  *              VOID    rerr()          assubr.c
555  *
556  *      side effects:
557  *              The expression may be changed to absolute and the
558  *              'r' error invoked.
559  */
560
561 VOID
562 abscheck(esp)
563 register struct expr *esp;
564 {
565         if (esp->e_flag || esp->e_base.e_ap) {
566                 esp->e_flag = 0;
567                 esp->e_base.e_ap = NULL;
568                 rerr();
569         }
570 }
571
572 /*)Function     int     is_abs(esp)
573  *
574  *              expr *  esp             pointer to an expr structure
575  *
576  *      The function is_abs() tests the evaluation of an
577  *      expression to verify it is absolute.  If the evaluation
578  *      is absolute then 1 is returned, else 0 is returned.
579  *
580  *      Note:   The area type (i.e. ABS) is not checked because
581  *              the linker can be told to explicitly relocate an
582  *              absolute area.
583  *
584  *      local variables:
585  *              none
586  *
587  *      global variables:
588  *              none
589  *
590  *      functions called:
591  *              none
592  *
593  *      side effects:
594  *              none
595  */
596
597 int
598 is_abs (esp)
599 register struct expr *esp;
600 {
601         if (esp->e_flag || esp->e_base.e_ap) {
602                 return(0);
603         }
604         return(1);
605 }
606
607 /*)Function     int     oprio(c)
608  *
609  *              int     c               operator character
610  *
611  *      The function oprio() returns a relative priority
612  *      for all valid unary and binary operators.
613  *
614  *      local variables:
615  *              none
616  *
617  *      global variables:
618  *              none
619  *
620  *      functions called:
621  *              none
622  *
623  *      side effects:
624  *              none
625  */
626
627 int
628 oprio(c)
629 register int c;
630 {
631         if (c == '*' || c == '/' || c == '%')
632                 return (10);
633         if (c == '+' || c == '-')
634                 return (7);
635         if (c == '<' || c == '>')
636                 return (5);
637         if (c == '^')
638                 return (4);
639         if (c == '&')
640                 return (3);
641         if (c == '|')
642                 return (1);
643         return (0);
644 }
645
646 /*)Function     VOID    clrexpr(esp)
647  *
648  *              expr *  esp             pointer to expression structure
649  *
650  *      The function clrexpr() clears the expression structure.
651  *
652  *      local variables:
653  *              none
654  *
655  *      global variables:
656  *              none
657  *
658  *      functions called:
659  *              none
660  *
661  *      side effects:
662  *              expression structure cleared.
663  */
664
665 VOID
666 clrexpr(esp)
667 register struct expr *esp;
668 {
669         esp->e_mode = 0;
670         esp->e_flag = 0;
671         esp->e_addr = 0;
672         esp->e_base.e_ap = NULL;
673         esp->e_rlcf = 0;
674 }