Pristine Ack-5.5
[Ack-5.5.git] / modules / src / read_em / reade.c
1 /* $Id: reade.c,v 1.14 1994/06/24 11:21:31 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 /*      This file is ment to be included in the file read_em.c.
7         It contains the part that takes care of the reading of human readable
8         EM-code.
9 */
10
11 #include <ctype.h>
12
13 /* #define XXX_YYY      /* only for early debugging */
14
15 #ifdef XXX_YYY
16 #define out(str)        (sys_write(STDOUT, str, strlen(str)))
17 #else
18 #define out(s)
19 #endif
20
21 #define fit16i(x)       ((x) >= -32768L && (x) <= 32767L)
22
23 #define HSIZE   256     /* Size of hashtable for mnemonics */
24
25 static int hashtab[HSIZE];      /* The hashtable for mnemonics */
26
27 static int argnum;              /* Number of arguments */
28
29 #define COMMENTSTARTER  ';'
30
31 /* inithash, pre_hash, hash: Simple hashtable mechanism
32 */
33 PRIVATE int
34 hash(s)
35         register char *s;
36 {
37         register int h = 0;
38
39         while (*s) {
40                 h <<= 1;
41                 h += *s++;
42         }
43         return h;
44 }
45
46 PRIVATE void
47 pre_hash(i, s)
48         char *s;
49 {
50         register int h;
51
52         assert(i != 0);
53         h = hash(s);
54
55         for (;;) {
56                 h++;
57                 if (h >= HSIZE) h %= HSIZE;
58                 if (hashtab[h] == 0) {
59                         hashtab[h] = i;
60                         return;
61                 }
62         }
63         /*NOTREACHED*/
64 }
65
66 extern char em_mnem[][4];
67 extern char em_pseu[][4];
68
69 PRIVATE void
70 inithash()
71 {
72         register int i;
73
74         /* Enter instructions ... */
75         for (i = sp_fmnem; i <= sp_lmnem; i++) {
76                 pre_hash(i, em_mnem[i - sp_fmnem]);
77         }
78
79         /* and pseudos ... */
80         for (i = sp_fpseu; i <= sp_lpseu; i++) {
81                 pre_hash(i, em_pseu[i - sp_fpseu]);
82         }
83 }
84
85 /* nospace: skip until we find a non-space character. Also skip
86         comments.
87 */
88 PRIVATE int
89 nospace()
90 {
91         register int c;
92
93         do      c = getbyte();
94         while (isspace(c) && c != '\n');
95
96         if (c == COMMENTSTARTER) {
97                 do      c = getbyte();
98                 while (c != '\n' && c != EOF);
99         }
100
101         return c;
102 }
103
104 /* syntax: Put an error message in EM_error and skip to the end of the line
105 */
106 PRIVATE void
107 syntax(s)
108         char *s;
109 {
110         register int c;
111
112         xerror(s);
113         state = 0;
114         while ((c = getbyte()) != '\n' && c != EOF) /* nothing */ ;
115         ungetbyte(c);
116 }
117
118 /* checkeol: check that we have a complete line (except maybe for spaces)
119 */
120 PRIVATE void
121 checkeol()
122 {
123
124         if (nospace() != '\n') {
125                 syntax("end of line expected");
126                 nospace();
127         }
128 }
129
130 /* getescape: read a '\' escape sequence
131 */
132 PRIVATE int
133 getescape()
134 {
135         register int c, j, r;
136
137         if ((c = getbyte()) >= '0' && c <= '7') { /* numeric escape */
138                 r = c - '0';
139
140                 for (j = 0; j < 2; j++) {
141                         if ((c = getbyte()) < '0' || c > '7') {
142                                 ungetbyte(c);
143                                 return r;
144                         }
145                         r <<= 3;
146                         r += c - '0';
147                 }
148
149                 return r;
150         }
151
152         switch(c) {
153         case 'b':       return '\b';
154         case 'f':       return '\f';
155         case 'n':       return '\n';
156         case 'r':       return '\r';
157         case 't':       return '\t';
158         }
159
160         return c;
161 }
162
163 /* getname: Read a string of characters representing an identifier
164 */
165 PRIVATE struct string *
166 getname()
167 {
168         register char *p;
169         register struct string *s;
170         register int c;
171
172         s = &string;
173         p = s->str;
174         if (!p) {
175                 s->maxlen = 256;
176                 s->str = p = Malloc(256);
177         }
178         c = getbyte();
179
180         if (!(isalpha(c) || c == '_')) {
181                 ungetbyte(c);
182                 syntax("Letter expected");
183                 return s;
184         }
185
186         while (isalnum(c) || c == '_') {
187                 if (p >= &(s->str[s->maxlen])) {
188                         int df = p - s->str;
189                         s->str = Realloc(s->str, (s->maxlen += 256));
190                         p = s->str + df;
191                 }
192                 *p++ = c;
193                 c = getbyte();
194         }
195
196         ungetbyte(c);
197         *p = '\0';
198         s->length = p - s->str;
199         return s;
200 }
201
202 /* getstring: read a string of characters between quotes
203 */
204 PRIVATE struct string *
205 getstring()
206 {
207         register char *p;
208         struct string *s;
209         register int c;
210         static int termc;
211
212         s = &string;
213         p = s->str;
214         if (!p) {
215                 s->maxlen = 256;
216                 s->str = p = Malloc(256);
217         }
218
219         termc = getbyte();
220         /* assert(termc == '"' || termc == '\''); */
221         /* This assertion does not work. Compiler error messages.
222            The trouble lies in the ", it terminates the string
223            created in the assertion macro
224         */
225
226         for (;;) {
227                 if ((c = getbyte()) == '\n' || c == EOF) {
228                         ungetbyte(c);
229                         syntax("non-terminated string");
230                         break;
231                 }
232
233                 if (c == termc) {
234                         if (termc == '"') *p++ = '\0';
235                         break;
236                 }
237
238                 if (c == '\\') c = getescape();
239
240                 if (p >= &(s->str[s->maxlen])) {
241                         int df = p - s->str;
242                         s->str = Realloc(s->str, (s->maxlen += 256));
243                         p = s->str + df;
244                 }
245
246                 *p++ = c;       
247         }
248         *p = '\0';
249
250         s->length = p - s->str;
251         return s;
252 }
253
254 PRIVATE void gettyp();
255
256 PRIVATE int
257 offsetted(argtyp, ap)
258         arith *ap;
259 {
260         register int c;
261
262         if ((c = nospace()) == '+' || c == '-') {
263                 struct e_arg dummy;
264
265                 gettyp(cst_ptyp, &dummy);
266                 if (c == '-') *ap = -(dummy.ema_cst);
267                 else *ap = dummy.ema_cst;
268                 return sp_doff;
269         }
270         else    *ap = 0;
271
272         ungetbyte(c);
273         return argtyp;
274 }
275
276 PRIVATE int
277 getnumber(c, ap)
278         register int c;
279         register struct e_arg *ap;
280 {
281         char str[256 + 1];
282         register char *p = str;
283         int n;
284         int expsign;
285         long str2long();
286
287         ap->ema_argtype = cst_ptyp;
288         expsign = 0;
289
290         if (c == '+' || c == '-') {
291                 if (c == '-') *p++ = c;
292                 c = getbyte();
293         }
294
295         if (! isdigit(c)) {
296                 ungetbyte(c);
297                 syntax("digit expected");
298                 return sp_cst4;
299         }
300
301         n = sp_cst4;
302
303         for (;;) {
304                 if (p >= &(str[256])) {
305                         syntax("number too long");
306                         return sp_cst4;
307                 }
308
309                 *p++ = c;
310
311                 if ((c = getbyte()) == '.' || c == 'e' || c == 'E') {
312                         expsign = c != '.';
313                         n = sp_fcon;
314                         continue;
315                 }
316
317                 if (expsign) {
318                         expsign = 0;
319                         if (c == '+' || c == '-') continue;
320                 }
321
322                 if (! isdigit(c)) break;
323         }
324
325         ungetbyte(c);
326         *p = '\0';
327         c = nospace();
328
329         if (n == sp_fcon && c != 'F') {
330                 ungetbyte(c);
331                 syntax("'F' expected");
332                 return n;
333         }       
334
335         if (c == 'I' || c == 'U' || c == 'F') {
336                 struct e_arg dummy;
337
338                 strcpy(string.str, str);
339                 ap->ema_string = string.str;
340                 gettyp(cst_ptyp, &dummy);
341                 ap->ema_szoroff = dummy.ema_cst;
342
343                 switch(c) {
344                 case 'I':
345                         ap->ema_argtype = ico_ptyp;
346                         return sp_icon;
347                 case 'U':
348                         ap->ema_argtype = uco_ptyp;
349                         return sp_ucon;
350                 case 'F':
351                         ap->ema_argtype = fco_ptyp;
352                         return sp_fcon;
353                 }
354                 assert(0);
355         }
356
357         ungetbyte(c);
358         ap->ema_cst = (arith) str2long(str, 10);
359         return sp_cst4;
360 }
361
362 PRIVATE int getexpr();
363
364 PRIVATE int
365 getfactor(c, ap)
366         register int c;
367         register struct e_arg *ap;
368 {
369         if (c == '(') {
370                 if (getexpr(nospace(), ap) != sp_cst4) {
371                         syntax("expression expected");
372                 }
373                 else if ((c = nospace()) != ')') {
374                         ungetbyte(c);
375                         syntax("')' expected");
376                 }
377                 return sp_cst4;
378         }
379         return getnumber(c, ap);
380 }
381
382 PRIVATE int
383 getterm(c, ap) 
384         register int c;
385         register struct e_arg *ap;
386 {
387         arith left;
388
389         if ((c = getfactor(c, ap)) != sp_cst4) return c;
390
391         for (;;) {
392                 if ((c = nospace()) != '*' && c != '/' && c != '%') {
393                         ungetbyte(c);
394                         break;
395                 }
396
397                 left = ap->ema_cst;
398                 if (getfactor(nospace(), ap) != sp_cst4) {
399                         syntax("factor expected");
400                         break;
401                 }
402
403                 if (c == '*') ap->ema_cst *= left;
404                 else if (c == '/') ap->ema_cst = left / ap->ema_cst;
405                 else    ap->ema_cst = left % ap->ema_cst;
406         }
407         return sp_cst4;
408 }
409
410 PRIVATE int
411 getexpr(c, ap)
412         register int c;
413         register struct e_arg *ap;
414 {
415         arith left;
416
417         if ((c = getterm(c, ap)) != sp_cst4) return c;
418
419         for (;;) {
420                 if ((c = nospace()) != '+' && c != '-') {
421                         ungetbyte(c);
422                         break;
423                 }
424
425                 left = ap->ema_cst;
426                 if (getterm(nospace(), ap) != sp_cst4) {
427                         syntax("term expected");
428                         break;
429                 }
430
431                 if (c == '+') ap->ema_cst += left;
432                 else ap->ema_cst = left - ap->ema_cst;
433         }
434         return sp_cst4;
435 }
436
437 PRIVATE int
438 get15u()
439 {
440         struct e_arg dummy;
441
442         if (getnumber(getbyte(), &dummy) != sp_cst4) {
443                 syntax("integer expected");
444         }
445         else check((dummy.ema_cst & ~077777) == 0);
446         return (int) (dummy.ema_cst);
447 }
448
449 PRIVATE void
450 gettyp(typset, ap)
451         register struct e_arg *ap;
452 {
453         register int c, t;
454         register int argtyp;
455
456         if ((c = nospace()) == '\n') {
457                 ungetbyte(c);
458                 out("newline\n");
459                 argtyp = sp_cend;
460         }
461         else if (isdigit(c) || c == '+' || c == '-' || c == '(') {
462                 out("expr\n");
463                 argtyp = getexpr(c, ap);
464                 if (argtyp == sp_cst4 && fit16i(ap->ema_cst)) argtyp = sp_cst2;
465         }
466         else if (isalpha(c) || c == '_') {
467                 out("name\n");
468                 ungetbyte(c);
469                 ap->ema_dnam = getname()->str;
470                 ap->ema_argtype = sof_ptyp;
471                 argtyp = offsetted(sp_dnam, &(ap->ema_szoroff));
472         }
473         else if (c == '.') {
474                 out(".label\n");
475                 ap->ema_dlb = get15u();
476                 ap->ema_argtype = nof_ptyp;
477                 argtyp = offsetted(sp_dlb2, &(ap->ema_szoroff));
478         }
479         else if (c == '*') {
480                 out("*label\n");
481                 ap->ema_ilb = get15u();
482                 ap->ema_argtype = ilb_ptyp;
483                 argtyp = sp_ilb2;
484         }
485         else if (c == '$') {
486                 out("$name\n");
487                 ap->ema_pnam = getname()->str;
488                 ap->ema_argtype = pro_ptyp;
489                 argtyp = sp_pnam;
490         }
491         else if (c == '"' || c == '\'') {
492                 register struct string *s;
493
494                 out("string\n");
495                 ungetbyte(c);
496                 s = getstring(0);
497                 ap->ema_string = s->str;
498                 ap->ema_szoroff = s->length;    
499                 ap->ema_argtype = str_ptyp;
500                 argtyp = sp_scon;
501         }
502         else if (c == '?') {
503                 out("?\n");
504                 argtyp = sp_cend;
505                 ap->ema_argtype = 0;
506         }
507         else {
508                 /* c != '\n', so "ungetbyte" not neccesary */
509                 syntax("operand expected");
510                 return;
511         }
512
513         t = argtyp - sp_fspec;
514         assert(t >= 0 && t < 16);
515         if ((typset & (1 << t)) == 0) {
516                 syntax("Bad argument type");
517                 return;
518         }
519
520         if (argtyp == sp_cend) {
521                 ap->ema_argtype = 0;
522         }
523 }
524
525 PRIVATE void
526 getarg(typset, ap)
527         struct e_arg *ap;
528 {
529         register int c;
530
531         if (argnum != 1) {
532                 if ((c = nospace()) != ',') {
533                         if (c != '\n') {
534                                 syntax("comma expected");
535                                 return;
536                         }
537                         ungetbyte(c);
538                 }
539         }
540         argnum++;
541         gettyp(typset, ap);
542 }
543
544 /* getmnem: We found the start of either an instruction or a pseudo.
545         get the rest of it
546 */
547 PRIVATE void
548 getmnem(c, p)
549         register struct e_instr *p;
550 {
551         register int h;
552         int i;
553         register struct string *s;
554
555         ungetbyte(c);
556         s = getname();
557         h = hash(s->str);
558
559         for (;;) {
560                 h++;
561                 if (h >= HSIZE) h %= HSIZE;
562                 if ((i = hashtab[h]) == 0) {
563                         syntax("bad mnemonic");
564                         return;
565                 }
566                 else if (i <= sp_lmnem) {
567                         assert(i >= sp_fmnem);
568                         if (strcmp(s->str, em_mnem[i - sp_fmnem]) != 0) {
569                                 continue;
570                         }
571                         p->em_type = EM_MNEM;
572                         p->em_opcode = i;
573                         break;
574                 }
575                 assert(i <= sp_lpseu && i >= sp_fpseu);
576                 if (strcmp(s->str, em_pseu[i - sp_fpseu]) != 0) {
577                         continue;
578                 }
579                 if (i == ps_mes) {
580                         p->em_type = EM_STARTMES;
581                         break;
582                 }
583                 p->em_opcode = i;
584                 p->em_type = EM_PSEU;
585                 break;
586         }
587 }
588
589 PRIVATE void
590 line_line()
591 {
592         static char filebuf[256 + 1];
593         char *btscpy();
594         struct e_arg dummy;
595
596         gettyp(ptyp(sp_cst2), &dummy);
597         EM_lineno = dummy.ema_cst;
598         gettyp(str_ptyp, &dummy);
599         btscpy(filebuf, dummy.ema_string, (int) dummy.ema_szoroff);
600         EM_filename = filebuf;
601 }
602
603 PRIVATE void
604 getlabel(c, p)
605         register struct e_instr *p;
606 {
607
608         ungetbyte(c);
609         gettyp(lab_ptyp|ptyp(sp_cst2), &(p->em_arg));
610         switch(p->em_argtype) {
611         case cst_ptyp:
612                 p->em_type = EM_DEFILB;
613                 p->em_argtype = ilb_ptyp;
614                 p->em_ilb = p->em_cst;
615                 break;
616         case sof_ptyp:
617                 p->em_type = EM_DEFDNAM;
618                 break;
619         case nof_ptyp:
620                 p->em_type = EM_DEFDLB;
621                 break;
622         }
623         checkeol();
624 }
625
626 PRIVATE void
627 gethead(p)
628         register struct e_instr *p;
629 {
630         register int c;
631
632         argnum = 1;
633         for (;;) {      
634                 EM_lineno++;
635                 c = getbyte();
636                 if (c == COMMENTSTARTER) {
637                         do      c = getbyte();
638                         while (c != '\n' && c != EOF);
639                 }
640                 if (c == EOF) {
641                         p->em_type = EM_EOF;
642                         return;
643                 }
644                 if (c == '\n') continue;
645                 if (isspace(c)) {
646                         c = nospace();
647                         if (isalpha(c) || c == '_') {
648                                 getmnem(c, p);
649                                 return;
650                         }
651                         ungetbyte(c);
652                 }
653                 else if (c == '#') line_line();
654                 else {
655                         getlabel(c, p);
656                         return;
657                 }
658                 checkeol();
659                 if (p->em_type == EM_ERROR || p->em_type == EM_FATAL) return;
660         }
661         /*NOTREACHED*/
662 }