diff --git a/modules/src/read_em/EM_vars.c b/modules/src/read_em/EM_vars.c new file mode 100644 index 000000000..347ee07e8 --- /dev/null +++ b/modules/src/read_em/EM_vars.c @@ -0,0 +1,7 @@ +/* $Header$ */ + +/* Variables must be declared somewhere ... */ + +char *EM_error; +char *EM_filename; +unsigned int EM_lineno; diff --git a/modules/src/read_em/Makefile b/modules/src/read_em/Makefile new file mode 100644 index 000000000..2c4baf87b --- /dev/null +++ b/modules/src/read_em/Makefile @@ -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 diff --git a/modules/src/read_em/argtype b/modules/src/read_em/argtype new file mode 100755 index 000000000..3ca1d7dc9 --- /dev/null +++ b/modules/src/read_em/argtype @@ -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 " 1>&2 + exit 1 + ;; +esac +ed - $2 << A +1,/^\$/d +1,/^\$/d +1,/^\$/g/^\(...\) [$1].*/s//\\1/gp +A diff --git a/modules/src/read_em/em_comp.h b/modules/src/read_em/em_comp.h new file mode 100644 index 000000000..0d946c96c --- /dev/null +++ b/modules/src/read_em/em_comp.h @@ -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; diff --git a/modules/src/read_em/m_C_mnem b/modules/src/read_em/m_C_mnem new file mode 100755 index 000000000..f31347e83 --- /dev/null +++ b/modules/src/read_em/m_C_mnem @@ -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 diff --git a/modules/src/read_em/m_C_mnem_na b/modules/src/read_em/m_C_mnem_na new file mode 100755 index 000000000..d0bdab948 --- /dev/null +++ b/modules/src/read_em/m_C_mnem_na @@ -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 diff --git a/modules/src/read_em/mkcalls.c b/modules/src/read_em/mkcalls.c new file mode 100644 index 000000000..3aee2fb6d --- /dev/null +++ b/modules/src/read_em/mkcalls.c @@ -0,0 +1,467 @@ +/* makecalls: expand a datastructure as delivered by "EM_getline" + into calls to the procedural interface. + Exported routine: + EM_mkcalls +*/ + +#include +#include +#include +#include +#include "em_ptyp.h" +#include +#include "em_comp.h" +#include + +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; +} diff --git a/modules/src/read_em/read_em.3 b/modules/src/read_em/read_em.3 new file mode 100644 index 000000000..4cadc3ed4 --- /dev/null +++ b/modules/src/read_em/read_em.3 @@ -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 +.br +.B #include +.br +.B #include +.br +.B #include +.br +.B #include +.br +.B #include +.br +.B #include +.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 , 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 , +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 diff --git a/modules/src/read_em/read_em.c b/modules/src/read_em/read_em.c new file mode 100644 index 000000000..085fa4141 --- /dev/null +++ b/modules/src/read_em/read_em.c @@ -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 . + 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 +#include +#include +#include +#include +#include +#include "em_ptyp.h" +#include "em_comp.h" +#include +#include + +/* 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; +} diff --git a/modules/src/read_em/reade.c b/modules/src/read_em/reade.c new file mode 100644 index 000000000..16ba0c0fd --- /dev/null +++ b/modules/src/read_em/reade.c @@ -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 + +/* #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*/ +} diff --git a/modules/src/read_em/readk.c b/modules/src/read_em/readk.c new file mode 100644 index 000000000..1ba9df643 --- /dev/null +++ b/modules/src/read_em/readk.c @@ -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 + +/* 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; +}