4 * (C) Copyright 1989-1995
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.
28 * asexpr.c contains the following functions:
37 * asexpr.c contains no local/static variables
40 /*)Function VOID expr(esp, n)
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.
47 * The function expr() evaluates an expression and
48 * stores its value and relocation information into
49 * the expr structure supplied by the user.
52 * int c current assembler-source
54 * int p current operator priority
55 * area * ap pointer to an area structure
56 * exp re internal expr structure
59 * char ctype[] array of character types, one per
63 * VOID abscheck() asexpr.c
64 * VOID clrexpr() asexpr.c
65 * VOID expr() asexpr.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
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.
83 register struct expr *esp;
91 while (ctype[c = getnb()] & BINOP) {
93 * Handle binary operators + - * / & | % ^ << >>
95 if ((p = oprio(c)) <= n)
97 if ((c == '>' || c == '<') && c != get())
101 esp->e_rlcf |= re.e_rlcf;
104 * esp + re, at least one must be absolute
106 if (esp->e_base.e_ap == NULL) {
108 * esp is absolute (constant),
111 esp->e_base.e_ap = re.e_base.e_ap;
113 if (re.e_base.e_ap) {
115 * re should be absolute (constant)
119 if (esp->e_flag && re.e_flag)
123 esp->e_addr += re.e_addr;
129 if ((ap = re.e_base.e_ap) != NULL) {
130 if (esp->e_base.e_ap == ap) {
131 esp->e_base.e_ap = NULL;
138 esp->e_addr -= re.e_addr;
141 * Both operands (esp and re) must be constants
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 */
153 esp->e_addr *= re.e_addr;
159 esp->e_addr /= re.e_addr;
165 esp->e_addr &= re.e_addr;
171 esp->e_addr |= re.e_addr;
177 esp->e_addr %= re.e_addr;
183 esp->e_addr ^= re.e_addr;
189 esp->e_addr <<= re.e_addr;
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 ;
201 else if (esp->e_base.e_ap && re.e_addr == 16)
205 esp->e_rlcf |= R_HIB;
211 "(expr >> 16) is only meaningful in "
218 /* else continue with the normal processing */
220 esp->e_addr >>= re.e_addr;
232 /*)Function Addr_T absexpr()
234 * The function absexpr() evaluates an expression, verifies it
235 * is absolute (i.e. not position dependent or relocatable), and
239 * expr e expr structure
245 * VOID abscheck() asexpr.c
246 * VOID clrexpr() asexpr.c
247 * VOID expr() asexpr.c
250 * If the expression is not absolute then
251 * a 'r' error is reported.
265 /*)Function VOID term(esp)
267 * expr * esp pointer to an expr structure
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.
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
286 * char ctype[] array of character types, one per
288 * sym * symp pointer to a symbol structure
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
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
305 * An arithmetic term is evaluated, a symbol structure
306 * may be created, term evaluation may be terminated
312 register struct expr *esp;
323 * Discard the unary '+' at this point and
324 * also any reference to numerical arguments
325 * associated with the '#' prefix.
327 while (c == '+' || c == '#') { c = getnb(); }
329 * Evaluate all binary operators
330 * by recursively calling expr().
334 if (getnb() != RTTERM)
341 esp->e_addr = 0-esp->e_addr;
347 esp->e_addr = ~esp->e_addr;
351 esp->e_mode = S_USER;
352 esp->e_addr = getmap(-1)&0377;
356 esp->e_mode = S_USER;
358 esp->e_addr = (getmap(-1)&0377)<<8;
359 esp->e_addr |= (getmap(-1)&0377);
361 esp->e_addr = (getmap(-1)&0377);
362 esp->e_addr |= (getmap(-1)&0377)<<8;
366 if (c == '>' || c == '<') {
370 * evaluate msb/lsb directly
378 * let linker perform msb/lsb, lsb is default
380 esp->e_rlcf |= R_BYT2;
382 esp->e_rlcf |= R_MSB;
387 * Evaluate digit sequences as local symbols
388 * if followed by a '$' or as constants.
390 if (ctype[c] & DIGIT) {
391 esp->e_mode = S_USER;
393 while (ctype[(int)*jp] & RAD10) {
398 while ((v = digit(c, 10)) >= 0) {
404 if (n == tp->t_num) {
405 esp->e_base.e_ap = tp->t_area;
406 esp->e_addr = tp->t_addr;
447 while ((v = digit(c, r)) >= 0) {
456 * Evaluate '$' sequences as a temporary radix
457 * if followed by a '%', '&', '#', or '$'.
461 if (c == '%' || c == '&' || c == '#' || c == '$') {
480 while ((v = digit(c, r)) >= 0) {
485 esp->e_mode = S_USER;
493 * Evaluate symbols and labels
495 if (ctype[c] & LETTER) {
496 esp->e_mode = S_USER;
499 if (sp->s_type == S_NEW) {
501 if (sp->s_flag&S_GBL) {
503 esp->e_base.e_sp = sp;
508 esp->e_mode = sp->s_type;
509 esp->e_addr = sp->s_addr;
510 esp->e_base.e_ap = sp->s_area;
520 /*)Function int digit(c, r)
522 * int c digit character
523 * int r current radix
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.
533 * char ctype[] array of character types, one per
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);
557 if (ctype[c] & RAD10)
571 /*)Function VOID abscheck(esp)
573 * expr * esp pointer to an expr structure
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
580 * Note: The area type (i.e. ABS) is not checked because
581 * the linker can be told to explicitly relocate an
591 * VOID rerr() assubr.c
594 * The expression may be changed to absolute and the
600 register struct expr *esp;
602 if (esp->e_flag || esp->e_base.e_ap) {
604 esp->e_base.e_ap = NULL;
609 /*)Function int is_abs(esp)
611 * expr * esp pointer to an expr structure
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.
617 * Note: The area type (i.e. ABS) is not checked because
618 * the linker can be told to explicitly relocate an
636 register struct expr *esp;
638 if (esp->e_flag || esp->e_base.e_ap) {
644 /*)Function int oprio(c)
646 * int c operator character
648 * The function oprio() returns a relative priority
649 * for all valid unary and binary operators.
668 if (c == '*' || c == '/' || c == '%')
670 if (c == '+' || c == '-')
672 if (c == '<' || c == '>')
683 /*)Function VOID clrexpr(esp)
685 * expr * esp pointer to expression structure
687 * The function clrexpr() clears the expression structure.
699 * expression structure cleared.
704 register struct expr *esp;
709 esp->e_base.e_ap = NULL;