ack/modules/src/read_em/reade.c

654 lines
11 KiB
C
Raw Normal View History

1987-03-10 09:24:02 +00:00
/* $Header$ */
1987-03-09 15:15:03 +00:00
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
1987-01-06 11:05:35 +00:00
/* 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 <ctype.h>
/* #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");
1987-03-04 09:54:23 +00:00
i_strings--;
1987-01-06 11:05:35 +00:00
return sp_cst4;
}
n = sp_cst4;
for (;;) {
if (p >= &(s->str[STRSIZ])) {
syntax("number too long");
1987-03-04 09:54:23 +00:00
i_strings--;
1987-01-06 11:05:35 +00:00
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--;
1987-03-04 09:54:23 +00:00
i_strings--;
1987-01-06 11:05:35 +00:00
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++;
1987-02-06 10:27:57 +00:00
c = getbyte();
if (c == COMMENTSTARTER) {
do c = getbyte();
while (c != '\n' && c != EOF);
}
if (c == EOF) return 0;
1987-01-06 11:05:35 +00:00
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*/
}