1987-01-06 11:05:35 +00:00
|
|
|
/* This file must be included in the file "read_emk.c".
|
|
|
|
It takes care of the reading of compact EM code.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
/* get16, get32: read a signed constant
|
|
|
|
*/
|
|
|
|
PRIVATE int
|
|
|
|
get16()
|
|
|
|
{
|
|
|
|
register int l_byte, h_byte;
|
|
|
|
|
|
|
|
l_byte = getbyte();
|
|
|
|
h_byte = getbyte();
|
|
|
|
if (h_byte >= 128) h_byte -= 256;
|
|
|
|
return l_byte | (h_byte << 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRIVATE arith
|
|
|
|
get32()
|
|
|
|
{
|
|
|
|
register arith l;
|
|
|
|
register int h_byte;
|
|
|
|
|
|
|
|
l = getbyte();
|
|
|
|
l |= ((unsigned) getbyte() << 8);
|
|
|
|
l |= ((arith) getbyte() << 16);
|
|
|
|
h_byte = getbyte();
|
|
|
|
if (h_byte >= 128) h_byte -= 256;
|
|
|
|
return l | ((arith) h_byte << 24);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRIVATE struct string *getstring();
|
|
|
|
|
|
|
|
/* getarg : read an argument of any type, and check it against "typset"
|
|
|
|
if neccesary. Return a pointer to the argument.
|
|
|
|
*/
|
|
|
|
PRIVATE struct e_args *
|
|
|
|
getarg(typset)
|
|
|
|
{
|
|
|
|
register struct e_args *ap = argentry();
|
|
|
|
register int i = getbyte();
|
|
|
|
#ifdef CHECKING
|
|
|
|
int argtyp;
|
|
|
|
#endif CHECKING
|
|
|
|
|
|
|
|
ap->em_next = 0;
|
|
|
|
switch(i) {
|
|
|
|
default:
|
|
|
|
if (i < sp_fcst0+sp_ncst0 && i >= sp_fcst0) { /* A cst */
|
|
|
|
ap->em_cst = i - sp_zcst0;
|
|
|
|
ap->em_argtype = cst_ptyp;
|
|
|
|
i = sp_cst2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case sp_dlb1: /* Numeric data label encoded in one byte */
|
|
|
|
ap->em_dlb = getbyte();
|
|
|
|
ap->em_noff = 0;
|
|
|
|
ap->em_argtype = nof_ptyp;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case sp_dlb2: /* Numeric data label encoded in two bytes */
|
|
|
|
ap->em_dlb = get16();
|
|
|
|
ap->em_noff = 0;
|
|
|
|
ap->em_argtype = nof_ptyp;
|
|
|
|
#ifdef CHECKING
|
|
|
|
if (ap->em_dlb < 0) {
|
|
|
|
xerror("Illegal data label");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif CHECKING
|
|
|
|
break;
|
|
|
|
|
|
|
|
case sp_ilb1: /* Instruction label encoded in one byte */
|
|
|
|
ap->em_ilb = getbyte();
|
|
|
|
ap->em_argtype = ilb_ptyp;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case sp_ilb2: /* Instruction label encoded in two bytes */
|
|
|
|
ap->em_ilb = get16();
|
|
|
|
ap->em_argtype = ilb_ptyp;
|
|
|
|
#ifdef CHECKING
|
|
|
|
if (ap->em_ilb < 0) {
|
|
|
|
xerror("Illegal instruction label");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif CHECKING
|
|
|
|
break;
|
|
|
|
|
|
|
|
case sp_cst2: /* A cst encoded in two bytes */
|
|
|
|
ap->em_cst = get16();
|
|
|
|
ap->em_argtype = cst_ptyp;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case sp_cst4: /* A cst encoded in four bytes */
|
|
|
|
ap->em_cst = get32();
|
|
|
|
ap->em_argtype = cst_ptyp;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case sp_pnam: /* A procedure name */
|
|
|
|
{
|
|
|
|
register struct string *p;
|
|
|
|
|
|
|
|
p = getstring(1);
|
|
|
|
#ifdef CHECKING
|
|
|
|
if (state & INSTRING) {
|
|
|
|
xerror("Procedure name too long");
|
|
|
|
}
|
|
|
|
#endif CHECKING
|
|
|
|
ap->em_pnam = p->str;
|
|
|
|
ap->em_argtype = pro_ptyp;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case sp_dnam: /* A Non-numeric data label */
|
|
|
|
{
|
|
|
|
register struct string *p;
|
|
|
|
|
|
|
|
p = getstring(1);
|
|
|
|
#ifdef CHECKING
|
|
|
|
if (state & INSTRING) {
|
|
|
|
xerror("Data label too long");
|
|
|
|
}
|
|
|
|
#endif CHECKING
|
|
|
|
ap->em_dnam = p->str;
|
|
|
|
ap->em_soff = 0;
|
|
|
|
ap->em_argtype = sof_ptyp;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case sp_doff: /* A data label + offset */
|
|
|
|
{
|
1987-02-05 18:33:44 +00:00
|
|
|
register struct e_args *ap1;
|
1987-01-06 11:05:35 +00:00
|
|
|
|
|
|
|
ap1 = getarg(lab_ptyp);
|
|
|
|
*ap = *ap1;
|
1987-02-05 18:33:44 +00:00
|
|
|
i_emargs--;
|
|
|
|
ap1 = getarg(cst_ptyp);
|
1987-02-05 18:37:12 +00:00
|
|
|
if (ap->em_argtype == sof_ptyp) { /* non-numeric label */
|
1987-02-05 18:33:44 +00:00
|
|
|
ap->em_soff = ap1->em_cst;
|
1987-01-06 11:05:35 +00:00
|
|
|
}
|
1987-02-05 18:33:44 +00:00
|
|
|
else ap->em_noff = ap1->em_cst;
|
|
|
|
i_emargs--;
|
1987-01-06 11:05:35 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case sp_icon: /* An integer constant */
|
|
|
|
case sp_ucon: /* An unsigned constant */
|
|
|
|
case sp_fcon: /* A floating constant */
|
|
|
|
{
|
|
|
|
register struct string *p;
|
|
|
|
|
1987-02-05 18:33:44 +00:00
|
|
|
ap->em_size = getarg(cst_ptyp)->em_cst;
|
|
|
|
i_emargs--;
|
1987-01-06 11:05:35 +00:00
|
|
|
p = getstring(0);
|
|
|
|
#ifdef CHECKING
|
|
|
|
if (state & INSTRING) {
|
|
|
|
xerror("Numeric constant too long");
|
|
|
|
}
|
|
|
|
#endif CHECKING
|
|
|
|
ap->em_argtype = ptyp(i);
|
|
|
|
ap->em_str = p->str;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case sp_scon: /* A string constant */
|
|
|
|
{
|
|
|
|
register struct string *p;
|
|
|
|
|
|
|
|
p = getstring(0);
|
|
|
|
ap->em_argtype = str_ptyp;
|
|
|
|
ap->em_str = p->str;
|
|
|
|
ap->em_size = p->length;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef CHECKING
|
|
|
|
argtyp = i;
|
|
|
|
if (EM_error) return 0;
|
|
|
|
|
|
|
|
if (i == EOF) {
|
|
|
|
xfatal("Unexpected EOF");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((i -= sp_fspec) < 0 || i >= 16) {
|
|
|
|
xerror("Illegal byte");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((typset & (1 << i)) == 0) {
|
|
|
|
xerror("Bad argument type");
|
|
|
|
}
|
|
|
|
if (argtyp == sp_cend) return 0;
|
|
|
|
#else not CHECKING
|
|
|
|
if (i == sp_cend) return 0;
|
|
|
|
#endif CHECKING
|
|
|
|
return ap;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CHECKING
|
|
|
|
/* checkident: check that a string indeed represents an identifier
|
|
|
|
*/
|
|
|
|
PRIVATE int
|
|
|
|
checkident(s)
|
|
|
|
register struct string *s;
|
|
|
|
{
|
|
|
|
register char *p;
|
|
|
|
register int n;
|
|
|
|
|
|
|
|
p = s->str;
|
|
|
|
if (!isascii(*p) || (!isalpha(*p) && *p != '_')) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
p++;
|
|
|
|
for (n = s->length; --n > 0; p++) {
|
|
|
|
if (!isascii(*p) || (!isalnum(*p) && *p != '_')) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
#endif CHECKING
|
|
|
|
|
|
|
|
/* getstring: read a string from the input, but at most STRSIZ characters
|
|
|
|
of it. The next characters will be read another time around
|
|
|
|
*/
|
|
|
|
/*ARGSUSED*/
|
|
|
|
PRIVATE struct string *
|
|
|
|
getstring(isident)
|
|
|
|
{
|
|
|
|
register char *p;
|
|
|
|
register int n;
|
|
|
|
register struct string *s;
|
|
|
|
|
|
|
|
if (!(state & INSTRING)) { /* Not reading a string yet */
|
|
|
|
struct e_args *ap = getarg(cst_ptyp);
|
|
|
|
/* Read length of string */
|
|
|
|
i_emargs--;
|
|
|
|
strleft = ap->em_cst;
|
|
|
|
#ifdef CHECKING
|
|
|
|
if (strleft < 0) {
|
|
|
|
xerror("Negative length in string");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif CHECKING
|
|
|
|
}
|
|
|
|
|
|
|
|
s = stringentry();
|
|
|
|
|
|
|
|
if (strleft <= STRSIZ) { /* Handle the whole string */
|
|
|
|
n = strleft;
|
|
|
|
state &= ~INSTRING;
|
|
|
|
}
|
|
|
|
else { /* Handle STRSIZ characters of it, and
|
|
|
|
indicate that there is more
|
|
|
|
*/
|
|
|
|
n = STRSIZ;
|
|
|
|
strleft -= STRSIZ;
|
|
|
|
state |= INSTRING;
|
|
|
|
}
|
|
|
|
|
|
|
|
s->length = n;
|
|
|
|
p = s->str;
|
|
|
|
while (--n >= 0) {
|
|
|
|
*p++ = getbyte();
|
|
|
|
}
|
|
|
|
*p++ = '\0';
|
|
|
|
|
|
|
|
#ifdef CHECKING
|
|
|
|
if (isident) {
|
|
|
|
if (!checkident(s)) {
|
|
|
|
xerror("Illegal identifier");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif CHECKING
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* gethead: read the start of an EM-line
|
|
|
|
*/
|
|
|
|
PRIVATE struct e_instr *
|
|
|
|
gethead()
|
|
|
|
{
|
|
|
|
register int i;
|
|
|
|
register struct e_instr *p = &emhead;
|
|
|
|
|
|
|
|
EM_lineno++;
|
|
|
|
|
|
|
|
if ((i = getbyte()) < sp_fmnem+sp_nmnem && i >= sp_fmnem) {
|
|
|
|
/* A mnemonic */
|
|
|
|
p->em_type = EM_MNEM;
|
|
|
|
p->em_opcode = i;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i < sp_fpseu+sp_npseu && i >= sp_fpseu) { /* A pseudo */
|
|
|
|
if (i == ps_mes) {
|
|
|
|
p->em_type = EM_STARTMES;
|
|
|
|
}
|
|
|
|
else p->em_type = EM_PSEU;
|
|
|
|
p->em_opcode = i;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i < sp_filb0+sp_nilb0 && i >= sp_filb0) { /* Instruction label */
|
|
|
|
p->em_type = EM_DEFILB;
|
|
|
|
p->em_deflb = i - sp_filb0;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(i) {
|
|
|
|
case sp_ilb1: /* Instruction label */
|
|
|
|
p->em_type = EM_DEFILB;
|
|
|
|
p->em_deflb = getbyte();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case sp_ilb2: /* Instruction label */
|
|
|
|
p->em_type = EM_DEFILB;
|
|
|
|
p->em_deflb = get16();
|
|
|
|
#ifdef CHECKING
|
|
|
|
if (p->em_deflb < 0) {
|
|
|
|
xerror("Illegal instruction label definition");
|
|
|
|
}
|
|
|
|
#endif CHECKING
|
|
|
|
break;
|
|
|
|
|
|
|
|
case sp_dlb1: /* Numeric data label */
|
|
|
|
p->em_type = EM_DEFDLB;
|
|
|
|
p->em_deflb = getbyte();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case sp_dlb2: /* Numeric data label */
|
|
|
|
p->em_type = EM_DEFDLB;
|
|
|
|
p->em_deflb = get16();
|
|
|
|
#ifdef CHECKING
|
|
|
|
if (p->em_deflb < 0) {
|
|
|
|
xerror("Illegal data label definition");
|
|
|
|
}
|
|
|
|
#endif CHECKING
|
|
|
|
break;
|
|
|
|
|
|
|
|
case sp_dnam: /* Non-numeric data label */
|
|
|
|
{
|
|
|
|
struct string *s;
|
|
|
|
|
|
|
|
p->em_type = EM_DEFDNAM;
|
|
|
|
if (!(s = getstring(1))) {
|
|
|
|
p->em_type = EM_ERROR;
|
|
|
|
}
|
|
|
|
else p->em_defdnam = s->str;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case EOF: /* End of file */
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
default:
|
|
|
|
xerror("Unknown opcode");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|