* as/link/aslink.h: added LKOBJEXT
[fw/sdcc] / as / link / lkeval.c
1 /* lkeval.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 <string.h>
14 #include "aslink.h"
15
16 /*)Module       lkeval.c
17  *
18  *      The module lkeval.c contains the routines to evaluate
19  *      arithmetic/numerical expressions.  The functions in
20  *      lkeval.c perform a recursive evaluation of the arithmetic
21  *      expression read from the input text line.
22  *      The expression may include binary/unary operators, brackets,
23  *      symbols, labels, and constants in hexadecimal, decimal, octal
24  *      and binary.  Arithmetic operations are prioritized and
25  *      evaluated by normal arithmetic conventions.
26  *
27  *      lkeval.c contains the following functions:
28  *              int     digit()
29  *              Addr_T  eval()
30  *              Addr_T  expr()
31  *              int     oprio()
32  *              Addr_T  term()
33  *
34  *      lkeval.c contains no local/static variables
35  */
36
37 /*)Function     Addr_T  eval()
38  *
39  *      The function eval() evaluates a character string to a
40  *      numerical value.
41  *
42  *      local variables:
43  *              int     c               character from input string
44  *              int     v               value of character in current radix
45  *              Addr_T  n               evaluation value
46  *
47  *      global variables:
48  *              int     radix           current number conversion radix
49  *
50  *      functions called:
51  *              int     digit()         lkeval.c
52  *              char    get()           lklex.c
53  *              char    getnb()         lklex.c
54  *              VOID    unget()         lklex.c
55  *
56  *      side effects:
57  *              Input test is scanned and evaluated to a
58  *              numerical value.
59  */
60
61 Addr_T
62 eval()
63 {
64         register int c, v;
65         register Addr_T n;
66
67         c = getnb();
68         n = 0;
69         while ((v = digit(c, radix)) >= 0) {
70                 n = n*radix + v;
71                 c = get();
72         }
73         unget(c);
74         return(n);
75 }
76
77 /*)Function     Addr_T  expr(n)
78  *
79  *              int     n               a firewall priority; all top
80  *                                      level calls (from the user)
81  *                                      should be made with n set to 0.
82  *
83  *      The function expr() evaluates an expression and
84  *      returns the value.
85  *
86  *      local variables:
87  *              int     c               current input text character
88  *              int     p               current operator priority
89  *              Addr_T  v               value returned by term()
90  *              Addr_T  ve              value returned by a
91  *                                      recursive call to expr()
92  *
93  *      global variables:
94  *              char    ctype[]         array of character types, one per
95  *                                      ASCII character
96  *              int     lkerr           error flag
97  *              FILE *  stderr          c_library
98  *
99  *      functions called:
100  *              VOID    expr()          lkeval.c
101  *              int     fprintf()       c_library
102  *              int     getnb()         lklex.c
103  *              int     oprio()         lkeval.c
104  *              VOID    term()          lkeval.c
105  *              VOID    unget()         lklex.c
106  *
107  *
108  *      side effects:
109  *              An expression is evaluated by scanning the input
110  *              text string.
111  */
112
113 Addr_T
114 expr (n)
115 {
116         register int c, p;
117         register Addr_T v, ve;
118
119         v = term();
120         while (ctype[c = getnb()] & BINOP) {
121                 if ((p = oprio(c)) <= n)
122                         break;
123                 if ((c == '>' || c == '<') && c != get()) {
124                         fprintf(stderr, "Invalid expression");
125                         lkerr++;
126                         return(v);
127                 }
128                 ve = expr(p);
129                 if (c == '+') {
130                         v += ve;
131                 } else
132                 if (c == '-') {
133                         v -= ve;
134                 } else {
135                         switch (c) {
136
137                         case '*':
138                                 v *= ve;
139                                 break;
140
141                         case '/':
142                                 v /= ve;
143                                 break;
144
145                         case '&':
146                                 v &= ve;
147                                 break;
148
149                         case '|':
150                                 v |= ve;
151                                 break;
152
153                         case '%':
154                                 v %= ve;
155                                 break;
156
157                         case '^':
158                                 v ^= ve;
159                                 break;
160
161                         case '<':
162                                 v <<= ve;
163                                 break;
164
165                         case '>':
166                                 v >>= ve;
167                                 break;
168                         }
169                 }
170         }
171         unget(c);
172         return(v);
173 }
174
175 /*)Function     Addr_T  term()
176  *
177  *      The function term() evaluates a single constant
178  *      or symbol value prefaced by any unary operator
179  *      ( +, -, ~, ', ", >, or < ).
180  *
181  *      local variables:
182  *              int     c               current character
183  *              char    id[]            symbol name
184  *              int     n               value of digit in current radix
185  *              int     r               current evaluation radix
186  *              sym *   sp              pointer to a sym structure
187  *              Addr_T  v               evaluation value
188  *
189  *      global variables:
190  *              char    ctype[]         array of character types, one per
191  *                                      ASCII character
192  *              int     lkerr           error flag
193  *
194  *      functions called:
195  *              int     digit()         lkeval.c
196  *              VOID    expr()          lkeval.c
197  *              int     fprintf()       c_library
198  *              int     get()           lklex.c
199  *              VOID    getid()         lklex.c
200  *              int     getmap()        lklex.c
201  *              int     getnb()         lklex.c
202  *              sym *   lkpsym()        lksym.c
203  *              Addr_T  symval()        lksym.c
204  *              VOID    unget()         lklex.c
205  *
206  *      side effects:
207  *              An arithmetic term is evaluated by scanning input text.
208  */
209
210 Addr_T
211 term()
212 {
213         register int c, r, n;
214         register Addr_T v;
215         struct sym *sp;
216         char id[NCPS];
217
218         c = getnb();
219         if (c == '#') { c = getnb(); }
220         if (c == '(') {
221                 v = expr(0);
222                 if (getnb() != ')') {
223                         fprintf(stderr, "Missing delimiter");
224                         lkerr++;
225                 }
226                 return(v);
227         }
228         if (c == '-') {
229                 return(0-expr(100));
230         }
231         if (c == '~') {
232                 return(~expr(100));
233         }
234         if (c == '\'') {
235                 return(getmap(-1)&0377);
236         }
237         if (c == '\"') {
238                 if (hilo) {
239                         v  = (getmap(-1)&0377)<<8;
240                         v |=  getmap(-1)&0377;
241                 } else {
242                         v  =  getmap(-1)&0377;
243                         v |= (getmap(-1)&0377)<<8;
244                 }
245                 return(v);
246         }
247         if (c == '>' || c == '<') {
248                 v = expr(100);
249                 if (c == '>')
250                         v >>= 8;
251                 return(v&0377);
252         }
253         if (ctype[c] & DIGIT) {
254                 r = 10;
255                 if (c == '0') {
256                         c = get();
257                         switch (c) {
258                         case 'b':
259                         case 'B':
260                                 r = 2;
261                                 c = get();
262                                 break;
263                         case '@':
264                         case 'o':
265                         case 'O':
266                         case 'q':
267                         case 'Q':
268                                 r = 8;
269                                 c = get();
270                                 break;
271                         case 'd':
272                         case 'D':
273                                 r = 10;
274                                 c = get();
275                                 break;
276                         case 'h':
277                         case 'H':
278                         case 'x':
279                         case 'X':
280                                 r = 16;
281                                 c = get();
282                                 break;
283                         default:
284                                 break;
285                         }
286                 }
287                 v = 0;
288                 while ((n = digit(c, r)) >= 0) {
289                         v = r*v + n;
290                         c = get();
291                 }
292                 unget(c);
293                 return(v);
294         }
295         if (ctype[c] & LETTER) {
296                 getid(id, c);
297                 if ((sp = lkpsym(id, 0)) == NULL) {
298                         fprintf(stderr, "Undefined symbol %8s\n", id);
299                         lkerr++;
300                         return(0);
301                 } else {
302                         return(symval(sp));
303                 }
304         }
305         /* Shouldn't get here. */
306         return(0);
307 }
308
309 /*)Function     int     digit(c, r)
310  *
311  *              int     c               digit character
312  *              int     r               current radix
313  *
314  *      The function digit() returns the value of c
315  *      in the current radix r.  If the c value is not
316  *      a number of the current radix then a -1 is returned.
317  *
318  *      local variables:
319  *              none
320  *
321  *      global variables:
322  *              char    ctype[]         array of character types, one per
323  *                                      ASCII character
324  *
325  *      functions called:
326  *              none
327  *
328  *      side effects:
329  *              none
330  */
331
332 int
333 digit(c, r)
334 register int c, r;
335 {
336         if (r == 16) {
337                 if (ctype[c] & RAD16) {
338                         if (c >= 'A' && c <= 'F')
339                                 return (c - 'A' + 10);
340                         if (c >= 'a' && c <= 'f')
341                                 return (c - 'a' + 10);
342                         return (c - '0');
343                 }
344         } else
345         if (r == 10) {
346                 if (ctype[c] & RAD10)
347                         return (c - '0');
348         } else
349         if (r == 8) {
350                 if (ctype[c] & RAD8)
351                         return (c - '0');
352         } else
353         if (r == 2) {
354                 if (ctype[c] & RAD2)
355                         return (c - '0');
356         }
357         return (-1);
358 }
359
360 /*)Function     int     oprio(c)
361  *
362  *              int     c               operator character
363  *
364  *      The function oprio() returns a relative priority
365  *      for all valid unary and binary operators.
366  *
367  *      local variables:
368  *              none
369  *
370  *      global variables:
371  *              none
372  *
373  *      functions called:
374  *              none
375  *
376  *      side effects:
377  *              none
378  */
379  
380 int
381 oprio(c)
382 register int c;
383 {
384         if (c == '*' || c == '/' || c == '%')
385                 return (10);
386         if (c == '+' || c == '-')
387                 return (7);
388         if (c == '<' || c == '>')
389                 return (5);
390         if (c == '^')
391                 return (4);
392         if (c == '&')
393                 return (3);
394         if (c == '|')
395                 return (1);
396         return (0);
397 }