home *** CD-ROM | disk | FTP | other *** search
- /* asexpr.c */
-
- /*
- * (C) Copyright 1989
- * All Rights Reserved
- *
- * Alan R. Baldwin
- * 721 Berkeley St.
- * Kent, Ohio 44240
- */
-
- #include <stdio.h>
- #include <setjmp.h>
- #include "asm.h"
-
- /*
- * Read an expression. The value of the
- * expression and its associated relocation
- * information is stored into the `expr'
- * structure supplied by the user. `N' is
- * a firewall priority; all top level calls
- * (from the user) should be made with `n'
- * set to 0.
- */
- VOID
- expr(esp, n)
- register struct expr *esp;
- {
- register c, d, p;
- struct area *ap;
- struct expr re;
-
- term(esp);
- while (ctype[c = getnb()] == BINOP) {
- if ((p = oprio(c)) <= n)
- break;
- if ((c == '>' || c == '<') && c != get())
- qerr();
- expr(&re, p);
- if (c == '+') {
- if (esp->e_base.e_ap == NULL) {
- esp->e_flag = re.e_flag;
- esp->e_base.e_ap = re.e_base.e_ap;
- } else
- if (re.e_base.e_ap) {
- rerr();
- }
- esp->e_addr += re.e_addr;
- } else
- if (c == '-') {
- if (ap = re.e_base.e_ap) {
- if (esp->e_base.e_ap == ap) {
- esp->e_base.e_ap = NULL;
- } else {
- rerr();
- }
- if (esp->e_flag || re.e_flag) {
- rerr();
- }
- }
- esp->e_addr -= re.e_addr;
- } else {
- abscheck(esp);
- abscheck(&re);
- switch (c) {
-
- case '*':
- esp->e_addr *= re.e_addr;
- break;
-
- case '/':
- esp->e_addr /= re.e_addr;
- break;
-
- case '&':
- esp->e_addr &= re.e_addr;
- break;
-
- case '|':
- esp->e_addr |= re.e_addr;
- break;
-
- case '%':
- esp->e_addr %= re.e_addr;
- break;
-
- case '^':
- esp->e_addr ^= re.e_addr;
- break;
-
- case '<':
- esp->e_addr <<= re.e_addr;
- break;
-
- case '>':
- esp->e_addr >>= re.e_addr;
- break;
- }
- }
- }
- unget(c);
- }
-
- /*
- * Read an absolute expression.
- */
- addr_t
- absexpr()
- {
- struct expr e;
-
- expr(&e, 0);
- abscheck(&e);
- return (e.e_addr);
- }
-
- /*
- * Read a term.
- * Handles unary operators, brackets,
- * constants in decimal, octal or hexadecimal
- * and identifiers. This routine is also
- * responsible for setting the relocation type
- * to symbol based (e.flag != 0) on global
- * references.
- */
- VOID
- term(esp)
- register struct expr *esp;
- {
- register c, n, nd;
- char id[NCPS];
- struct sym *sp;
- struct tsym *tp;
- int r, v;
-
- c = getnb();
- if (c == '#') { c = getnb(); }
- if (c == LFTERM) {
- expr(esp, 0);
- if (getnb() != RTTERM)
- qerr();
- return;
- }
- if (c == '-') {
- expr(esp, 100);
- abscheck(esp);
- esp->e_addr = -esp->e_addr;
- return;
- }
- if (c == '~') {
- expr(esp, 100);
- abscheck(esp);
- esp->e_addr = ~esp->e_addr;
- return;
- }
- if (c == '\'') {
- esp->e_mode = S_USER;
- esp->e_flag = 0;
- esp->e_base.e_ap = NULL;
- esp->e_addr = getmap(-1);
- return;
- }
- if (c == '\"') {
- esp->e_mode = S_USER;
- esp->e_flag = 0;
- esp->e_base.e_ap = NULL;
- if (hilo) {
- esp->e_addr = (getmap(-1)&0377)<<8 | (getmap(-1)&0377);
- } else {
- esp->e_addr = (getmap(-1)&0377) | (getmap(-1)&0377)<<8;
- }
- return;
- }
- if (c == '>' || c == '<') {
- expr(esp, 100);
- abscheck(esp);
- if (c == '>')
- esp->e_addr >>= 8;
- esp->e_addr &= 0377;
- return;
- }
- if (ctype[c] == DIGIT) {
- esp->e_mode = S_USER;
- esp->e_flag = 0;
- esp->e_base.e_ap = NULL;
- r = radix;
- if (c == '0') {
- c = get();
- switch (c) {
- case 'b':
- case 'B':
- r = 2;
- c = get();
- break;
- case '@':
- case 'o':
- case 'O':
- case 'q':
- case 'Q':
- r = 8;
- c = get();
- break;
- case 'd':
- case 'D':
- r = 10;
- c = get();
- break;
- case 'h':
- case 'H':
- case 'x':
- case 'X':
- r = 16;
- c = get();
- break;
- default:
- break;
- }
- }
- n = 0;
- nd = 0;
- while ((v = digit(c, r)) >= 0) {
- n = r*n + v;
- nd = 10*nd + v;
- c = get();
- }
- if (c=='$') {
- tp = symp->s_tsym;
- while (tp) {
- if (nd == tp->t_num) {
- esp->e_base.e_ap = tp->t_area;
- esp->e_addr = tp->t_addr;
- return;
- }
- tp = tp->t_lnk;
- }
- err('u');
- esp->e_addr = 0;
- return;
- }
- unget(c);
- esp->e_addr = n;
- return;
- }
- if (ctype[c] == LETTER) {
- esp->e_mode = S_USER;
- esp->e_flag = 0;
- esp->e_base.e_ap = NULL;
- esp->e_addr = 0;
- getid(id, c);
- if (sp = lookup(id)) {
- if (sp->s_type == S_NEW) {
- if (sp->s_flag&S_GBL) {
- esp->e_flag = 1;
- esp->e_base.e_sp = sp;
- return;
- }
- err('u');
- return;
- }
- esp->e_mode = sp->s_type;
- esp->e_base.e_ap = sp->s_area;
- esp->e_addr = sp->s_addr;
- return;
- }
- err('u');
- return;
- }
- qerr();
- }
-
- /*
- * If `c' is a legal radix `r' digit
- * return its value; otherwise return
- * -1.
- */
- int
- digit(c, r)
- register c, r;
- {
- if (r == 16) {
- if (c >= 'A' && c <= 'F')
- return (c - 'A' + 10);
- if (c >= 'a' && c <= 'f')
- return (c - 'a' + 10);
- }
- if (c >= '0' && c <= '9')
- return (c - '0');
- return (-1);
- }
-
- /*
- * Check if the value of the supplied
- * expression is absolute; if not give
- * a relocation error and force the
- * type to absolute.
- */
- VOID
- abscheck(esp)
- register struct expr *esp;
- {
- if (esp->e_flag || esp->e_base.e_ap) {
- rerr();
- esp->e_flag = 0;
- esp->e_base.e_ap = NULL;
- }
- }
-
- /*
- * Return the priority of the binary
- * operator `c'.
- */
- int
- oprio(c)
- register c;
- {
- if (c == '*' || c == '/' || c == '%')
- return (10);
- if (c == '+' || c == '-')
- return (7);
- if (c == '<' || c == '>')
- return (5);
- if (c == '^')
- return (4);
- if (c == '&')
- return (3);
- if (c == '|')
- return (1);
- return (0);
- }
-