Initial revision
[fw/sdcc] / as / mcs51 / 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 #include <alloc.h>
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                     /* SD :- moved the abscheck to each case
145                        case and change the right shift operator.. if
146                        right shift by 8 bits of a relocatable address then
147                        the user wants the higher order byte. set the R_MSB
148                        for the expression */
149                        switch (c) {
150
151                         case '*':
152                             abscheck(esp);
153                             abscheck(&re);
154                             esp->e_addr *= re.e_addr;
155                             break;
156
157                         case '/':
158                             abscheck(esp);
159                             abscheck(&re);                          
160                             esp->e_addr /= re.e_addr;
161                             break;
162
163                         case '&':
164                             abscheck(esp);
165                             abscheck(&re);                          
166                             esp->e_addr &= re.e_addr;
167                             break;
168
169                         case '|':
170                             abscheck(esp);
171                             abscheck(&re);                          
172                             esp->e_addr |= re.e_addr;
173                             break;
174
175                         case '%':
176                             abscheck(esp);
177                             abscheck(&re);                          
178                             esp->e_addr %= re.e_addr;
179                             break;
180
181                         case '^':
182                             abscheck(esp);
183                             abscheck(&re);                          
184                             esp->e_addr ^= re.e_addr;
185                             break;
186
187                         case '<':
188                             abscheck(esp);
189                             abscheck(&re);                          
190                             esp->e_addr <<= re.e_addr;
191                             break;
192
193                         case '>':
194                             /* SD change here */                           
195                             abscheck(&re);      
196                             /* if the left is a relative address &
197                                the right side is == 8 then */
198                             if (esp->e_base.e_ap && re.e_addr == 8) {
199                                 esp->e_rlcf |= R_MSB ;
200                                 break;
201                             }
202                             /* else continue with the normal processing */
203                             abscheck(esp);
204                             esp->e_addr >>= re.e_addr;
205                             break;
206                             
207                        default:
208                            qerr();
209                            break;
210                        }
211                 }
212         }
213         unget(c);
214 }
215
216 /*)Function     addr_t  absexpr()
217  *
218  *      The function absexpr() evaluates an expression, verifies it
219  *      is absolute (i.e. not position dependent or relocatable), and
220  *      returns its value.
221  *
222  *      local variables:
223  *              expr    e               expr structure
224  *
225  *      global variables:
226  *              none
227  *
228  *      functions called:
229  *              VOID    abscheck()      asexpr.c
230  *              VOID    clrexpr()       asexpr.c
231  *              VOID    expr()          asexpr.c
232  *
233  *      side effects:
234  *              If the expression is not absolute then
235  *              a 'r' error is reported.
236  */
237
238 addr_t
239 absexpr()
240 {
241         struct expr e;
242
243         clrexpr(&e);
244         expr(&e, 0);
245         abscheck(&e);
246         return (e.e_addr);
247 }
248
249 /*)Function     VOID    term(esp)
250  *
251  *              expr *  esp             pointer to an expr structure
252  *
253  *      The function term() evaluates a single constant
254  *      or symbol value prefaced by any unary operator
255  *      ( +, -, ~, ', ", >, or < ).  This routine is also
256  *      responsible for setting the relocation type to symbol
257  *      based (e.flag != 0) on global references.
258  *
259  *      local variables:
260  *              int     c               current character
261  *              char    id[]            symbol name
262  *              char *  jp              pointer to assembler-source text
263  *              int     n               constant evaluation running sum
264  *              int     r               current evaluation radix
265  *              sym *   sp              pointer to a sym structure
266  *              tsym *  tp              pointer to a tsym structure
267  *              int     v               current digit evaluation
268  *
269  *      global variables:
270  *              char    ctype[]         array of character types, one per
271  *                                      ASCII character
272  *              sym *   symp            pointer to a symbol structure
273  *
274  *      functions called:
275  *              VOID    abscheck()      asexpr.c
276  *              int     digit()         asexpr.c
277  *              VOID    err()           assubr.c
278  *              VOID    expr()          asexpr.c
279  *              int     is_abs()        asexpr.c
280  *              int     get()           aslex.c
281  *              VOID    getid()         aslex.c
282  *              int     getmap()        aslex.c
283  *              int     getnb()         aslex.c
284  *              sym *   lookup()        assym.c
285  *              VOID    qerr()          assubr.c
286  *              VOID    unget()         aslex.c
287  *
288  *      side effects:
289  *              An arithmetic term is evaluated, a symbol structure
290  *              may be created, term evaluation may be terminated
291  *              by a 'q' error.
292  */
293
294 VOID
295 term(esp)
296 register struct expr *esp;
297 {
298         register int c, n;
299         register char *jp;
300         char id[NCPS];
301         struct sym  *sp;
302         struct tsym *tp;
303         int r=0, v;
304
305         c = getnb();
306         /*
307          * Discard the unary '+' at this point and
308          * also any reference to numerical arguments
309          * associated with the '#' prefix.
310          */
311         while (c == '+' || c == '#') { c = getnb(); }
312         /*
313          * Evaluate all binary operators
314          * by recursively calling expr().
315          */
316         if (c == LFTERM) {
317                 expr(esp, 0);
318                 if (getnb() != RTTERM)
319                         qerr();
320                 return;
321         }
322         if (c == '-') {
323                 expr(esp, 100);
324                 abscheck(esp);
325                 esp->e_addr = -esp->e_addr;
326                 return;
327         }
328         if (c == '~') {
329                 expr(esp, 100);
330                 abscheck(esp);
331                 esp->e_addr = ~esp->e_addr;
332                 return;
333         }
334         if (c == '\'') {
335                 esp->e_mode = S_USER;
336                 esp->e_addr = getmap(-1)&0377;
337                 return;
338         }
339         if (c == '\"') {
340                 esp->e_mode = S_USER;
341                 if (hilo) {
342                     esp->e_addr  = (getmap(-1)&0377)<<8;
343                     esp->e_addr |= (getmap(-1)&0377);
344                 } else {
345                     esp->e_addr  = (getmap(-1)&0377);
346                     esp->e_addr |= (getmap(-1)&0377)<<8;
347                 }
348                 return;
349         }
350         if (c == '>' || c == '<') {
351                 expr(esp, 100);
352                 if (is_abs (esp)) {
353                         /*
354                          * evaluate msb/lsb directly
355                          */
356                         if (c == '>')
357                                 esp->e_addr >>= 8;
358                         esp->e_addr &= 0377;
359                         return;
360                 } else {
361                         /*
362                          * let linker perform msb/lsb, lsb is default
363                          */
364                         esp->e_rlcf |= R_BYT2;
365                         if (c == '>')
366                                 esp->e_rlcf |= R_MSB;
367                         return;
368                 }
369         }
370         /*
371          * Evaluate digit sequences as local symbols
372          * if followed by a '$' or as constants.
373          */
374         if (ctype[c] & DIGIT) {
375                 esp->e_mode = S_USER;
376                 jp = ip;
377                 while (ctype[(int)*jp] & RAD10) {
378                         jp++;
379                 }
380                 if (*jp == '$') {
381                         n = 0;
382                         while ((v = digit(c, 10)) >= 0) {
383                                 n = 10*n + v;
384                                 c = get();
385                         }
386                         tp = symp->s_tsym;
387                         while (tp) {
388                                 if (n == tp->t_num) {
389                                         esp->e_base.e_ap = tp->t_area;
390                                         esp->e_addr = tp->t_addr;
391                                         return;
392                                 }
393                                 tp = tp->t_lnk;
394                         }
395                         /* err('u'); */
396                         return;
397                 }
398                 r = radix;
399                 if (c == '0') {
400                         c = get();
401                         switch (c) {
402                                 case 'b':
403                                 case 'B':
404                                         r = 2;
405                                         c = get();
406                                         break;
407                                 case 'o':
408                                 case 'O':
409                                 case 'q':
410                                 case 'Q':
411                                         r = 8;
412                                         c = get();
413                                         break;
414                                 case 'd':
415                                 case 'D':
416                                         r = 10;
417                                         c = get();
418                                         break;
419                                 case 'h':
420                                 case 'H':
421                                 case 'x':
422                                 case 'X':
423                                         r = 16;
424                                         c = get();
425                                         break;
426                                 default:
427                                         break;
428                         }
429                 }
430                 n = 0;
431                 while ((v = digit(c, r)) >= 0) {
432                         n = r*n + v;
433                         c = get();
434                 }
435                 unget(c);
436                 esp->e_addr = n;
437                 return;
438         }
439         /*
440          * Evaluate '$' sequences as a temporary radix
441          * if followed by a '%', '&', '#', or '$'.
442          */
443         if (c == '$') {
444                 c = get();
445                 if (c == '%' || c == '&' || c == '#' || c == '$') {
446                         switch (c) {
447                                 case '%':
448                                         r = 2;
449                                         break;
450                                 case '&':
451                                         r = 8;
452                                         break;
453                                 case '#':
454                                         r = 10;
455                                         break;
456                                 case '$':
457                                         r = 16;                         
458                                         break;
459                                 default:
460                                         break;
461                         }
462                         c = get();
463                         n = 0;
464                         while ((v = digit(c, r)) >= 0) {
465                                 n = r*n + v;
466                                 c = get();
467                         }
468                         unget(c);
469                         esp->e_mode = S_USER;
470                         esp->e_addr = n;
471                         return;
472                 }
473                 unget(c);
474                 c = '$';
475         }
476         /*
477          * Evaluate symbols and labels
478          */
479         if (ctype[c] & LETTER) {
480                 esp->e_mode = S_USER;
481                 getid(id, c);
482                 sp = lookup(id);
483                 if (sp->s_type == S_NEW) {
484                         esp->e_addr = 0;
485                         if (sp->s_flag&S_GBL) {
486                                 esp->e_flag = 1;
487                                 esp->e_base.e_sp = sp;
488                                 return;
489                         }
490                         /* err('u'); */
491                 } else {
492                         esp->e_mode = sp->s_type;
493                         esp->e_addr = sp->s_addr;
494                         esp->e_base.e_ap = sp->s_area;
495                 }
496                 return;
497         }
498         /*
499          * Else not a term.
500          */
501         qerr();
502 }
503
504 /*)Function     int     digit(c, r)
505  *
506  *              int     c               digit character
507  *              int     r               current radix
508  *
509  *      The function digit() returns the value of c
510  *      in the current radix r.  If the c value is not
511  *      a number of the current radix then a -1 is returned.
512  *
513  *      local variables:
514  *              none
515  *
516  *      global variables:
517  *              char    ctype[]         array of character types, one per
518  *                                      ASCII character
519  *
520  *      functions called:
521  *              none
522  *
523  *      side effects:
524  *              none
525  */
526
527 int
528 digit(c, r)
529 register int c, r;
530 {
531         if (r == 16) {
532                 if (ctype[c] & RAD16) {
533                         if (c >= 'A' && c <= 'F')
534                                 return (c - 'A' + 10);
535                         if (c >= 'a' && c <= 'f')
536                                 return (c - 'a' + 10);
537                         return (c - '0');
538                 }
539         } else
540         if (r == 10) {
541                 if (ctype[c] & RAD10)
542                         return (c - '0');
543         } else
544         if (r == 8) {
545                 if (ctype[c] & RAD8)
546                         return (c - '0');
547         } else
548         if (r == 2) {
549                 if (ctype[c] & RAD2)
550                         return (c - '0');
551         }
552         return (-1);
553 }
554
555 /*)Function     VOID    abscheck(esp)
556  *
557  *              expr *  esp             pointer to an expr structure
558  *
559  *      The function abscheck() tests the evaluation of an
560  *      expression to verify it is absolute.  If the evaluation
561  *      is relocatable then an 'r' error is noted and the expression
562  *      made absolute.
563  *
564  *      Note:   The area type (i.e. ABS) is not checked because
565  *              the linker can be told to explicitly relocate an
566  *              absolute area.
567  *
568  *      local variables:
569  *              none
570  *
571  *      global variables:
572  *              none
573  *
574  *      functions called:
575  *              VOID    rerr()          assubr.c
576  *
577  *      side effects:
578  *              The expression may be changed to absolute and the
579  *              'r' error invoked.
580  */
581
582 VOID
583 abscheck(esp)
584 register struct expr *esp;
585 {
586         if (esp->e_flag || esp->e_base.e_ap) {
587                 esp->e_flag = 0;
588                 esp->e_base.e_ap = NULL;
589                 rerr();
590         }
591 }
592
593 /*)Function     int     is_abs(esp)
594  *
595  *              expr *  esp             pointer to an expr structure
596  *
597  *      The function is_abs() tests the evaluation of an
598  *      expression to verify it is absolute.  If the evaluation
599  *      is absolute then 1 is returned, else 0 is returned.
600  *
601  *      Note:   The area type (i.e. ABS) is not checked because
602  *              the linker can be told to explicitly relocate an
603  *              absolute area.
604  *
605  *      local variables:
606  *              none
607  *
608  *      global variables:
609  *              none
610  *
611  *      functions called:
612  *              none
613  *
614  *      side effects:
615  *              none
616  */
617
618 int
619 is_abs (esp)
620 register struct expr *esp;
621 {
622         if (esp->e_flag || esp->e_base.e_ap) {
623                 return(0);
624         }
625         return(1);
626 }
627
628 /*)Function     int     oprio(c)
629  *
630  *              int     c               operator character
631  *
632  *      The function oprio() returns a relative priority
633  *      for all valid unary and binary operators.
634  *
635  *      local variables:
636  *              none
637  *
638  *      global variables:
639  *              none
640  *
641  *      functions called:
642  *              none
643  *
644  *      side effects:
645  *              none
646  */
647  
648 int
649 oprio(c)
650 register int c;
651 {
652         if (c == '*' || c == '/' || c == '%')
653                 return (10);
654         if (c == '+' || c == '-')
655                 return (7);
656         if (c == '<' || c == '>')
657                 return (5);
658         if (c == '^')
659                 return (4);
660         if (c == '&')
661                 return (3);
662         if (c == '|')
663                 return (1);
664         return (0);
665 }
666
667 /*)Function     VOID    clrexpr(esp)
668  *
669  *              expr *  esp             pointer to expression structure
670  *
671  *      The function clrexpr() clears the expression structure.
672  *
673  *      local variables:
674  *              none
675  *
676  *      global variables:
677  *              none
678  *
679  *      functions called:
680  *              none
681  *
682  *      side effects:
683  *              expression structure cleared.
684  */
685  
686 VOID
687 clrexpr(esp)
688 register struct expr *esp;
689 {
690         esp->e_mode = 0;
691         esp->e_flag = 0;
692         esp->e_addr = 0;
693         esp->e_base.e_ap = NULL;
694         esp->e_rlcf = 0;
695 }