1 /* $Id: read_em.c,v 1.22 1994/06/24 11:21:27 ceriel Exp $ */
3 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
4 * See the copyright notice in the ACK home directory, in the file "Copyright".
6 /* Read_em: a module to read either compact or human readable EM code.
7 Exported are the following routines:
8 EM_open() : has a parameter representing either a pointer to a
9 filename or a null pointer, indicating that input is
10 from standard input. This routine initializes for
12 EM_getinstr() : Delivers the next EM instruction in a format
13 defined in <em_comp.h>.
15 The constants COMPACT (either defined or not defined) and
16 CHECKING (again either defined or not defined),
17 some routines from the system module. and the em_code module
34 #define getbyte() (*_ich ? (*_ich++ & 0377) : _fill())
35 #define ungetbyte(uch) ((uch) >= 0 && (*--_ich = (uch)))
36 #define init_input() (_fill(), _ich--)
46 static char text[BUFSIZ + 1];
49 if (_ich && _ich < &text[sz]) return _ich++, '\0';
51 if (sys_read(fd, text, BUFSIZ, &sz) &&
55 return (*_ich++&0377);
64 static struct e_instr *emhead; /* Where we put the head */
65 static struct e_instr aheads[3];
68 static struct string {
74 static int state; /* What state are we in? */
75 #define CON 01 /* Reading a CON */
76 #define ROM 02 /* Reading a ROM */
77 #define MES 03 /* Reading a MES */
80 static int EM_initialized; /* EM_open called? */
82 static long wordmask[] = { /* allowed bits in a word */
90 static int wsize, psize; /* word size and pointer size */
93 static char *argrange = "Argument range error";
94 #define check(expr) (expr || EM_error || (EM_error = argrange))
95 #else /* not CHECKING */
96 #define check(x) /* nothing */
106 if (emhead->em_type != EM_FATAL) emhead->em_type = EM_ERROR;
107 if (!EM_error) EM_error = s;
115 emhead->em_type = EM_FATAL;
116 if (!EM_error) EM_error = s;
120 #else /* not COMPACT */
124 /* EM_open: Open input file, get magic word if COMPACT.
130 if (EM_initialized) {
131 EM_error = "EM_open already called";
136 if (!sys_open(filename, OP_READ, &fd)) {
137 EM_error = "Could not open input file";
142 EM_filename = filename;
146 if (get16() != sp_magic) {
147 EM_error = "Illegal magic word";
150 #else /* not COMPACT */
151 inithash(); /* initialize hashtable */
158 /* EM_close: Close input file
172 /* startmes: handle the start of a message. The only important thing here
173 is to get the wordsize and pointer size, and remember that they
174 have already been read, not only to check that they are not specified
175 again, but also to deliver the arguments on next calls to EM_getinstr.
176 This is indicated by the variable "argp".
180 register struct e_instr *p;
183 getarg(cst_ptyp, &(p->em_arg));
186 if (p->em_cst == ms_emx) {
187 p = &aheads[ahead++];
188 getarg(cst_ptyp, &(p->em_arg));
189 if (wsize && p->em_cst != wsize && !EM_error) {
190 EM_error = "Different wordsize in duplicate ms_emx";
193 EM_wordsize = p->em_cst;
194 p->em_type = EM_MESARG;
195 p = &aheads[ahead++];
196 getarg(cst_ptyp, &(p->em_arg));
197 if (psize && p->em_cst != psize && !EM_error) {
198 EM_error = "Different pointersize in duplicate ms_emx";
201 EM_pointersize = p->em_cst;
202 p->em_type = EM_MESARG;
207 /* EM_getinstr: read an "EM_line"
211 register struct e_instr *p;
220 for (i = 0; i < ahead; i++) aheads[i] = aheads[i+1];
226 if (!EM_initialized) {
227 EM_error = "Initialization not done";
228 p->em_type = EM_FATAL;
231 #endif /* CHECKING */
233 if (!state) { /* All clear, get a new line */
237 return EM_error == 0;
240 extern char em_flag[];
241 extern short em_ptyp[];
243 j = em_flag[p->em_opcode - sp_fmnem] & EM_PAR;
245 if (j == PAR_NO) { /* No arguments */
249 if (j == PAR_B) i = ptyp(sp_ilb2);
251 if (j != PAR_NO) getarg(i, &(p->em_arg));
254 p->em_cst = p->em_ilb;
255 p->em_argtype = cst_ptyp;
261 if (wsize <= 4 && psize <= 4) switch(j) {
263 check(p->em_cst <= 32767);
266 check(p->em_cst >= 0);
269 if (p->em_argtype != cst_ptyp) {
272 check(p->em_cst >= 0);
275 /* ??? not in original em_decode or em_encode */
277 { arith m = p->em_cst >= 0 ? p->em_cst :
280 /* Check that the number fits in a pointer */
281 check((m & ~wordmask[psize]) == 0);
285 if (p->em_argtype == 0) {
289 check((p->em_cst & ~wordmask[wsize]) == 0);
292 check(p->em_cst > 0);
295 check(p->em_cst >= 0 &&
296 p->em_cst % wsize == 0);
299 check(p->em_cst > 0 &&
300 ( p->em_cst % wsize == 0 ||
301 wsize % p->em_cst == 0));
304 check(p->em_cst >= 0 && p->em_cst <= 2);
307 #endif /* CHECKING */
314 /* handle a pseudo, read possible arguments. CON's and
315 ROM's are handled especially: Only one argument is
316 read, and a mark is set that an argument list of
317 type ROM or CON is in process
322 switch(p->em_opcode) {
325 getarg(cst_ptyp, &dummy);
326 EM_holsize = dummy.ema_cst;
327 getarg(par_ptyp, &(p->em_arg));
328 getarg(cst_ptyp, &dummy);
329 EM_holinit = dummy.ema_cst;
331 /* Check that the last value is 0 or 1
333 if (EM_holinit != 1 && EM_holinit != 0) {
335 EM_error="Third argument of hol/bss not 0/1";
337 #endif /* CHECKING */
341 getarg(lab_ptyp, &(p->em_arg));
345 getarg(pro_ptyp, &(p->em_arg));
348 getarg(cst_ptyp, &dummy);
349 p->em_exc1 = dummy.ema_cst;
350 getarg(cst_ptyp, &dummy);
351 p->em_exc2 = dummy.ema_cst;
354 getarg(pro_ptyp, &(p->em_arg));
355 getarg(cst_ptyp|ptyp(sp_cend), &dummy);
356 if (dummy.ema_argtype == 0) {
359 else p->em_nlocals = dummy.ema_cst;
362 getarg(cst_ptyp|ptyp(sp_cend), &(p->em_arg));
365 getarg(val_ptyp, &(p->em_arg));
369 getarg(val_ptyp, &(p->em_arg));
373 xerror("Bad pseudo");
378 if (p->em_opcode != ps_con && p->em_opcode != ps_rom) {
387 if (!wsize && !EM_error) {
390 EM_error = "EM code should start with mes 2";
392 return EM_error == 0;
395 /* Here, we are in a state reading arguments */
396 getarg(any_ptyp, &(p->em_arg));
397 if (EM_error && p->em_type != EM_FATAL) {
400 if (p->em_argtype == 0) { /* No more arguments */
406 p->em_type = EM_ENDMES;
407 return EM_error == 0;
409 /* Here, we have to get the next instruction */
411 return EM_getinstr(p);
414 /* Here, there was an argument */
416 p->em_type = EM_MESARG;
417 return EM_error == 0;
419 p->em_type = EM_PSEU;
420 if (state == CON) p->em_opcode = ps_con;
421 else p->em_opcode = ps_rom;
422 return EM_error == 0;