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