4 * (C) Copyright 1989-1995
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.
29 * asexpr.c contains the following functions:
38 * asexpr.c contains no local/static variables
41 /*)Function VOID expr(esp, n)
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.
48 * The function expr() evaluates an expression and
49 * stores its value and relocation information into
50 * the expr structure supplied by the user.
53 * int c current assembler-source
55 * int p current operator priority
56 * area * ap pointer to an area structure
57 * exp re internal expr structure
60 * char ctype[] array of character types, one per
64 * VOID abscheck() asexpr.c
65 * VOID clrexpr() asexpr.c
66 * VOID expr() asexpr.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
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.
84 register struct expr *esp;
92 while (ctype[c = getnb()] & BINOP) {
94 * Handle binary operators + - * / & | % ^ << >>
96 if ((p = oprio(c)) <= n)
98 if ((c == '>' || c == '<') && c != get())
102 esp->e_rlcf |= re.e_rlcf;
105 * esp + re, at least one must be absolute
107 if (esp->e_base.e_ap == NULL) {
109 * esp is absolute (constant),
112 esp->e_base.e_ap = re.e_base.e_ap;
114 if (re.e_base.e_ap) {
116 * re should be absolute (constant)
120 if (esp->e_flag && re.e_flag)
124 esp->e_addr += re.e_addr;
130 if ((ap = re.e_base.e_ap) != NULL) {
131 if (esp->e_base.e_ap == ap) {
132 esp->e_base.e_ap = NULL;
139 esp->e_addr -= re.e_addr;
142 * Both operands (esp and re) must be constants
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 */
154 esp->e_addr *= re.e_addr;
160 esp->e_addr /= re.e_addr;
166 esp->e_addr &= re.e_addr;
172 esp->e_addr |= re.e_addr;
178 esp->e_addr %= re.e_addr;
184 esp->e_addr ^= re.e_addr;
190 esp->e_addr <<= re.e_addr;
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 ;
202 else if (esp->e_base.e_ap && re.e_addr == 16)
206 esp->e_rlcf |= R_HIB;
212 "(expr >> 16) is only meaningful in "
219 /* else continue with the normal processing */
221 esp->e_addr >>= re.e_addr;
233 /*)Function addr_t absexpr()
235 * The function absexpr() evaluates an expression, verifies it
236 * is absolute (i.e. not position dependent or relocatable), and
240 * expr e expr structure
246 * VOID abscheck() asexpr.c
247 * VOID clrexpr() asexpr.c
248 * VOID expr() asexpr.c
251 * If the expression is not absolute then
252 * a 'r' error is reported.
266 /*)Function VOID term(esp)
268 * expr * esp pointer to an expr structure
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.
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
287 * char ctype[] array of character types, one per
289 * sym * symp pointer to a symbol structure
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
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
306 * An arithmetic term is evaluated, a symbol structure
307 * may be created, term evaluation may be terminated
313 register struct expr *esp;
324 * Discard the unary '+' at this point and
325 * also any reference to numerical arguments
326 * associated with the '#' prefix.
328 while (c == '+' || c == '#') { c = getnb(); }
330 * Evaluate all binary operators
331 * by recursively calling expr().
335 if (getnb() != RTTERM)
342 esp->e_addr = -esp->e_addr;
348 esp->e_addr = ~esp->e_addr;
352 esp->e_mode = S_USER;
353 esp->e_addr = getmap(-1)&0377;
357 esp->e_mode = S_USER;
359 esp->e_addr = (getmap(-1)&0377)<<8;
360 esp->e_addr |= (getmap(-1)&0377);
362 esp->e_addr = (getmap(-1)&0377);
363 esp->e_addr |= (getmap(-1)&0377)<<8;
367 if (c == '>' || c == '<') {
371 * evaluate msb/lsb directly
379 * let linker perform msb/lsb, lsb is default
381 esp->e_rlcf |= R_BYT2;
383 esp->e_rlcf |= R_MSB;
388 * Evaluate digit sequences as local symbols
389 * if followed by a '$' or as constants.
391 if (ctype[c] & DIGIT) {
392 esp->e_mode = S_USER;
394 while (ctype[(int)*jp] & RAD10) {
399 while ((v = digit(c, 10)) >= 0) {
405 if (n == tp->t_num) {
406 esp->e_base.e_ap = tp->t_area;
407 esp->e_addr = tp->t_addr;
448 while ((v = digit(c, r)) >= 0) {
457 * Evaluate '$' sequences as a temporary radix
458 * if followed by a '%', '&', '#', or '$'.
462 if (c == '%' || c == '&' || c == '#' || c == '$') {
481 while ((v = digit(c, r)) >= 0) {
486 esp->e_mode = S_USER;
494 * Evaluate symbols and labels
496 if (ctype[c] & LETTER) {
497 esp->e_mode = S_USER;
500 if (sp->s_type == S_NEW) {
502 if (sp->s_flag&S_GBL) {
504 esp->e_base.e_sp = sp;
509 esp->e_mode = sp->s_type;
510 esp->e_addr = sp->s_addr;
511 esp->e_base.e_ap = sp->s_area;
521 /*)Function int digit(c, r)
523 * int c digit character
524 * int r current radix
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.
534 * char ctype[] array of character types, one per
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);
558 if (ctype[c] & RAD10)
572 /*)Function VOID abscheck(esp)
574 * expr * esp pointer to an expr structure
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
581 * Note: The area type (i.e. ABS) is not checked because
582 * the linker can be told to explicitly relocate an
592 * VOID rerr() assubr.c
595 * The expression may be changed to absolute and the
601 register struct expr *esp;
603 if (esp->e_flag || esp->e_base.e_ap) {
605 esp->e_base.e_ap = NULL;
610 /*)Function int is_abs(esp)
612 * expr * esp pointer to an expr structure
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.
618 * Note: The area type (i.e. ABS) is not checked because
619 * the linker can be told to explicitly relocate an
637 register struct expr *esp;
639 if (esp->e_flag || esp->e_base.e_ap) {
645 /*)Function int oprio(c)
647 * int c operator character
649 * The function oprio() returns a relative priority
650 * for all valid unary and binary operators.
669 if (c == '*' || c == '/' || c == '%')
671 if (c == '+' || c == '-')
673 if (c == '<' || c == '>')
684 /*)Function VOID clrexpr(esp)
686 * expr * esp pointer to expression structure
688 * The function clrexpr() clears the expression structure.
700 * expression structure cleared.
705 register struct expr *esp;
710 esp->e_base.e_ap = NULL;