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