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