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