Pristine Ack-5.5
[Ack-5.5.git] / modules / src / read_em / read_em.c
1 /* $Id: read_em.c,v 1.22 1994/06/24 11:21:27 ceriel Exp $ */
2 /*
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".
5  */
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
11                         reading.
12         EM_getinstr() : Delivers the next EM instruction in a format
13                         defined in <em_comp.h>.
14         Imported are:
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
18 */
19
20 #include <assert.h>
21 #include <alloc.h>
22 #include <system.h>
23 #include <em_label.h>
24 #include <em_arith.h>
25 #include <em_pseu.h>
26 #include <em_spec.h>
27 #include "em_ptyp.h"
28 #include "em_comp.h"
29 #include <em_flag.h>
30 #include <em_mes.h>
31
32 /* Buffered input */
33
34 #define getbyte()       (*_ich ? (*_ich++ & 0377) : _fill())
35 #define ungetbyte(uch)  ((uch) >= 0 && (*--_ich = (uch)))
36 #define init_input()    (_fill(), _ich--)
37
38 #define EOF     -1
39
40 static File *fd;
41 static char *_ich;
42
43 PRIVATE int
44 _fill()
45 {
46         static char text[BUFSIZ + 1];
47         static int sz;
48
49         if (_ich && _ich < &text[sz]) return _ich++, '\0';
50         _ich = text;
51         if (sys_read(fd, text, BUFSIZ, &sz) &&
52             sz > 0
53            ) {
54                 text[sz] = '\0';
55                 return (*_ich++&0377);
56         }
57         else {
58                 sz = 0;
59                 text[0] = 0;
60                 return EOF;
61         }
62 }
63
64 static struct e_instr *emhead;  /* Where we put the head */
65 static struct e_instr aheads[3];
66 static int ahead;
67
68 static struct string {
69         int length;
70         unsigned int maxlen;
71         char *str;
72 } string;
73
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 */
78 #define PSEUMASK 03
79
80 static int EM_initialized;      /* EM_open called? */
81
82 static long wordmask[] = {      /* allowed bits in a word */
83         0x00000000,
84         0x000000FF,
85         0x0000FFFF,
86         0x00000000,
87         0xFFFFFFFF
88 };
89
90 static int wsize, psize;        /* word size and pointer size */
91
92 #ifdef CHECKING
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 */
97 #endif /* CHECKING */
98
99 /* Error handling
100 */
101
102 PRIVATE void
103 xerror(s)
104         char *s;
105 {
106         if (emhead->em_type != EM_FATAL) emhead->em_type = EM_ERROR;
107         if (!EM_error) EM_error = s;
108 }
109
110 #ifdef COMPACT
111 PRIVATE void
112 xfatal(s)
113         char *s;
114 {
115         emhead->em_type = EM_FATAL;
116         if (!EM_error) EM_error = s;
117 }
118
119 #include "readk.c"
120 #else /* not COMPACT */
121 #include "reade.c"
122 #endif /* COMPACT */
123
124 /* EM_open: Open input file, get magic word if COMPACT.
125 */
126 EXPORT int
127 EM_open(filename)
128         char *filename;
129 {
130         if (EM_initialized) {
131                 EM_error = "EM_open already called";
132                 return 0;
133         }
134         
135         if (filename) {
136                 if (!sys_open(filename, OP_READ, &fd)) {
137                         EM_error = "Could not open input file";
138                         return 0;
139                 }
140         }
141         else    fd = STDIN;
142         EM_filename = filename;
143         init_input();
144
145 #ifdef COMPACT
146         if (get16() != sp_magic) {
147                 EM_error = "Illegal magic word";
148                 return 0;
149         }
150 #else /* not COMPACT */
151         inithash();     /* initialize hashtable */
152 #endif /* COMPACT */
153
154         EM_initialized = 1;
155         return 1;
156 }
157
158 /* EM_close: Close input file
159 */
160 EXPORT void
161 EM_close()
162 {
163         
164         if (fd != STDIN) {
165                 sys_close(fd);
166                 fd = STDIN;
167         }
168         EM_initialized = 0;
169 }
170
171
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".
177 */
178 PRIVATE void
179 startmes(p)
180         register struct e_instr *p;
181 {
182
183         getarg(cst_ptyp, &(p->em_arg));
184         state = MES;
185
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";
191                 }
192                 wsize = p->em_cst;
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";
199                 }
200                 psize = p->em_cst;
201                 EM_pointersize = p->em_cst;
202                 p->em_type = EM_MESARG;
203         }
204 }
205
206
207 /* EM_getinstr: read an "EM_line"
208 */
209 EXPORT int
210 EM_getinstr(p)
211         register struct e_instr *p;
212 {
213
214         EM_error = 0;
215         if (ahead) {
216                 register int i;
217
218                 ahead--;
219                 *p = aheads[0];
220                 for (i = 0; i < ahead; i++) aheads[i] = aheads[i+1];
221                 return 1;
222         }
223         emhead = p;
224         p->em_type = 0;
225 #ifdef CHECKING
226         if (!EM_initialized) {
227                 EM_error = "Initialization not done";
228                 p->em_type = EM_FATAL;
229                 return 0;
230         }
231 #endif /* CHECKING */
232
233         if (!state) {           /* All clear, get a new line */
234                 gethead(p);
235                 switch(p->em_type) {
236                 case EM_EOF:
237                         return EM_error == 0;
238                 case EM_MNEM: {
239                         register int i,j;
240                         extern char em_flag[];
241                         extern short em_ptyp[]; 
242
243                         j = em_flag[p->em_opcode - sp_fmnem] & EM_PAR;
244                         i = em_ptyp[j];
245                         if (j == PAR_NO) {      /* No arguments */
246                                 p->em_argtype = 0;
247                         }
248 #ifndef COMPACT
249                         if (j == PAR_B) i = ptyp(sp_ilb2);
250 #endif /* COMPACT */
251                         if (j != PAR_NO) getarg(i, &(p->em_arg));
252 #ifndef COMPACT
253                         if (j == PAR_B) {
254                                 p->em_cst = p->em_ilb;
255                                 p->em_argtype = cst_ptyp;
256                         }
257 #endif /* COMPACT */
258                         /* range checking
259                         */
260 #ifdef CHECKING
261                         if (wsize <= 4 && psize <= 4) switch(j) {
262                         case PAR_B:
263                                 check(p->em_cst <= 32767);
264                                 /* Fall through */
265                         case PAR_N:
266                                 check(p->em_cst >= 0);
267                                 break;
268                         case PAR_G:
269                                 if (p->em_argtype != cst_ptyp) {
270                                         break;
271                                 }
272                                 check(p->em_cst >= 0);
273                                 /* Fall through */
274                         case PAR_F:
275                                 /* ??? not in original em_decode or em_encode */
276                         case PAR_L:
277                         {       arith m = p->em_cst >= 0 ? p->em_cst :
278                                                             - p->em_cst;
279
280                                 /* Check that the number fits in a pointer */
281                                 check((m & ~wordmask[psize]) == 0);
282                                 break;
283                         }
284                         case PAR_W:
285                                 if (p->em_argtype == 0) {
286                                         p->em_cst = 0;
287                                         break;
288                                 }
289                                 check((p->em_cst & ~wordmask[wsize]) == 0);
290                                 /* Fall through */
291                         case PAR_S:
292                                 check(p->em_cst > 0);
293                                 /* Fall through */
294                         case PAR_Z:
295                                 check(p->em_cst >= 0 &&
296                                       p->em_cst % wsize == 0);
297                                 break;
298                         case PAR_O:
299                                 check(p->em_cst > 0 &&
300                                       ( p->em_cst % wsize == 0 ||
301                                         wsize % p->em_cst == 0));
302                                 break;
303                         case PAR_R:
304                                 check(p->em_cst >= 0 && p->em_cst <= 2);
305                                 break;
306                         }
307 #endif /* CHECKING */
308 #ifndef COMPACT
309                         checkeol();
310 #endif /* COMPACT */
311                         }
312                         break;
313                 case EM_PSEU:
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
318                         */
319                         {
320                         struct e_arg dummy;
321
322                         switch(p->em_opcode) {
323                         case ps_bss:
324                         case ps_hol:
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;
330 #ifdef CHECKING
331                                 /* Check that the last value is 0 or 1
332                                 */
333                                 if (EM_holinit != 1 && EM_holinit != 0) {
334                                   if (! EM_error)
335                                    EM_error="Third argument of hol/bss not 0/1";
336                                 }
337 #endif /* CHECKING */
338                                 break;
339                         case ps_exa:
340                         case ps_ina:
341                                 getarg(lab_ptyp, &(p->em_arg));
342                                 break;
343                         case ps_exp:
344                         case ps_inp:
345                                 getarg(pro_ptyp, &(p->em_arg));
346                                 break;
347                         case ps_exc:
348                                 getarg(cst_ptyp, &dummy);
349                                 p->em_exc1 = dummy.ema_cst;
350                                 getarg(cst_ptyp, &dummy);
351                                 p->em_exc2 = dummy.ema_cst;
352                                 break;
353                         case ps_pro:
354                                 getarg(pro_ptyp, &(p->em_arg));
355                                 getarg(cst_ptyp|ptyp(sp_cend), &dummy);
356                                 if (dummy.ema_argtype == 0) {
357                                         p->em_nlocals = -1;
358                                 }
359                                 else    p->em_nlocals = dummy.ema_cst;
360                                 break;
361                         case ps_end:
362                                 getarg(cst_ptyp|ptyp(sp_cend), &(p->em_arg));
363                                 break;
364                         case ps_con:
365                                 getarg(val_ptyp, &(p->em_arg));
366                                 state |= CON;
367                                 break;
368                         case ps_rom:
369                                 getarg(val_ptyp, &(p->em_arg));
370                                 state |= ROM;
371                                 break;
372                         default:
373                                 xerror("Bad pseudo");
374                                 break;
375                         }
376                         }
377 #ifndef COMPACT
378                         if (p->em_opcode != ps_con && p->em_opcode != ps_rom) {
379                                 checkeol();
380                         }
381 #endif /* COMPACT */
382                         break;
383                 case EM_STARTMES:
384                         startmes(p);
385                         break;
386                 }
387                 if (!wsize && !EM_error) {
388                         wsize = 2;
389                         psize = 2;
390                         EM_error = "EM code should start with mes 2";
391                 }
392                 return EM_error == 0;
393         }
394
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) {
398                 return 0;
399         }
400         if (p->em_argtype == 0) {       /* No more arguments */
401 #ifndef COMPACT
402                 checkeol();
403 #endif
404                 if (state == MES) {
405                         state = 0;
406                         p->em_type = EM_ENDMES;
407                         return EM_error == 0;
408                 }
409                 /* Here, we have to get the next instruction */
410                 state = 0;
411                 return EM_getinstr(p);
412         }
413
414         /* Here, there was an argument */
415         if (state == MES) {
416                 p->em_type = EM_MESARG;
417                 return EM_error == 0;
418         }
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;
423 }