/* * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. * See the copyright notice in the ACK home directory, in the file "Copyright". */ /* This file is ment to be included in the file read_emeV.c. It contains the part that takes care of the reading of human readable EM-code. */ #include /* #define XXX_YYY /* only for early debugging */ #ifdef XXX_YYY #define out(str) ((void) sys_write(STDOUT, str, strlen(str))) #else #define out(s) #endif #define fit16i(x) ((x) >= -32768L && (x) <= 32767L) #define HSIZE 256 /* Size of hashtable for mnemonics */ static int hashtab[HSIZE]; /* The hashtable for mnemonics */ static int argnum; /* Number of arguments */ #define COMMENTSTARTER ';' /* inithash, pre_hash, hash: Simple hashtable mechanism */ PRIVATE int hash(s) register char *s; { register int h = 0; while (*s) { h <<= 1; h += *s++; } return h; } PRIVATE pre_hash(i, s) char *s; { register int h; assert(i != 0); h = hash(s); for (;;) { h++; if (h >= HSIZE) h %= HSIZE; if (hashtab[h] == 0) { hashtab[h] = i; return; } } /*NOTREACHED*/ } extern char em_mnem[][4]; extern char em_pseu[][4]; PRIVATE inithash() { register int i; /* Enter instructions ... */ for (i = sp_fmnem; i <= sp_lmnem; i++) { pre_hash(i, em_mnem[i - sp_fmnem]); } /* and pseudos ... */ for (i = sp_fpseu; i <= sp_lpseu; i++) { pre_hash(i, em_pseu[i - sp_fpseu]); } } /* nospace: skip until we find a non-space character. Also skip comments. */ PRIVATE int nospace() { register int c; do c = getbyte(); while (isspace(c) && c != '\n'); if (c == COMMENTSTARTER) { do c = getbyte(); while (c != '\n' && c != EOF); } return c; } /* syntax: Put an error message in EM_error and skip to the end of the line */ PRIVATE syntax(s) char *s; { register int c; xerror(s); state = 0; while ((c = getbyte()) != '\n' && c != EOF) /* nothing */ ; ungetbyte(c); } /* checkeol: check that we have a complete line (except maybe for spaces) */ PRIVATE checkeol() { if (nospace() != '\n') { syntax("end of line expected"); (void) nospace(); } } /* getescape: read a '\' escape sequence */ PRIVATE int getescape() { register int c, j, r; if ((c = getbyte()) >= '0' && c <= '7') { /* numeric escape */ r = c - '0'; for (j = 0; j < 2; j++) { if ((c = getbyte()) < '0' || c > '7') { ungetbyte(c); return r; } r <<= 3; r += c - '0'; } return r; } switch(c) { case 'b': return '\b'; case 'f': return '\f'; case 'n': return '\n'; case 'r': return '\r'; case 't': return '\t'; } return c; } /* getname: Read a string of characters representing an identifier */ PRIVATE struct string * getname() { register char *p; register struct string *s; register int c; s = stringentry(); p = s->str; c = getbyte(); if (!(isalpha(c) || c == '_')) { ungetbyte(c); syntax("Letter expected"); return s; } while (isalnum(c) || c == '_') { if (p < &(s->str[STRSIZ])) *p++ = c; c = getbyte(); } ungetbyte(c); *p = '\0'; s->length = p - s->str; return s; } /* getstring: read a string of characters between quotes */ PRIVATE struct string * getstring() { register char *p; struct string *s; register int c; static int termc; s = stringentry(); p = s->str; if (!(state & INSTRING)) { /* Not reading a string yet */ termc = getbyte(); /* assert(termc == '"' || termc == '\''); */ /* This assertion does not work. Compiler error messages. The trouble lies in the ", it terminates the string created in the assertion macro */ } for (;;) { if ((c = getbyte()) == '\n' || c == EOF) { ungetbyte(c); syntax("non-terminated string"); break; } if (c == termc) { if (termc == '"') *p++ = '\0'; state &= ~INSTRING; break; } if (c == '\\') c = getescape(); if (p >= &(s->str[STRSIZ])) { state |= INSTRING; ungetbyte(c); break; } *p++ = c; } *p = '\0'; s->length = p - s->str; return s; } PRIVATE struct e_args *gettyp(); PRIVATE int offsetted(argtyp, ap) arith *ap; { register int c; register struct e_args *ap1; if ((c = nospace()) == '+' || c == '-') { ap1 = gettyp(cst_ptyp); if (c == '-') *ap = -(ap1->em_cst); else *ap = ap1->em_cst; return sp_doff; } else *ap = 0; ungetbyte(c); return argtyp; } PRIVATE int getnumber(c, ap) register int c; register struct e_args *ap; { register char *p; int n; register struct string *s = stringentry(); int expsign; long str2long(); p = s->str; ap->em_argtype = cst_ptyp; expsign = 0; if (c == '+' || c == '-') { if (c == '-') *p++ = c; c = getbyte(); } if (! isdigit(c)) { ungetbyte(c); syntax("digit expected"); i_strings--; return sp_cst4; } n = sp_cst4; for (;;) { if (p >= &(s->str[STRSIZ])) { syntax("number too long"); i_strings--; return sp_cst4; } *p++ = c; if ((c = getbyte()) == '.' || c == 'e' || c == 'E') { expsign = c != '.'; n = sp_fcon; continue; } if (expsign) { expsign = 0; if (c == '+' || c == '-') continue; } if (! isdigit(c)) break; } ungetbyte(c); *p = '\0'; c = nospace(); if (n == sp_fcon && c != 'F') { ungetbyte(c); syntax("'F' expected"); return n; } if (c == 'I' || c == 'U' || c == 'F') { ap->em_str = s->str; ap->em_size = gettyp(cst_ptyp)->em_cst; switch(c) { case 'I': ap->em_argtype = ico_ptyp; return sp_icon; case 'U': ap->em_argtype = uco_ptyp; return sp_ucon; case 'F': ap->em_argtype = fco_ptyp; return sp_fcon; } assert(0); } ungetbyte(c); ap->em_cst = (arith) str2long(s->str, 10); i_strings--; return sp_cst4; } PRIVATE int getexpr(); PRIVATE int getfactor(c, ap) register int c; register struct e_args *ap; { if (c == '(') { if (getexpr(nospace(), ap) != sp_cst4) { syntax("expression expected"); } else if ((c = nospace()) != ')') { ungetbyte(c); syntax("')' expected"); } return sp_cst4; } return getnumber(c, ap); } PRIVATE int getterm(c, ap) register int c; register struct e_args *ap; { arith left; if ((c = getfactor(c, ap)) != sp_cst4) return c; for (;;) { if ((c = nospace()) != '*' && c != '/' && c != '%') { ungetbyte(c); break; } left = ap->em_cst; if (getfactor(nospace(), ap) != sp_cst4) { syntax("factor expected"); break; } if (c == '*') ap->em_cst *= left; else if (c == '/') ap->em_cst = left / ap->em_cst; else ap->em_cst = left % ap->em_cst; } return sp_cst4; } PRIVATE int getexpr(c, ap) register int c; register struct e_args *ap; { arith left; if ((c = getterm(c, ap)) != sp_cst4) return c; for (;;) { if ((c = nospace()) != '+' && c != '-') { ungetbyte(c); break; } left = ap->em_cst; if (getterm(nospace(), ap) != sp_cst4) { syntax("term expected"); break; } if (c == '+') ap->em_cst += left; else ap->em_cst = left - ap->em_cst; } return sp_cst4; } PRIVATE int get15u() { register struct e_args *ap = argentry(); ap->em_next = 0; if (getnumber(getbyte(), ap) != sp_cst4) { syntax("integer expected"); } else check((ap->em_cst & ~077777) == 0); i_emargs--; return (int) (ap->em_cst); } PRIVATE struct e_args * gettyp(typset) { register int c, t; register struct e_args *ap = argentry(); register int argtyp; ap->em_next = 0; if ((c = nospace()) == '\n') { ungetbyte(c); out("newline\n"); argtyp = sp_cend; } else if (isdigit(c) || c == '+' || c == '-' || c == '(') { out("expr\n"); argtyp = getexpr(c, ap); if (argtyp == sp_cst4 && fit16i(ap->em_cst)) argtyp = sp_cst2; } else if (isalpha(c) || c == '_') { out("name\n"); ungetbyte(c); ap->em_dnam = getname()->str; ap->em_argtype = sof_ptyp; argtyp = offsetted(sp_dnam, &(ap->em_soff)); } else if (c == '.') { out(".label\n"); ap->em_dlb = get15u(); ap->em_argtype = nof_ptyp; argtyp = offsetted(sp_dlb2, &(ap->em_noff)); } else if (c == '*') { out("*label\n"); ap->em_ilb = get15u(); ap->em_argtype = ilb_ptyp; argtyp = sp_ilb2; } else if (c == '$') { out("$name\n"); ap->em_pnam = getname()->str; ap->em_argtype = pro_ptyp; argtyp = sp_pnam; } else if (c == '"' || c == '\'') { register struct string *s; out("string\n"); ungetbyte(c); s = getstring(0); ap->em_str = s->str; ap->em_size = s->length; ap->em_argtype = str_ptyp; argtyp = sp_scon; } else if (c == '?') { out("?\n"); argtyp = sp_cend; } else { /* c != '\n', so "ungetbyte" not neccesary */ syntax("operand expected"); return ap; } t = argtyp - sp_fspec; assert(t >= 0 && t < 16); if ((typset & (1 << t)) == 0) { syntax("Bad argument type"); return ap; } if (argtyp == sp_cend) return 0; return ap; } PRIVATE struct e_args * getarg(typset) { register int c; if (argnum != 1) { if ((c = nospace()) != ',') { if (c != '\n') { syntax("comma expected"); return 0; } ungetbyte(c); } } argnum++; return gettyp(typset); } /* getmnem: We found the start of either an instruction or a pseudo. get the rest of it */ PRIVATE getmnem(c, p) register struct e_instr *p; { register int h; int i; register struct string *s; ungetbyte(c); s = getname(); h = hash(s->str); for (;;) { h++; if (h >= HSIZE) h %= HSIZE; if ((i = hashtab[h]) == 0) { syntax("bad mnemonic"); return; } else if (i <= sp_lmnem) { assert(i >= sp_fmnem); if (strcmp(s->str, em_mnem[i - sp_fmnem]) != 0) { continue; } p->em_type = EM_MNEM; p->em_opcode = i; break; } assert(i <= sp_lpseu && i >= sp_fpseu); if (strcmp(s->str, em_pseu[i - sp_fpseu]) != 0) { continue; } if (i == ps_mes) { p->em_type = EM_STARTMES; break; } p->em_opcode = i; p->em_type = EM_PSEU; break; } i_strings--; } PRIVATE line_line() { register struct e_args *ap; static char filebuf[STRSIZ + 1]; char *btscpy(); ap = gettyp(ptyp(sp_cst2)); EM_lineno = ap->em_cst; i_emargs--; ap = gettyp(str_ptyp); btscpy(filebuf, ap->em_str, (int) ap->em_size); i_emargs--; i_strings--; EM_filename = filebuf; } PRIVATE getlabel(c, p) register struct e_instr *p; { register struct e_args *ap; ungetbyte(c); ap = gettyp(lab_ptyp|ptyp(sp_cst2)); switch(ap->em_argtype) { case cst_ptyp: p->em_type = EM_DEFILB; p->em_deflb = ap->em_cst; break; case sof_ptyp: p->em_type = EM_DEFDNAM; p->em_defdnam = ap->em_dnam; break; case nof_ptyp: p->em_type = EM_DEFDLB; p->em_deflb = ap->em_dlb; break; } checkeol(); } PRIVATE struct e_instr * gethead() { register int c, i; register struct e_instr *p = &emhead; argnum = 1; for (;;) { EM_lineno++; c = getbyte(); if (c == COMMENTSTARTER) { do c = getbyte(); while (c != '\n' && c != EOF); } if (c == EOF) return 0; if (c == '\n') continue; if (isspace(c)) { c = nospace(); if (isalpha(c) || c == '_') { getmnem(c, p); return p; } ungetbyte(c); } else if (c == '#') line_line(); else { getlabel(c, p); return p; } checkeol(); } /*NOTREACHED*/ }