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