Initial revision
This commit is contained in:
parent
cb96da9bfa
commit
56a28240ff
7
modules/src/read_em/EM_vars.c
Normal file
7
modules/src/read_em/EM_vars.c
Normal file
|
@ -0,0 +1,7 @@
|
|||
/* $Header$ */
|
||||
|
||||
/* Variables must be declared somewhere ... */
|
||||
|
||||
char *EM_error;
|
||||
char *EM_filename;
|
||||
unsigned int EM_lineno;
|
86
modules/src/read_em/Makefile
Normal file
86
modules/src/read_em/Makefile
Normal file
|
@ -0,0 +1,86 @@
|
|||
EMHOME = ../../..
|
||||
MODULES = $(EMHOME)/modules
|
||||
HDIR = $(MODULES)/h
|
||||
EMHDIR = $(EMHOME)/h
|
||||
INCLUDES = -I$(HDIR) -I$(EMHDIR)
|
||||
CFLAGS = -O $(INCLUDES) -DPRIVATE=static -DEXPORT=
|
||||
INSTALL = $(MODULES)/install
|
||||
COMPARE = $(MODULES)/compare
|
||||
|
||||
TARGETS = libread_emk.a\
|
||||
libread_emkV.a\
|
||||
libread_emeV.a
|
||||
|
||||
SRCFILES = em_comp.h\
|
||||
read_em.c\
|
||||
reade.c\
|
||||
readk.c\
|
||||
mkcalls.c\
|
||||
EM_vars.c
|
||||
|
||||
EV_OFILES = read_emeV.o makecallsV.o EM_vars.o
|
||||
KV_OFILES = read_emkV.o makecallsV.o EM_vars.o
|
||||
K_OFILES = read_emk.o makecalls.o EM_vars.o
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
install: all
|
||||
$(INSTALL) h/em_comp.h
|
||||
$(INSTALL) lib/libread_emk.a
|
||||
$(INSTALL) lib/libread_emkV.a
|
||||
$(INSTALL) lib/libread_emeV.a
|
||||
$(INSTALL) man/read_em.3
|
||||
|
||||
cmp: all
|
||||
$(COMPARE) h/em_comp.h
|
||||
$(COMPARE) lib/libread_emk.a
|
||||
$(COMPARE) lib/libread_emkV.a
|
||||
$(COMPARE) lib/libread_emeV.a
|
||||
$(COMPARE) man/read_em.3
|
||||
|
||||
pr:
|
||||
@pr Makefile m_C_mnem m_C_mnem_na argtype $(SRCFILES)
|
||||
|
||||
opr:
|
||||
make pr | opr
|
||||
|
||||
clean:
|
||||
rm -f *.o *.a C_mnem C_mnem_narg
|
||||
|
||||
libread_emk.a: $(K_OFILES)
|
||||
ar r libread_emk.a $(K_OFILES)
|
||||
-sh -c 'ranlib libread_emk.a'
|
||||
|
||||
libread_emkV.a: $(KV_OFILES)
|
||||
ar r libread_emkV.a $(KV_OFILES)
|
||||
-sh -c 'ranlib libread_emkV.a'
|
||||
|
||||
libread_emeV.a: $(EV_OFILES)
|
||||
ar r libread_emeV.a $(EV_OFILES)
|
||||
-sh -c 'ranlib libread_emeV.a'
|
||||
|
||||
read_emk.o: read_em.c em_comp.h readk.c
|
||||
$(CC) -c $(CFLAGS) -DCOMPACT read_em.c
|
||||
mv read_em.o read_emk.o
|
||||
|
||||
read_emkV.o: read_em.c em_comp.h readk.c
|
||||
$(CC) -c $(CFLAGS) -DCOMPACT -DCHECKING read_em.c
|
||||
mv read_em.o read_emkV.o
|
||||
|
||||
read_emeV.o: read_em.c em_comp.h reade.c
|
||||
$(CC) -c $(CFLAGS) -DCHECKING read_em.c
|
||||
mv read_em.o read_emeV.o
|
||||
|
||||
makecalls.o: C_mnem C_mnem_narg em_comp.h mkcalls.c
|
||||
$(CC) -c $(CFLAGS) mkcalls.c
|
||||
mv mkcalls.o makecalls.o
|
||||
|
||||
makecallsV.o: C_mnem C_mnem_narg em_comp.h mkcalls.c
|
||||
$(CC) -c $(CFLAGS) -DCHECKING mkcalls.c
|
||||
mv mkcalls.o makecallsV.o
|
||||
|
||||
C_mnem: m_C_mnem argtype
|
||||
sh m_C_mnem > C_mnem
|
||||
|
||||
C_mnem_narg: m_C_mnem_na argtype
|
||||
sh m_C_mnem_na > C_mnem_narg
|
14
modules/src/read_em/argtype
Executable file
14
modules/src/read_em/argtype
Executable file
|
@ -0,0 +1,14 @@
|
|||
: argtype lists all em mnemonics that have an argument type equal to
|
||||
: one of the letters specified in the argument
|
||||
case x$# in
|
||||
x2)
|
||||
;;
|
||||
x*) echo "Usage: $0 argtypes <em_table>" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
ed - $2 << A
|
||||
1,/^\$/d
|
||||
1,/^\$/d
|
||||
1,/^\$/g/^\(...\) [$1].*/s//\\1/gp
|
||||
A
|
64
modules/src/read_em/em_comp.h
Normal file
64
modules/src/read_em/em_comp.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
/* $Header$ */
|
||||
|
||||
struct e_instr {
|
||||
int em_type; /* Type of this instr */
|
||||
#define EM_MNEM 256 /* A machine instruction */
|
||||
#define EM_PSEU 257 /* A pseudo */
|
||||
#define EM_STARTMES 258 /* Start of a MES pseudo */
|
||||
#define EM_MESARG 259 /* A member in a MES list */
|
||||
#define EM_ENDMES 260 /* End of a MES pseudo */
|
||||
#define EM_DEFILB 261 /* An instruction label definition */
|
||||
#define EM_DEFDLB 262 /* A numeric data label definition */
|
||||
#define EM_DEFDNAM 263 /* A non-numeric data label def */
|
||||
#define EM_ERROR 264 /* Recoverable error */
|
||||
#define EM_FATAL 265 /* Unrecoverable error */
|
||||
union {
|
||||
struct {
|
||||
int emus_opcode; /* Opcode of instruction */
|
||||
struct e_args *emus_args; /* Arguments of instruction */
|
||||
} emu_mp;
|
||||
label emu_deflb; /* Numeric label definition */
|
||||
char *emu_defdnam; /* Non-numeric label definition */
|
||||
struct e_args *emu_arg; /* For an argument */
|
||||
} em_i;
|
||||
#define em_opcode em_i.emu_mp.emus_opcode
|
||||
#define em_args em_i.emu_mp.emus_args
|
||||
#define em_deflb em_i.emu_deflb
|
||||
#define em_defdnam em_i.emu_defdnam
|
||||
#define em_arg em_i.emu_arg
|
||||
};
|
||||
|
||||
struct e_args {
|
||||
struct e_args *em_next; /* Next argument */
|
||||
short em_argtype; /* Type of this argument */
|
||||
union {
|
||||
arith emu_cst; /* A constant */
|
||||
label emu_ilb; /* An instruction label */
|
||||
char *emu_pnam; /* A procedure name (not including '$') */
|
||||
struct {
|
||||
label emus_dlb;
|
||||
arith emus_noff;
|
||||
} emu_ndlb; /* Numeric data label + offset */
|
||||
struct {
|
||||
char *emus_dnam;
|
||||
arith emus_soff;
|
||||
} emu_sdlb; /* String data label + offset */
|
||||
struct {
|
||||
char *emus_str;
|
||||
arith emus_size;
|
||||
} emu_con; /* An scon, icon, ucon or fcon */
|
||||
} em_value;
|
||||
#define em_cst em_value.emu_cst
|
||||
#define em_ilb em_value.emu_ilb
|
||||
#define em_pnam em_value.emu_pnam
|
||||
#define em_dlb em_value.emu_ndlb.emus_dlb
|
||||
#define em_noff em_value.emu_ndlb.emus_noff
|
||||
#define em_dnam em_value.emu_sdlb.emus_dnam
|
||||
#define em_soff em_value.emu_sdlb.emus_soff
|
||||
#define em_str em_value.emu_con.emus_str
|
||||
#define em_size em_value.emu_con.emus_size
|
||||
};
|
||||
|
||||
extern char *EM_error;
|
||||
extern unsigned int EM_lineno;
|
||||
extern char *EM_filename;
|
91
modules/src/read_em/m_C_mnem
Executable file
91
modules/src/read_em/m_C_mnem
Executable file
|
@ -0,0 +1,91 @@
|
|||
EM_TABLE=../../../etc/em_table
|
||||
echo "switch(opcode) {"
|
||||
for i in - cdflnorswz p b
|
||||
do
|
||||
list=`./argtype $i $EM_TABLE`
|
||||
case $i in
|
||||
-) args='()'
|
||||
echo "/* no arguments */"
|
||||
;;
|
||||
cdflnorswz)
|
||||
args='(arg->em_cst)'
|
||||
echo "/* one integer constant argument */"
|
||||
;;
|
||||
p)
|
||||
args='(arg->em_pnam)'
|
||||
echo "/* a procedure name argument */"
|
||||
;;
|
||||
b)
|
||||
|
||||
: Grumbl, an instruction label as argument is encoded in a sp_cst2
|
||||
|
||||
args='((label) (arg->em_cst))'
|
||||
echo "/* An instruction label argument */"
|
||||
;;
|
||||
esac
|
||||
for i in $list
|
||||
do
|
||||
cat << EOF
|
||||
case op_$i:
|
||||
C_$i$args;
|
||||
break;
|
||||
EOF
|
||||
done
|
||||
done
|
||||
list=`./argtype g $EM_TABLE`
|
||||
cat << 'EOF'
|
||||
default:
|
||||
/* a "g" argument */
|
||||
if (arg->em_argtype == nof_ptyp) {
|
||||
switch(opcode) {
|
||||
default:
|
||||
EM_error = "Illegal mnemonic";
|
||||
break;
|
||||
EOF
|
||||
for i in $list
|
||||
do
|
||||
cat << EOF
|
||||
case op_$i:
|
||||
C_${i}_dlb(arg->em_dlb, arg->em_noff);
|
||||
break;
|
||||
EOF
|
||||
done
|
||||
cat << 'EOF'
|
||||
}
|
||||
}
|
||||
else if (arg->em_argtype == sof_ptyp) {
|
||||
switch(opcode) {
|
||||
default:
|
||||
EM_error = "Illegal mnemonic";
|
||||
break;
|
||||
EOF
|
||||
for i in $list
|
||||
do
|
||||
cat << EOF
|
||||
case op_$i:
|
||||
C_${i}_dnam(arg->em_dnam, arg->em_soff);
|
||||
break;
|
||||
EOF
|
||||
done
|
||||
cat << 'EOF'
|
||||
}
|
||||
}
|
||||
else /*argtype == cst_ptyp */ {
|
||||
switch(opcode) {
|
||||
default:
|
||||
EM_error = "Illegal mnemonic";
|
||||
break;
|
||||
EOF
|
||||
for i in $list
|
||||
do
|
||||
cat << EOF
|
||||
case op_$i:
|
||||
C_$i(arg->em_cst);
|
||||
break;
|
||||
EOF
|
||||
done
|
||||
cat << 'EOF'
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
15
modules/src/read_em/m_C_mnem_na
Executable file
15
modules/src/read_em/m_C_mnem_na
Executable file
|
@ -0,0 +1,15 @@
|
|||
EM_TABLE=../../../etc/em_table
|
||||
list=`./argtype w $EM_TABLE`
|
||||
echo "switch(opcode) {"
|
||||
for i in $list
|
||||
do
|
||||
cat << EOF
|
||||
case op_$i:
|
||||
C_${i}_narg();
|
||||
break;
|
||||
EOF
|
||||
done
|
||||
cat << EOF
|
||||
default: EM_error = "Illegal mnemonic";
|
||||
}
|
||||
EOF
|
467
modules/src/read_em/mkcalls.c
Normal file
467
modules/src/read_em/mkcalls.c
Normal file
|
@ -0,0 +1,467 @@
|
|||
/* makecalls: expand a datastructure as delivered by "EM_getline"
|
||||
into calls to the procedural interface.
|
||||
Exported routine:
|
||||
EM_mkcalls
|
||||
*/
|
||||
|
||||
#include <em_spec.h>
|
||||
#include <em_mnem.h>
|
||||
#include <em_pseu.h>
|
||||
#include <em_flag.h>
|
||||
#include "em_ptyp.h"
|
||||
#include <em.h>
|
||||
#include "em_comp.h"
|
||||
#include <assert.h>
|
||||
|
||||
extern char em_flag[]; /* One per EM instruction: indicates parameter kind */
|
||||
extern short em_ptyp[]; /* One per parameter kind: indicates parameter type */
|
||||
|
||||
static int listtype = 0; /* indicates pseudo when generating code for
|
||||
variable length argument lists
|
||||
(only for MES)
|
||||
*/
|
||||
|
||||
#ifdef CHECKING
|
||||
/* c_getarg: Check the argument indicated by "args".
|
||||
The argument must be of a type allowed by "typset".
|
||||
Return a pointer to the next argument.
|
||||
*/
|
||||
PRIVATE struct e_args *
|
||||
c_getarg(args, typset)
|
||||
register struct e_args *args;
|
||||
{
|
||||
|
||||
if (((!typset) && args) ||
|
||||
((!args) && typset)) {
|
||||
/* End of arguments expected, but there are more, or
|
||||
an argument expected, but there is none
|
||||
*/
|
||||
EM_error = "Illegal number of parameters";
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!args) return 0;
|
||||
if (!(args->em_argtype & typset)) {
|
||||
/* Type error */
|
||||
EM_error = "Illegal parameter type";
|
||||
}
|
||||
|
||||
return args->em_next;
|
||||
}
|
||||
#else not CHECKING
|
||||
#define c_getarg(arg, x) ((arg) ? (arg)->em_next : (arg))
|
||||
#endif CHECKING
|
||||
|
||||
/* EM_doinstr: An EM instruction
|
||||
*/
|
||||
PRIVATE
|
||||
EM_doinstr(opcode, arg)
|
||||
register struct e_args *arg;
|
||||
{
|
||||
register int parametertype; /* parametertype of the instruction */
|
||||
register struct e_args *args;
|
||||
|
||||
parametertype = em_flag[opcode-sp_fmnem] & EM_PAR;
|
||||
#ifdef CHECKING
|
||||
if (parametertype != PAR_NO && parametertype != PAR_W) {
|
||||
if (!arg) {
|
||||
EM_error = "Illegal number of parameters";
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif CHECKING
|
||||
switch(parametertype) {
|
||||
case PAR_NO:
|
||||
break;
|
||||
default:
|
||||
args = c_getarg(arg, em_ptyp[parametertype]);
|
||||
args = c_getarg(args, 0);
|
||||
break;
|
||||
case PAR_W:
|
||||
if (arg) {
|
||||
args = c_getarg(arg, cst_ptyp);
|
||||
args = c_getarg(args, 0);
|
||||
}
|
||||
else {
|
||||
#include "C_mnem_narg"
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#include "C_mnem"
|
||||
}
|
||||
|
||||
PRIVATE
|
||||
EM_dopseudo(opcode, args)
|
||||
register struct e_args *args;
|
||||
{
|
||||
register struct e_args *arg;
|
||||
|
||||
switch(opcode) {
|
||||
case ps_exc: {
|
||||
register struct e_args *args2;
|
||||
|
||||
arg = c_getarg(args, cst_ptyp);
|
||||
args2 = c_getarg(arg, cst_ptyp);
|
||||
args2 = c_getarg(args2, 0);
|
||||
C_exc(args->em_cst, arg->em_cst);
|
||||
break;
|
||||
}
|
||||
case ps_hol: {
|
||||
register struct e_args *args2, *args3;
|
||||
|
||||
arg = c_getarg(args, cst_ptyp);
|
||||
args2 = c_getarg(arg, arg_ptyp);
|
||||
args3 = c_getarg(args2, cst_ptyp);
|
||||
args3 = c_getarg(args3, 0);
|
||||
switch(arg->em_argtype) {
|
||||
case cst_ptyp:
|
||||
C_hol_cst(args->em_cst,
|
||||
arg->em_cst,
|
||||
args2->em_cst);
|
||||
break;
|
||||
case ico_ptyp:
|
||||
C_hol_icon(args->em_cst,
|
||||
arg->em_str,
|
||||
arg->em_size,
|
||||
args2->em_cst);
|
||||
break;
|
||||
case uco_ptyp:
|
||||
C_hol_ucon(args->em_cst,
|
||||
arg->em_str,
|
||||
arg->em_size,
|
||||
args2->em_cst);
|
||||
break;
|
||||
case fco_ptyp:
|
||||
C_hol_fcon(args->em_cst,
|
||||
arg->em_str,
|
||||
arg->em_size,
|
||||
args2->em_cst);
|
||||
break;
|
||||
case sof_ptyp:
|
||||
C_hol_dnam(args->em_cst,
|
||||
arg->em_dnam,
|
||||
arg->em_soff,
|
||||
args2->em_cst);
|
||||
break;
|
||||
case nof_ptyp:
|
||||
C_hol_dlb(args->em_cst,
|
||||
arg->em_dlb,
|
||||
arg->em_noff,
|
||||
args2->em_cst);
|
||||
break;
|
||||
case ilb_ptyp:
|
||||
C_hol_ilb(args->em_cst,
|
||||
arg->em_ilb,
|
||||
args2->em_cst);
|
||||
break;
|
||||
case pro_ptyp:
|
||||
C_hol_pnam(args->em_cst,
|
||||
arg->em_pnam,
|
||||
args2->em_cst);
|
||||
break;
|
||||
default:
|
||||
EM_error = "Illegal parameter type";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ps_bss: {
|
||||
register struct e_args *args2, *args3;
|
||||
|
||||
arg = c_getarg(args, cst_ptyp);
|
||||
args2 = c_getarg(arg, arg_ptyp);
|
||||
args3 = c_getarg(args2, cst_ptyp);
|
||||
args3 = c_getarg(args3, 0);
|
||||
switch(arg->em_argtype) {
|
||||
case cst_ptyp:
|
||||
C_bss_cst(args->em_cst,
|
||||
arg->em_cst,
|
||||
args2->em_cst);
|
||||
break;
|
||||
case ico_ptyp:
|
||||
C_bss_icon(args->em_cst,
|
||||
arg->em_str,
|
||||
arg->em_size,
|
||||
args2->em_cst);
|
||||
break;
|
||||
case uco_ptyp:
|
||||
C_bss_ucon(args->em_cst,
|
||||
arg->em_str,
|
||||
arg->em_size,
|
||||
args2->em_cst);
|
||||
break;
|
||||
case fco_ptyp:
|
||||
C_bss_fcon(args->em_cst,
|
||||
arg->em_str,
|
||||
arg->em_size,
|
||||
args2->em_cst);
|
||||
break;
|
||||
case sof_ptyp:
|
||||
C_bss_dnam(args->em_cst,
|
||||
arg->em_dnam,
|
||||
arg->em_soff,
|
||||
args2->em_cst);
|
||||
break;
|
||||
case nof_ptyp:
|
||||
C_bss_dlb(args->em_cst,
|
||||
arg->em_dlb,
|
||||
arg->em_noff,
|
||||
args2->em_cst);
|
||||
break;
|
||||
case ilb_ptyp:
|
||||
C_bss_ilb(args->em_cst,
|
||||
arg->em_ilb,
|
||||
args2->em_cst);
|
||||
break;
|
||||
case pro_ptyp:
|
||||
C_bss_pnam(args->em_cst,
|
||||
arg->em_pnam,
|
||||
args2->em_cst);
|
||||
break;
|
||||
default:
|
||||
EM_error = "Illegal parameter type";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ps_end:
|
||||
if (args) {
|
||||
arg = c_getarg(args, cst_ptyp);
|
||||
arg = c_getarg(arg, 0);
|
||||
C_end(args->em_cst);
|
||||
break;
|
||||
}
|
||||
C_end_narg();
|
||||
break;
|
||||
case ps_exa:
|
||||
case ps_ina:
|
||||
arg = c_getarg(args, lab_ptyp);
|
||||
arg = c_getarg(arg, 0);
|
||||
if (args->em_argtype == nof_ptyp) {
|
||||
if (opcode == ps_exa) {
|
||||
C_exa_dlb(args->em_dlb);
|
||||
}
|
||||
else C_ina_dlb(args->em_dlb);
|
||||
break;
|
||||
}
|
||||
if (opcode == ps_exa) {
|
||||
C_exa_dnam(args->em_dnam);
|
||||
}
|
||||
else C_ina_dnam(args->em_dnam);
|
||||
break;
|
||||
case ps_exp:
|
||||
case ps_inp:
|
||||
arg = c_getarg(args, pro_ptyp);
|
||||
arg = c_getarg(arg, 0);
|
||||
if (opcode == ps_exp) {
|
||||
C_exp(args->em_pnam);
|
||||
}
|
||||
else C_inp(args->em_pnam);
|
||||
break;
|
||||
case ps_pro:
|
||||
arg = c_getarg(args, pro_ptyp);
|
||||
if (arg) {
|
||||
struct e_args *args2;
|
||||
|
||||
args2 = c_getarg(arg, cst_ptyp);
|
||||
args2 = c_getarg(args2, 0);
|
||||
C_pro(args->em_pnam, arg->em_cst);
|
||||
}
|
||||
else C_pro_narg(args->em_pnam);
|
||||
break;
|
||||
case ps_con:
|
||||
arg = c_getarg(args, val_ptyp);
|
||||
arg = c_getarg(arg, 0);
|
||||
switch(args->em_argtype) {
|
||||
case ilb_ptyp:
|
||||
C_con_ilb(args->em_ilb);
|
||||
break;
|
||||
case nof_ptyp:
|
||||
C_con_dlb(args->em_dlb, args->em_noff);
|
||||
break;
|
||||
case sof_ptyp:
|
||||
C_con_dnam(args->em_dnam, args->em_soff);
|
||||
break;
|
||||
case cst_ptyp:
|
||||
C_con_cst(args->em_cst);
|
||||
break;
|
||||
case pro_ptyp:
|
||||
C_con_pnam(args->em_pnam);
|
||||
break;
|
||||
case str_ptyp:
|
||||
C_con_scon(args->em_str, args->em_size);
|
||||
break;
|
||||
case ico_ptyp:
|
||||
C_con_icon(args->em_str, args->em_size);
|
||||
break;
|
||||
case uco_ptyp:
|
||||
C_con_ucon(args->em_str, args->em_size);
|
||||
break;
|
||||
case fco_ptyp:
|
||||
C_con_fcon(args->em_str, args->em_size);
|
||||
break;
|
||||
default:
|
||||
EM_error = "Illegal argument type";
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case ps_rom:
|
||||
arg = c_getarg(args, val_ptyp);
|
||||
arg = c_getarg(arg, 0);
|
||||
switch(args->em_argtype) {
|
||||
case ilb_ptyp:
|
||||
C_rom_ilb(args->em_ilb);
|
||||
break;
|
||||
case nof_ptyp:
|
||||
C_rom_dlb(args->em_dlb, args->em_noff);
|
||||
break;
|
||||
case sof_ptyp:
|
||||
C_rom_dnam(args->em_dnam, args->em_soff);
|
||||
break;
|
||||
case cst_ptyp:
|
||||
C_rom_cst(args->em_cst);
|
||||
break;
|
||||
case pro_ptyp:
|
||||
C_rom_pnam(args->em_pnam);
|
||||
break;
|
||||
case str_ptyp:
|
||||
C_rom_scon(args->em_str, args->em_size);
|
||||
break;
|
||||
case ico_ptyp:
|
||||
C_rom_icon(args->em_str, args->em_size);
|
||||
break;
|
||||
case uco_ptyp:
|
||||
C_rom_ucon(args->em_str, args->em_size);
|
||||
break;
|
||||
case fco_ptyp:
|
||||
C_rom_fcon(args->em_str, args->em_size);
|
||||
break;
|
||||
default:
|
||||
EM_error = "Illegal argument type";
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
EM_error = "Illegal pseudo instruction";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PRIVATE
|
||||
EM_docon(args)
|
||||
register struct e_args *args;
|
||||
{
|
||||
register struct e_args *arg;
|
||||
|
||||
arg = c_getarg(args, val_ptyp);
|
||||
arg = c_getarg(arg, 0);
|
||||
switch(args->em_argtype) {
|
||||
case ilb_ptyp:
|
||||
C_ilb(args->em_ilb);
|
||||
break;
|
||||
case nof_ptyp:
|
||||
C_dlb(args->em_dlb, args->em_noff);
|
||||
break;
|
||||
case sof_ptyp:
|
||||
C_dnam(args->em_dnam, args->em_soff);
|
||||
break;
|
||||
case cst_ptyp:
|
||||
C_cst(args->em_cst);
|
||||
break;
|
||||
case pro_ptyp:
|
||||
C_pnam(args->em_pnam);
|
||||
break;
|
||||
case str_ptyp:
|
||||
C_scon(args->em_str, args->em_size);
|
||||
break;
|
||||
case ico_ptyp:
|
||||
C_icon(args->em_str, args->em_size);
|
||||
break;
|
||||
case uco_ptyp:
|
||||
C_ucon(args->em_str, args->em_size);
|
||||
break;
|
||||
case fco_ptyp:
|
||||
C_fcon(args->em_str, args->em_size);
|
||||
break;
|
||||
default:
|
||||
EM_error = "Illegal argument type";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PRIVATE
|
||||
EM_dostartmes(args)
|
||||
register struct e_args *args;
|
||||
{
|
||||
register struct e_args *arg;
|
||||
|
||||
if (listtype) {
|
||||
EM_error = "Message not ended";
|
||||
return;
|
||||
}
|
||||
arg = c_getarg(args, cst_ptyp);
|
||||
arg = c_getarg(arg, 0);
|
||||
C_mes_begin(args->em_cst);
|
||||
listtype = ps_mes;
|
||||
}
|
||||
|
||||
EXPORT int
|
||||
EM_mkcalls(line)
|
||||
register struct e_instr *line;
|
||||
{
|
||||
|
||||
#ifdef CHECKING
|
||||
if (listtype && line->em_type != EM_MESARG && line->em_type != EM_ENDMES) {
|
||||
EM_error = "Message not ended";
|
||||
return 0;
|
||||
}
|
||||
#endif CHECKING
|
||||
EM_error = 0;
|
||||
switch(line->em_type) {
|
||||
default:
|
||||
EM_error = "Illegal EM line";
|
||||
break;
|
||||
case EM_MNEM:
|
||||
/* normal instruction */
|
||||
EM_doinstr(line->em_opcode, line->em_args);
|
||||
break;
|
||||
case EM_DEFILB:
|
||||
/* defining occurrence of an instruction label */
|
||||
C_df_ilb(line->em_deflb);
|
||||
break;
|
||||
case EM_DEFDLB:
|
||||
/* defining occurrence of a global data label */
|
||||
C_df_dlb(line->em_deflb);
|
||||
break;
|
||||
case EM_DEFDNAM:
|
||||
/* defining occurrence of a non-numeric data label */
|
||||
C_df_dnam(line->em_defdnam);
|
||||
break;
|
||||
case EM_PSEU:
|
||||
/* pseudo */
|
||||
EM_dopseudo(line->em_opcode, line->em_args);
|
||||
break;
|
||||
case EM_STARTMES:
|
||||
/* start of a MES pseudo */
|
||||
EM_dostartmes(line->em_arg);
|
||||
break;
|
||||
case EM_MESARG:
|
||||
case EM_ENDMES:
|
||||
#ifdef CHECKING
|
||||
if (!listtype) {
|
||||
EM_error = "Message not started";
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (line->em_type == EM_MESARG) {
|
||||
EM_docon(line->em_args);
|
||||
break;
|
||||
}
|
||||
C_mes_end();
|
||||
listtype = 0;
|
||||
break;
|
||||
}
|
||||
if (EM_error) return 0;
|
||||
return 1;
|
||||
}
|
281
modules/src/read_em/read_em.3
Normal file
281
modules/src/read_em/read_em.3
Normal file
|
@ -0,0 +1,281 @@
|
|||
.TH READ_EM 3ACK "March 17, 1986"
|
||||
.SH NAME
|
||||
EM_open, EM_getinstr, EM_close,
|
||||
EM_mkcalls\ \-\ a module to read EM assembly code
|
||||
.SH SYNOPSIS
|
||||
.B #include <em_spec.h>
|
||||
.br
|
||||
.B #include <em_mnem.h>
|
||||
.br
|
||||
.B #include <em_pseu.h>
|
||||
.br
|
||||
.B #include <em_flag.h>
|
||||
.br
|
||||
.B #include <em_ptyp.h>
|
||||
.br
|
||||
.B #include <em.h>
|
||||
.br
|
||||
.B #include <em_comp.h>
|
||||
.PP
|
||||
.B int EM_open(filename)
|
||||
.br
|
||||
.B EM_close()
|
||||
.br
|
||||
.B char *filename;
|
||||
.PP
|
||||
.B struct e_instr *EM_getinstr()
|
||||
.PP
|
||||
.B int EM_mkcalls(instr)
|
||||
.br
|
||||
.B struct e_instr *instr;
|
||||
.PP
|
||||
.B char *EM_error;
|
||||
.PP
|
||||
.B unsigned int EM_lineno;
|
||||
.PP
|
||||
.B char *EM_filename;
|
||||
.SH DESCRIPTION
|
||||
This package provides routines to read EM assembly code.
|
||||
The object is to simplify the program
|
||||
writer's task of reading EM assembly code,
|
||||
either in compact or human-readable form.
|
||||
.PP
|
||||
\fIEM_open\fR must be called as initializer of the package.
|
||||
If \fIfilename\fR is a null pointer, reading is done from standard input,
|
||||
otherwise it is done from the file \fIfilename\fR.
|
||||
\fIEM_open\fR returns 1 on success and 0 on failure
|
||||
with an error message in \fIEM_error\fR.
|
||||
\fIEM_close\fR must be called after all other calls to this package.
|
||||
.PP
|
||||
\fIEM_getinstr\fR reads an EM instruction, and
|
||||
returns it as a pointer to a structure having the following
|
||||
layout:
|
||||
.br
|
||||
.PP
|
||||
.ta \w'struct'u +\w'struct e_instr *\ \ \ \ \ \ \ \ \ 'u +\w'em_argtype\ \ \ \ \ \ 'u
|
||||
.nf
|
||||
struct e_instr {
|
||||
int em_type; /* Type of this instruction */
|
||||
union {
|
||||
struct {
|
||||
int emus_opcode; /* Opcode of instruction */
|
||||
struct e_args *emus_args; /* Arguments of instruction */
|
||||
} emu_mp;
|
||||
label emu_deflb; /* Numeric label definition */
|
||||
char *emu_defdnam; /* Non-numeric label definition */
|
||||
struct e_args *emu_arg; /* For a message argument */
|
||||
} em_i;
|
||||
#define em_opcode \kaem_i.emu_mp.emus_opcode
|
||||
#define em_args\h'|\nau'em_i.emu_mp.emus_args
|
||||
#define em_deflb\h'|\nau'em_i.emu_deflb
|
||||
#define em_defdnam\h'|\nau'em_i.emu_defdnam
|
||||
#define em_arg\h'|\nau'em_i.emu_arg
|
||||
};
|
||||
.fi
|
||||
.PP
|
||||
Possible arguments to the EM instruction read are supplied in a linked list
|
||||
of structures:
|
||||
.PP
|
||||
.nf
|
||||
struct e_args {
|
||||
struct e_args *em_next; /* Next argument */
|
||||
short em_argtype; /* Type of this argument */
|
||||
union {
|
||||
arith emu_cst; /* A constant */
|
||||
label emu_ilb; /* An instruction label */
|
||||
char *emu_pnam; /* A procedure name (not including '$') */
|
||||
struct {
|
||||
label emus_dlb;
|
||||
arith emus_noff;
|
||||
} emu_ndlb; /* Numeric data label + offset */
|
||||
struct {
|
||||
char *emus_dnam;
|
||||
arith emus_soff;
|
||||
} emu_sdlb; /* String data label + offset */
|
||||
struct {
|
||||
char *emus_str;
|
||||
arith emus_size;
|
||||
} emu_con; /* An scon, icon, ucon or fcon */
|
||||
} em_value;
|
||||
#define em_cst\h'|\nau'em_value.emu_cst
|
||||
#define em_ilb\h'|\nau'em_value.emu_ilb
|
||||
#define em_pnam\h'|\nau'em_value.emu_pnam
|
||||
#define em_dlb\h'|\nau'em_value.emu_ndlb.emus_dlb
|
||||
#define em_noff\h'|\nau'em_value.emu_ndlb.emus_noff
|
||||
#define em_dnam\h'|\nau'em_value.emu_sdlb.emus_dnam
|
||||
#define em_soff\h'|\nau'em_value.emu_sdlb.emus_soff
|
||||
#define em_str\h'|\nau'em_value.emu_con.emus_str
|
||||
#define em_size\h'|\nau'em_value.emu_con.emus_size
|
||||
};
|
||||
.fi
|
||||
.PP
|
||||
The named types \fBarith\fR and \fBlabel\fR refer to types on the local machine
|
||||
that are suitable for doing arithmetic and storing EM numeric labels
|
||||
respectively.
|
||||
Common definitions are \fBlong\fR for \fBarith\fR and \fBunsigned int\fR for
|
||||
\fBlabel\fR.
|
||||
.PP
|
||||
The \fIe_instr\fR structure consists of the fields
|
||||
\fIem_type\fR, containing the type of this \fIe_instr\fR, and
|
||||
\fIem_i\fR, containing its value of this \fIe_instr\fR.
|
||||
.PP
|
||||
The possible values of
|
||||
\fIem_type\fR, defined in <em_code.h>, are summarized below:
|
||||
.br
|
||||
.ta \w'EM_STARTMES\ \ \ 'u +\w'em_defdnam\ \ \ 'u
|
||||
.di xx
|
||||
\ka
|
||||
.br
|
||||
.di
|
||||
.IP "Value Selector" \nau
|
||||
Meaning
|
||||
.IP "EM_MNEM em_opcode" \nau
|
||||
an EM machine instruction.
|
||||
.br
|
||||
.PD 0
|
||||
.IP " em_args" \nau
|
||||
The \fIem_opcode\fR field
|
||||
contains the opcode of the instruction, and \fIem_args\fR may indicate
|
||||
arguments.
|
||||
.IP "EM_PSEU em_opcode" \nau
|
||||
an EM pseudo instruction.
|
||||
.IP " em_args" \nau
|
||||
The \fIem_opcode\fR field
|
||||
contains the opcode, and \fIem_args\fR may indicate arguments.
|
||||
As consecutive CON-pseudos are allocated consecutively, a CON delivered by
|
||||
\fIEM_getinstr\fR has exactly one argument.
|
||||
If the CON-pseudo read has more, they are delivered as separate CON's.
|
||||
The same holds for ROM-pseudos.
|
||||
Also, if the length of a string constant exceeds 256 characters, it will be
|
||||
delivered as several CON's or ROM's.
|
||||
.IP "EM_STARTMES em_arg" \nau
|
||||
the start of a MES pseudo.
|
||||
.br
|
||||
There is one argument: the message number.
|
||||
The other arguments, if any, are delivered as separate EM_MESARG's.
|
||||
.IP "EM_MESARG em_arg" \nau
|
||||
an argument of a MES pseudo.
|
||||
.IP "EM_ENDMES none" \nau
|
||||
the end of a MES pseudo.
|
||||
.IP "EM_DEFILB em_deflb" \nau
|
||||
an instruction label definition.
|
||||
.br
|
||||
The field \fIem_deflb\fR contains the label (instruction labels are always
|
||||
numeric).
|
||||
.IP "EM_DEFDLB em_deflb" \nau
|
||||
a numeric data label definition.
|
||||
.br
|
||||
The field \fIem_deflb\fR contains the label.
|
||||
.IP "EM_DEFDNAM em_defdnam" \nau
|
||||
a non-numeric data label definition.
|
||||
.br
|
||||
The field \fIem_defdnam\fR contains the label.
|
||||
.IP "EM_ERROR none" \nau
|
||||
an error in the input.
|
||||
.br
|
||||
\fIEM_error\fR
|
||||
contains an error message.
|
||||
.IP "EM_FATAL none" \nau
|
||||
a fatal error.
|
||||
.br
|
||||
\fIEM_error\fR contains an
|
||||
error message.
|
||||
.PD
|
||||
.PP
|
||||
The \fIe_args\fR structure consists of the fields
|
||||
\fIem_next\fR, containing a pointer to the next argument or null,
|
||||
the field \fIem_argtype\fR, containing the type of this argument, and
|
||||
the field \fIem_value\fR, containing the value of the argument.
|
||||
The possible values of \fIem_argtype\fR, defined in <em_ptyp.h>,
|
||||
are summarized below:
|
||||
.br
|
||||
.ta \w'dlb_ptyp\ \ \ \ 'u +\w'em_opcode\ \ \ 'u
|
||||
.di xx
|
||||
\ka
|
||||
.br
|
||||
.di
|
||||
.IP "Value Selector" \nau
|
||||
Meaning
|
||||
.IP "ilb_ptyp em_ilb" \nau
|
||||
an instruction label.
|
||||
.PD 0
|
||||
.IP "nof_ptyp em_dlb" \nau
|
||||
an offset from a numeric data label.
|
||||
.IP " em_noff" \nau
|
||||
The
|
||||
\fIem_noff\fR field contains the offset and the
|
||||
\fIem_dlb\fR field contains the label.
|
||||
.IP "sof_ptyp em_dnam" \nau
|
||||
an offset from a non-numeric data label.
|
||||
.IP " em_soff" \nau
|
||||
The \fIem_soff\fR field contains the offset and the \fIem_dnam\fR field
|
||||
contains the label, represented as a string.
|
||||
.IP "cst_ptyp em_cst" \nau
|
||||
a numeric constant.
|
||||
.IP "pro_ptyp em_pnam" \nau
|
||||
a procedure name, not including the '$',
|
||||
represented as a string.
|
||||
.IP "str_ptyp em_str" \nau
|
||||
a string constant.
|
||||
.IP " em_size" \nau
|
||||
The string is found in \fIem_str\fR, represented as a row of bytes, of
|
||||
length \fIem_size\fR.
|
||||
.IP "ico_ptyp em_str" \nau
|
||||
an integer constant.
|
||||
.IP " em_size" \nau
|
||||
A string representation of the constant is found in \fIem_str\fR.
|
||||
It has size \fIem_size\fR bytes on the target machine.
|
||||
.IP "uco_ptyp em_str" \nau
|
||||
an unsigned constant.
|
||||
.IP " em_size" \nau
|
||||
A string representation of the constant is found in \fIem_str\fR.
|
||||
It has size \fIem_size\fR bytes on the target machine.
|
||||
.IP "fco_ptyp em_str" \nau
|
||||
a floating constant.
|
||||
.IP " em_size" \nau
|
||||
A string representation of the constant is found in \fIem_str\fR.
|
||||
It has size \fIem_size\fR bytes on the target machine.
|
||||
.PD
|
||||
.PP
|
||||
The routine \fIEM_mkcalls\fR "translates" the EM instruction indicated
|
||||
by \fIinstr\fR
|
||||
into calls of the procedural interface defined in \fIem_code\fR(3L).
|
||||
It returns 1 if it succeeds, 0 if it fails for some reason. The
|
||||
reason can then be found in \fIEM_error\fR.
|
||||
.PP
|
||||
\fIEM_lineno\fR contains the line number of the last line read by
|
||||
\fIEM_getinstr\fR.
|
||||
.PP
|
||||
\fIEM_filename\fR contains a filename. It usually contains the value
|
||||
given as parameter to \fIEM_open\fR, but may have a different value, when
|
||||
the input was the result of some preprocessing.
|
||||
.PP
|
||||
.SH FILES
|
||||
.nf
|
||||
~em/modules/h/em.h
|
||||
~em/modules/h/em_ptyp.h
|
||||
~em/modules/h/em_comp.h
|
||||
~em/modules/lib/libread_emk.a: non-checking library for reading compact EM code
|
||||
~em/modules/lib/libread_emkV.a: checking library for reading compact EM code
|
||||
~em/modules/lib/libread_emeV.a: checking library for reading human-readable EM code
|
||||
.fi
|
||||
.SH MODULES
|
||||
em_code(3), string(3), system(3), ~em/lib/em_data.a
|
||||
.SH "SEE ALSO"
|
||||
em_code(3)
|
||||
.br
|
||||
A.S. Tanenbaum, H. v Staveren, E.G. Keizer, J.W. Stevenson, "\fBDescription
|
||||
of a Machine Architecture for use with Block Structured Languages\fR",
|
||||
Informatica Rapport IR-81, Vrije Universiteit, Amsterdam, 1983.
|
||||
.SH DIAGNOSTICS
|
||||
\fIEM_getinstr\fR returns a null pointer on end of file.
|
||||
.SH REMARKS
|
||||
All information must be considered to be contained in a static area so it
|
||||
must be copied to be saved.
|
||||
.SH BUGS
|
||||
As CON's and ROM's may be delivered in several parts, the count fields in
|
||||
a static exchange may be wrong.
|
||||
.PP
|
||||
Please report bugs to the author.
|
||||
.SH AUTHOR
|
||||
Ceriel J.H. Jacobs <ceriel@vu44.UUCP>
|
452
modules/src/read_em/read_em.c
Normal file
452
modules/src/read_em/read_em.c
Normal file
|
@ -0,0 +1,452 @@
|
|||
/* Read_em: a module to read either compact or human readable EM code.
|
||||
Exported are the following routines:
|
||||
EM_open() : has a parameter representing either a pointer to a
|
||||
filename or a null pointer, indicating that input is
|
||||
from standard input. This routine initializes for
|
||||
reading.
|
||||
EM_getinstr() : Delivers the next EM instruction in a format
|
||||
defined in <em_comp.h>.
|
||||
Imported are:
|
||||
The constants COMPACT (either defined or not defined) and
|
||||
CHECKING (again either defined or not defined),
|
||||
some routines from the system module. and the em_code module
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <system.h>
|
||||
#include <em_label.h>
|
||||
#include <em_arith.h>
|
||||
#include <em_pseu.h>
|
||||
#include <em_spec.h>
|
||||
#include "em_ptyp.h"
|
||||
#include "em_comp.h"
|
||||
#include <em_flag.h>
|
||||
#include <em_mes.h>
|
||||
|
||||
/* Buffered input */
|
||||
|
||||
#define getbyte() (*_ich ? (*_ich++ & 0377) : _fill())
|
||||
#define ungetbyte(uch) ((uch) >= 0 && (*--_ich = (uch)))
|
||||
#define init_input() (_fill(), _ich--)
|
||||
|
||||
#define EOF -1
|
||||
|
||||
static File *fd;
|
||||
static char *_ich;
|
||||
|
||||
PRIVATE int
|
||||
_fill()
|
||||
{
|
||||
static char text[BUFSIZ + 1];
|
||||
static int sz;
|
||||
|
||||
if (_ich && _ich < &text[sz]) return _ich++, '\0';
|
||||
if (sys_read(fd, text, BUFSIZ, &sz) &&
|
||||
sz > 0
|
||||
) {
|
||||
text[sz] = '\0';
|
||||
return _ich = text, (*_ich++&0377);
|
||||
}
|
||||
else return EOF;
|
||||
}
|
||||
|
||||
#define NARGS 3 /* Maximum number of arguments */
|
||||
#define STRSIZ 256 /* Maximum length of strings */
|
||||
|
||||
static struct e_instr emhead; /* Where we put the head */
|
||||
static struct e_args emargs[NARGS]; /* Where we put the arguments */
|
||||
static struct e_args *i_emargs;
|
||||
#define argentry() (i_emargs++)
|
||||
static struct string {
|
||||
int length;
|
||||
char str[STRSIZ + 1];
|
||||
} strings[NARGS]; /* Room for strings */
|
||||
static struct string *i_strings; /* Index of last one used */
|
||||
#define stringentry() (i_strings++)
|
||||
|
||||
static struct e_args *argp; /* Indicates arguments yet to be
|
||||
delivered
|
||||
*/
|
||||
static arith strleft; /* count # of chars left to read
|
||||
in a string
|
||||
*/
|
||||
|
||||
static int state; /* What state are we in? */
|
||||
#define CON 01 /* Reading a CON */
|
||||
#define ROM 02 /* Reading a ROM */
|
||||
#define MES 03 /* Reading a MES */
|
||||
#define PSEUMASK 03
|
||||
#define INSTRING 010 /* Reading a string */
|
||||
|
||||
static int EM_initialized; /* EM_open called? */
|
||||
|
||||
static long wordmask[] = { /* allowed bits in a word */
|
||||
0x00000000,
|
||||
0x000000FF,
|
||||
0x0000FFFF,
|
||||
0x00000000,
|
||||
0xFFFFFFFF
|
||||
};
|
||||
|
||||
static int wsize, psize; /* word size and pointer size */
|
||||
|
||||
#ifdef CHECKING
|
||||
static char *argrange = "Argument range error";
|
||||
#define check(expr) (expr || (xerror(argrange)))
|
||||
#else not CHECKING
|
||||
#define check(x) /* nothing */
|
||||
#endif CHECKING
|
||||
|
||||
/* Error handling
|
||||
*/
|
||||
|
||||
PRIVATE
|
||||
xerror(s)
|
||||
char *s;
|
||||
{
|
||||
if (emhead.em_type != EM_FATAL) emhead.em_type = EM_ERROR;
|
||||
if (!EM_error) EM_error = s;
|
||||
}
|
||||
|
||||
PRIVATE
|
||||
xfatal(s)
|
||||
char *s;
|
||||
{
|
||||
emhead.em_type = EM_FATAL;
|
||||
if (!EM_error) EM_error = s;
|
||||
}
|
||||
|
||||
#ifdef COMPACT
|
||||
#include "readk.c"
|
||||
#else not COMPACT
|
||||
#include "reade.c"
|
||||
#endif COMPACT
|
||||
|
||||
/* EM_open: Open input file, get magic word if COMPACT.
|
||||
*/
|
||||
EXPORT int
|
||||
EM_open(filename)
|
||||
char *filename;
|
||||
{
|
||||
|
||||
if (EM_initialized) {
|
||||
EM_error = "EM_open already called";
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (filename) {
|
||||
if (!sys_open(filename, OP_READ, &fd)) {
|
||||
EM_error = "Could not open input file";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else fd = STDIN;
|
||||
EM_filename = filename;
|
||||
init_input();
|
||||
|
||||
#ifdef COMPACT
|
||||
if (get16() != sp_magic) {
|
||||
EM_error = "Illegal magic word";
|
||||
return 0;
|
||||
}
|
||||
#else not COMPACT
|
||||
inithash(); /* initialize hashtable */
|
||||
#endif COMPACT
|
||||
|
||||
EM_initialized = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* EM_close: Close input file
|
||||
*/
|
||||
EXPORT
|
||||
EM_close()
|
||||
{
|
||||
|
||||
register struct string *pstr;
|
||||
|
||||
if (fd != STDIN) {
|
||||
sys_close(fd);
|
||||
fd = STDIN;
|
||||
}
|
||||
EM_initialized = 0;
|
||||
}
|
||||
|
||||
|
||||
/* startmes: handle the start of a message. The only important thing here
|
||||
is to get the wordsize and pointer size, and remember that they
|
||||
have already been read, not only to check that they are not specified
|
||||
again, but also to deliver the arguments on next calls to EM_getinstr.
|
||||
This is indicated by the variable "argp".
|
||||
*/
|
||||
PRIVATE
|
||||
startmes(p)
|
||||
register struct e_instr *p;
|
||||
{
|
||||
register struct e_args *ap;
|
||||
|
||||
ap = getarg(cst_ptyp);
|
||||
p->em_arg = ap;
|
||||
state = MES;
|
||||
|
||||
if (ap->em_cst == ms_emx) {
|
||||
if (wsize || psize) {
|
||||
xerror("Duplicate ms_emx");
|
||||
}
|
||||
argp = ap = getarg(cst_ptyp);
|
||||
wsize = ap->em_cst;
|
||||
ap->em_next = getarg(cst_ptyp);
|
||||
ap = ap->em_next;
|
||||
psize = ap->em_cst;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* EM_getinstr: read an "EM_line"
|
||||
*/
|
||||
EXPORT struct e_instr *
|
||||
EM_getinstr()
|
||||
{
|
||||
register struct e_instr *p = &emhead;
|
||||
register struct e_args *args;
|
||||
|
||||
i_emargs = emargs;
|
||||
i_strings = strings;
|
||||
EM_error = 0;
|
||||
#ifdef CHECKING
|
||||
if (!EM_initialized) {
|
||||
EM_error = "Initialization not done";
|
||||
p->em_type = EM_FATAL;
|
||||
return p;
|
||||
}
|
||||
#endif CHECKING
|
||||
|
||||
if (argp) { /* We have some arguments left to deliver */
|
||||
args = argp;
|
||||
argp = args->em_next;
|
||||
p->em_type = EM_MESARG;
|
||||
p->em_args = args;
|
||||
args->em_next = 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
if (!state) { /* All clear, get a new line */
|
||||
p = gethead();
|
||||
if (!p) { /* End of file */
|
||||
return p;
|
||||
}
|
||||
switch(p->em_type) {
|
||||
case EM_MNEM: {
|
||||
register int i,j;
|
||||
register struct e_args *ap;
|
||||
extern char em_flag[];
|
||||
extern short em_ptyp[];
|
||||
|
||||
p->em_args = 0;
|
||||
j = em_flag[p->em_opcode - sp_fmnem] & EM_PAR;
|
||||
i = em_ptyp[j];
|
||||
if (j == PAR_NO) { /* No arguments */
|
||||
break;
|
||||
}
|
||||
#ifndef COMPACT
|
||||
if (j == PAR_B) i = ptyp(sp_ilb2);
|
||||
#endif COMPACT
|
||||
ap = getarg(i);
|
||||
#ifndef COMPACT
|
||||
if (j == PAR_B) {
|
||||
ap->em_cst = ap->em_ilb;
|
||||
ap->em_argtype = cst_ptyp;
|
||||
}
|
||||
#endif COMPACT
|
||||
/* range checking
|
||||
*/
|
||||
#ifdef CHECKING
|
||||
if (wsize <= 4 && psize <= 4) switch(j) {
|
||||
case PAR_B:
|
||||
check(ap->em_cst <= 32767);
|
||||
/* Fall through */
|
||||
case PAR_N:
|
||||
check(ap->em_cst >= 0);
|
||||
break;
|
||||
case PAR_G:
|
||||
if (ap->em_argtype == cst_ptyp) {
|
||||
check(ap->em_cst >= 0);
|
||||
}
|
||||
/* Fall through */
|
||||
case PAR_F:
|
||||
/* ??? not in original em_decode or em_encode */
|
||||
case PAR_L:
|
||||
{ arith m = ap->em_cst >= 0 ? ap->em_cst :
|
||||
- ap->em_cst;
|
||||
|
||||
/* Check that the number fits in a pointer */
|
||||
check((m & ~wordmask[psize]) == 0);
|
||||
break;
|
||||
}
|
||||
case PAR_W:
|
||||
if (!ap) break;
|
||||
check((ap->em_cst & ~wordmask[wsize]) == 0);
|
||||
/* Fall through */
|
||||
case PAR_S:
|
||||
check(ap->em_cst > 0);
|
||||
/* Fall through */
|
||||
case PAR_Z:
|
||||
check(ap->em_cst >= 0 &&
|
||||
ap->em_cst % wsize == 0);
|
||||
break;
|
||||
case PAR_O:
|
||||
check(ap->em_cst > 0 &&
|
||||
( ap->em_cst % wsize == 0 ||
|
||||
wsize % ap->em_cst == 0));
|
||||
break;
|
||||
case PAR_R:
|
||||
check(ap->em_cst >= 0 && ap->em_cst <= 2);
|
||||
break;
|
||||
}
|
||||
#endif CHECKING
|
||||
p->em_args = ap;
|
||||
#ifndef COMPACT
|
||||
checkeol();
|
||||
#endif COMPACT
|
||||
}
|
||||
break;
|
||||
case EM_PSEU:
|
||||
/* handle a pseudo, read possible arguments. CON's and
|
||||
ROM's are handled especially: Only one argument is
|
||||
read, and a mark is set that an argument list of
|
||||
type ROM or CON is in process
|
||||
*/
|
||||
{
|
||||
register struct e_args *ap = 0, *ap1;
|
||||
|
||||
switch(p->em_opcode) {
|
||||
case ps_bss:
|
||||
case ps_hol:
|
||||
ap = getarg(cst_ptyp);
|
||||
ap->em_next = ap1 = getarg(par_ptyp);
|
||||
ap->em_next->em_next = ap1 = getarg(cst_ptyp);
|
||||
#ifdef CHECKING
|
||||
/* Check that the last value is 0 or 1
|
||||
*/
|
||||
if (ap1->em_cst != 1 && ap1->em_cst != 0) {
|
||||
xerror("Third argument of hol/bss not 0/1");
|
||||
}
|
||||
#endif CHECKING
|
||||
break;
|
||||
case ps_exa:
|
||||
case ps_ina:
|
||||
ap = getarg(lab_ptyp);
|
||||
break;
|
||||
case ps_exp:
|
||||
case ps_inp:
|
||||
ap = getarg(pro_ptyp);
|
||||
break;
|
||||
case ps_exc:
|
||||
ap = getarg(cst_ptyp);
|
||||
ap->em_next = getarg(cst_ptyp);
|
||||
break;
|
||||
case ps_pro:
|
||||
ap = getarg(pro_ptyp);
|
||||
ap->em_next = getarg(cst_ptyp|ptyp(sp_cend));
|
||||
break;
|
||||
case ps_end:
|
||||
ap = getarg(cst_ptyp|ptyp(sp_cend));
|
||||
break;
|
||||
case ps_con:
|
||||
ap = getarg(val_ptyp);
|
||||
state |= CON;
|
||||
break;
|
||||
case ps_rom:
|
||||
ap = getarg(val_ptyp);
|
||||
state |= ROM;
|
||||
break;
|
||||
default:
|
||||
xerror("Bad pseudo");
|
||||
break;
|
||||
}
|
||||
p->em_args = ap;
|
||||
}
|
||||
#ifndef COMPACT
|
||||
if (p->em_opcode != ps_con && p->em_opcode != ps_rom) {
|
||||
checkeol();
|
||||
}
|
||||
#endif COMPACT
|
||||
break;
|
||||
case EM_STARTMES:
|
||||
startmes(p);
|
||||
break;
|
||||
}
|
||||
if (!wsize) {
|
||||
xerror("EM code should start with mes 2");
|
||||
}
|
||||
if (EM_error && p->em_type != EM_FATAL) p->em_type = EM_ERROR;
|
||||
return p;
|
||||
}
|
||||
|
||||
if (state & INSTRING) { /* We already delivered part of a string.
|
||||
Deliver the next part
|
||||
*/
|
||||
register struct string *s;
|
||||
|
||||
s = getstring(0);
|
||||
args = argentry();
|
||||
args->em_next = 0;
|
||||
args->em_argtype = str_ptyp;
|
||||
args->em_str = s->str;
|
||||
args->em_size = s->length;
|
||||
switch(state & PSEUMASK) {
|
||||
default:
|
||||
assert(0);
|
||||
case MES:
|
||||
xerror("String too long in message");
|
||||
/* p->em_type = EM_MESARG;
|
||||
p->em_arg = args;
|
||||
*/
|
||||
break;
|
||||
case CON:
|
||||
p->em_type = EM_PSEU;
|
||||
p->em_opcode = ps_con;
|
||||
p->em_args = args;
|
||||
break;
|
||||
case ROM:
|
||||
p->em_type = EM_PSEU;
|
||||
p->em_opcode = ps_rom;
|
||||
p->em_args = args;
|
||||
break;
|
||||
}
|
||||
if (EM_error && p->em_type != EM_FATAL) p->em_type = EM_ERROR;
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Here, we are in a state reading arguments */
|
||||
args = getarg(any_ptyp);
|
||||
if (EM_error && p->em_type != EM_FATAL) {
|
||||
p->em_type = EM_ERROR;
|
||||
return p;
|
||||
}
|
||||
if (!args) { /* No more arguments */
|
||||
#ifndef COMPACT
|
||||
checkeol();
|
||||
#endif
|
||||
if (state == MES) {
|
||||
state = 0;
|
||||
p->em_type = EM_ENDMES;
|
||||
return p;
|
||||
}
|
||||
/* Here, we have to get the next instruction */
|
||||
state = 0;
|
||||
return EM_getinstr();
|
||||
}
|
||||
|
||||
/* Here, there was an argument */
|
||||
if (state == MES) {
|
||||
p->em_type = EM_MESARG;
|
||||
p->em_arg = args;
|
||||
return p;
|
||||
}
|
||||
p->em_type = EM_PSEU;
|
||||
p->em_args = args;
|
||||
if (state == CON) p->em_opcode = ps_con;
|
||||
else p->em_opcode = ps_rom;
|
||||
return p;
|
||||
}
|
640
modules/src/read_em/reade.c
Normal file
640
modules/src/read_em/reade.c
Normal file
|
@ -0,0 +1,640 @@
|
|||
/* 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");
|
||||
return sp_cst4;
|
||||
}
|
||||
|
||||
n = sp_cst4;
|
||||
|
||||
for (;;) {
|
||||
if (p >= &(s->str[STRSIZ])) {
|
||||
syntax("number too long");
|
||||
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--;
|
||||
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++;
|
||||
if ((c = getbyte()) == 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*/
|
||||
}
|
367
modules/src/read_em/readk.c
Normal file
367
modules/src/read_em/readk.c
Normal file
|
@ -0,0 +1,367 @@
|
|||
/* 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 */
|
||||
{
|
||||
register struct e_args *ap1, *ap2;
|
||||
|
||||
ap1 = getarg(lab_ptyp);
|
||||
ap2 = getarg(cst_ptyp);
|
||||
*ap = *ap1;
|
||||
if (ap->em_argtype == sof_ptyp) { /* non-numeric label */
|
||||
ap->em_soff = ap2->em_cst;
|
||||
}
|
||||
else ap->em_noff = ap2->em_cst;
|
||||
i_emargs -= 2;
|
||||
break;
|
||||
}
|
||||
|
||||
case sp_icon: /* An integer constant */
|
||||
case sp_ucon: /* An unsigned constant */
|
||||
case sp_fcon: /* A floating constant */
|
||||
{
|
||||
register struct e_args *ap1;
|
||||
register struct string *p;
|
||||
|
||||
ap1 = getarg(cst_ptyp);
|
||||
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;
|
||||
ap->em_size = ap1->em_cst;
|
||||
i_emargs--;
|
||||
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;
|
||||
}
|
Loading…
Reference in a new issue