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