1 /*
2  *  Builder - builds a ZCode interpreter
3  *  Copyright (C) 2000 Andrew Hunter
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2.1 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19 
20 /*
21  * Yea, it's ugly. Hopefully not quite as ugly as doing the whole
22  * thing by hand, though...
23  *
24  * For those of you who can't be bothered reading the theory, it's
25  * basically that all the effort used here to produce the specialised
26  * interpreter is not required at runtime. The length of this file
27  * should indicate that that turns out to be quite a lot.
28  */
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 
34 #include "../config.h"
35 #undef VERSION
36 
37 #include "operation.h"
38 #ifndef APPLE_IS_ARBITRARY
39 # include "gram.h"
40 #else
41 # include "gram.tab.h"
42 #endif
43 
44 extern int    yyline;
45 extern oplist zmachine;
46 extern int    yyparse();
47 
48 static char*  filename;
49 
50 #ifndef HAVE_COMPUTED_GOTOS
51 static int    used_opcodes[256];
52 #endif
53 
sortops(const void * un,const void * deux)54 static int sortops(const void* un, const void* deux)
55 {
56   operation* one;
57   operation* two;
58 
59   one = (operation*) un;
60   two = (operation*) deux;
61 
62   if (one->type > two->type)
63     return 1;
64   else if (one->type < two->type)
65     return -1;
66   else if (one->value > two->value)
67     return 1;
68   else if (one->value < two->value)
69     return -1;
70   else
71     return 0;
72 }
73 
74 /* The various sections of code that make up an interpreter */
75 #ifndef HAVE_COMPUTED_GOTOS
76 static char* header =
77 "/*\n * Interpreter automatically generated for version %i\n * Do not alter this file\n */\n\n  switch (instr)\n    {\n";
78 
79 static char* notimpl = "    /* %s not implemented */\n";
80 #endif
81 
82 #define VERSIONS \
83 		  if (versions != -1) \
84 		    { \
85 		      fprintf(dest, "_"); \
86 		      for (z = 1; z<32; z++) \
87 			{ \
88 			  if (versions&(1<<z)) \
89 			    fprintf(dest, "%i", z); \
90 			} \
91 		    }
92 
93 #ifndef HAVE_COMPUTED_GOTOS
output_opname(FILE * dest,char * opname,int versions)94 static void output_opname(FILE* dest,
95 			  char* opname,
96 			  int   versions)
97 {
98   int z;
99 
100   fprintf(dest, "goto op_%s", opname);
101   VERSIONS;
102   fprintf(dest, ";\n");
103 }
104 #endif
105 
106 #ifndef HAVE_COMPUTED_GOTOS
output_interpreter(FILE * dest,int version)107 void output_interpreter(FILE* dest,
108 			int version)
109 {
110   int vmask;
111   int x,y;
112   int pcadd;
113 
114   for (x=0; x<256; x++)
115     used_opcodes[x] = 0;
116 
117   vmask = 1<<version;
118   fprintf(dest, header, version);
119 
120   for (x=0; x<zmachine.numops; x++)
121     {
122       operation* op;
123 
124       op = zmachine.op[x];
125       if ((op->versions&vmask && op->versions != -1) || (version==-1
126 							 && op->versions==-1))
127 	{
128 	  switch (op->type)
129 	    {
130 	      /* All possible 0OP bytes*/
131 	    case zop:
132 	      pcadd = 1;
133 	      fprintf(dest, "    case 0x%x: /* %s */\n",
134 		      op->value|0xb0, op->name);
135 
136 	      fprintf(dest, "#ifdef DEBUG\nprintf_debug(\"%s\\n\");\n#endif\n",
137 		      op->name);
138 	      used_opcodes[op->value|0xb0] = 1;
139 
140 	      if (op->flags.isstore)
141 		{
142 		  fprintf(dest, "      st = GetCode(pc+%i);\n", pcadd);
143 		  pcadd++;
144 		}
145 	      if (op->flags.isbranch)
146 		{
147 		  fprintf(dest, "      tmp = GetCode(pc+%i);\n", pcadd);
148 		  fprintf(dest, "      branch = tmp&0x3f;\n");
149 		  fprintf(dest, "      padding=0;\n");
150 		  fprintf(dest, "      if (!(tmp&0x40))\n");
151 		  fprintf(dest, "        {\n");
152 		  fprintf(dest, "          padding = 1;\n");
153 		  fprintf(dest, "          if (branch&0x20)\n");
154 		  fprintf(dest, "            branch -= 64;\n");
155 		  fprintf(dest, "          branch <<= 8;\n");
156 		  fprintf(dest, "          branch |= GetCode(pc+%i);\n",
157 			  pcadd+1);
158 		  fprintf(dest, "        }\n");
159 		  fprintf(dest, "      negate = tmp&0x80;\n");
160  		  pcadd++;
161 		}
162 	      if (op->flags.isstring)
163 		{
164 		  fprintf(dest, "#ifdef DEBUG\nprintf_debug(\"(String instruction) - decoding the string at #%%x: \", pc+%i);\n#endif\n", pcadd);
165 		  fprintf(dest, "      string = zscii_to_unicode(&GetCode(pc+%i), &padding);\n", pcadd);
166 		  fprintf(dest, "#ifdef DEBUG\nprintf_debug(\">%%s<\\n\", string);\n#endif\n");
167 		}
168 
169 	      if (op->flags.isbranch || op->flags.isstring)
170 		fprintf(dest, "      pc += %i+padding;\n", pcadd);
171 	      else
172 		fprintf(dest, "      pc += %i;\n", pcadd);
173 
174 	      fprintf(dest, "      ");
175 	      output_opname(dest, op->name, op->versions);
176 	      fprintf(dest, "\n");
177 	      break;
178 
179 	      /* All possible 1OP bytes */
180 	    case unop:
181 	      for (y=0; y<3; y++)
182 		{
183 		  pcadd = 1;
184 		  fprintf(dest, "    case 0x%x: /* %s */\n",
185 			  op->value|0x80|(y<<4), op->name);
186 
187 		  fprintf(dest, "#ifdef DEBUG\nprintf_debug(\"%s\\n\");\n#endif\n",
188 			  op->name);
189 		  used_opcodes[op->value|0x80|(y<<4)] = 1;
190 
191 		  switch (y)
192 		    {
193 		    case 0:
194 		      fprintf(dest, "      arg1 = (GetCode(pc+%i)<<8)|GetCode(pc+%i);\n", pcadd, pcadd+1);
195 		      pcadd+=2;
196 		      break;
197 
198 		    case 1:
199 		      fprintf(dest, "      arg1 = GetCode(pc+%i);\n",
200 			      pcadd);
201 		      pcadd++;
202 		      break;
203 
204 		    case 2:
205 		      fprintf(dest, "      arg1 = GetVar(GetCode(pc+%i));\n",
206 			      pcadd);
207 		      pcadd++;
208 		      break;
209 		    }
210 
211 		  if (op->flags.isstore)
212 		    {
213 		      fprintf(dest, "      st = GetCode(pc+%i);\n", pcadd);
214 		      pcadd++;
215 		    }
216 		  if (op->flags.isbranch)
217 		    {
218 		      fprintf(dest, "      tmp = GetCode(pc+%i);\n", pcadd);
219 		      fprintf(dest, "      branch = tmp&0x3f;\n");
220 		      fprintf(dest, "      padding=0;\n");
221 		      fprintf(dest, "      if (!(tmp&0x40))\n");
222 		      fprintf(dest, "        {\n");
223 		      fprintf(dest, "          padding = 1;\n");
224 		      fprintf(dest, "          if (branch&0x20)\n");
225 		      fprintf(dest, "            branch -= 64;\n");
226 		      fprintf(dest, "          branch <<= 8;\n");
227 		      fprintf(dest, "          branch |= GetCode(pc+%i);\n",
228 			      pcadd+1);
229 		      fprintf(dest, "        }\n");
230 		      fprintf(dest, "      negate = tmp&0x80;\n");
231 		      pcadd++;
232 		    }
233 		  if (op->flags.isstring)
234 		    {
235 		      fprintf(dest, "      /* Implement me */\n");
236 		    }
237 
238 		  if (op->flags.isbranch || op->flags.isstring)
239 		    fprintf(dest, "      pc += %i+padding;\n", pcadd);
240 		  else
241 		    fprintf(dest, "      pc += %i;\n", pcadd);
242 
243 		  fprintf(dest, "      ");
244 		  output_opname(dest, op->name, op->versions);
245 
246 		  fprintf(dest, "\n");
247 		}
248 	      break;
249 
250 	      /* All possible 2OP bytes */
251 	    case binop:
252 	      for (y=0; y<4; y++)
253 		{
254 		  pcadd = 1;
255 		  fprintf(dest, "    case 0x%x: /* %s */\n",
256 			  op->value|(y<<5), op->name);
257 
258 		  fprintf(dest, "#ifdef DEBUG\nprintf_debug(\"%s\\n\");\n#endif\n",
259 			  op->name);
260 		  used_opcodes[op->value|(y<<5)] = 1;
261 
262 		  if (op->flags.reallyvar)
263 		    fprintf(dest, "      argblock.n_args = 2;\n");
264 		  if (y&2)
265 		    fprintf(dest, "      arg1 = GetVar(GetCode(pc+1));\n");
266 		  else
267 		    fprintf(dest, "      arg1 = GetCode(pc+1);\n");
268 		  if (y&1)
269 		    fprintf(dest, "      arg2 = GetVar(GetCode(pc+2));\n");
270 		  else
271 		    fprintf(dest, "      arg2 = GetCode(pc+2);\n");
272 		  pcadd+=2;
273 
274 		  if (op->flags.isstore)
275 		    {
276 		      fprintf(dest, "      st = GetCode(pc+%i);\n", pcadd);
277 		      pcadd++;
278 		    }
279 		  if (op->flags.isbranch)
280 		    {
281 		      fprintf(dest, "      tmp = GetCode(pc+%i);\n", pcadd);
282 		      fprintf(dest, "      branch = tmp&0x3f;\n");
283 		      fprintf(dest, "      padding=0;\n");
284 		      fprintf(dest, "      if (!(tmp&0x40))\n");
285 		      fprintf(dest, "        {\n");
286 		      fprintf(dest, "          padding = 1;\n");
287 		      fprintf(dest, "          if (branch&0x20)\n");
288 		      fprintf(dest, "            branch -= 64;\n");
289 		      fprintf(dest, "          branch <<= 8;\n");
290 		      fprintf(dest, "          branch |= GetCode(pc+%i);\n",
291 			      pcadd+1);
292 		      fprintf(dest, "        }\n");
293 		      fprintf(dest, "      negate = tmp&0x80;\n");
294 		      pcadd++;
295 		    }
296 
297 		  if (op->flags.isbranch || op->flags.isstring)
298 		    fprintf(dest, "      pc += %i+padding;\n", pcadd);
299 		  else
300 		    fprintf(dest, "      pc += %i;\n", pcadd);
301 
302 		  fprintf(dest, "      ");
303 		  output_opname(dest, op->name, op->versions);
304 
305 		  fprintf(dest, "\n");
306 		}
307 
308 	      /*
309 	       * But that's not all, folks (yes, those zany guys at
310 	       * infocom had a *fifth* way to encode 2OPs. Which
311 	       * itself has 13 ways of representing its operands.
312 	       * Lucky me). This is all an evil plan to give me
313 	       * something better to do.
314 	       */
315 	      fprintf(dest, "    case 0x%x: /* %s - variable form */\n",
316 		      op->value|0xc0, op->name);
317 
318 	      fprintf(dest, "#ifdef DEBUG\nprintf_debug(\"%s (var form)\\n\");\n#endif\n",
319 		      op->name);
320 	      used_opcodes[op->value|0xc0] = 1;
321 
322 	      pcadd = 4;
323 #if 0
324 	      fprintf(dest, "      padding = 0;\n");
325 	      fprintf(dest, "      switch (GetCode(pc+1))\n");
326 	      fprintf(dest, "        {\n");
327 #define ARGTYPE(i) (i==0?"Large constant":(i==1?"Small constant":(i==2?"Variable":(i==3?"Omitted":"All messed up"))))
328 	      for (y=0; y<4; y++)
329  		{
330 		  for (z=3; ((z>=0&&y!=3)|(z==3&&y==3)); z--)
331 		    {
332 		      int padding;
333 
334 		      padding = 0;
335 		      fprintf(dest, "        case %i: /* arg1 - %s, arg2 - %s */\n",
336 			      (y<<6)|(z<<4)|0xf, ARGTYPE(y), ARGTYPE(z));
337 		      switch (y)
338 			{
339 			case 0:
340 			  fprintf(dest, "          arg1 = (GetCode(pc+2)<<8)|GetCode(pc+3);\n");
341 			  padding++;
342 			  break;
343 
344 			case 1:
345 			  fprintf(dest, "          arg1 = GetCode(pc+2);\n");
346 			  break;
347 
348 			case 2:
349 			  fprintf(dest, "          arg1 = GetVar(GetCode(pc+2));\n");
350 			  break;
351 
352 			case 3:
353 			  fprintf(dest, "          arg1 = 0;\n");
354 			  padding--;
355 			  break;
356 			}
357 		      switch (z)
358 			{
359 			case 0:
360 			  fprintf(dest, "          arg2 = (GetCode(pc+%i)<<8)|GetCode(pc+%i);\n",
361 				  padding+3, padding+4);
362 			  padding++;
363 			  break;
364 
365 			case 1:
366 			  fprintf(dest, "          arg2 = GetCode(pc+%i);\n",
367 				  padding+3);
368 			  break;
369 
370 			case 2:
371 			  fprintf(dest, "          arg2 = GetVar(GetCode(pc+%i));\n",
372 				  padding+3);
373 			  break;
374 
375 			case 3:
376 			  fprintf(dest, "          arg2 = 0;\n");
377 			  padding--;
378 			  break;
379 			}
380 		      if (y==3)
381 			fprintf(dest, "          omit = 0;\n");
382 		      else if (z==3)
383 			fprintf(dest, "          omit = 1;\n");
384 		      else
385 			fprintf(dest, "          omit = 2;\n");
386 
387 		      fprintf(dest, "          padding = %i;\n", padding);
388 		      fprintf(dest, "          goto loop;\n");
389 		    }
390 		}
391 	      fprintf(dest, "        default:\n");
392 	      fprintf(dest, "           zmachine_fatal(\"Invalid argument types for 2OP %s\");\n", op->name);
393 	      fprintf(dest, "        }\n");
394 #else
395 
396 	      fprintf(dest, "        padding = zmachine_decode_varop(stack, &GetCode(pc+1), &argblock)-2;\n");
397 #endif
398 
399 	      if (op->flags.isstore)
400 		{
401 		  fprintf(dest, "      st = GetCode(pc+%i+padding);\n", pcadd);
402 		  pcadd++;
403 		}
404 	      if (op->flags.isbranch)
405 		{
406 		  fprintf(dest, "      tmp = GetCode(pc+%i+padding);\n", pcadd);
407 		  fprintf(dest, "      branch = tmp&0x3f;\n");
408 		  fprintf(dest, "      if (!(tmp&0x40))\n");
409 		  fprintf(dest, "        {\n");
410 		  fprintf(dest, "          padding++;\n");
411 		  fprintf(dest, "          if (branch&0x20)\n");
412 		  fprintf(dest, "            branch -= 64;\n");
413 		  fprintf(dest, "          branch <<= 8;\n");
414 		  fprintf(dest, "          branch |= GetCode(pc+%i+padding);\n",
415 			  pcadd);
416 		  fprintf(dest, "        }\n");
417 		  fprintf(dest, "      negate = tmp&0x80;\n");
418 		  pcadd++;
419 		}
420 
421 	      fprintf(dest, "      pc += %i+padding;\n", pcadd);
422 	      fprintf(dest, "      ");
423 	      output_opname(dest, op->name, op->versions);
424 	      fprintf(dest, "\n");
425 	      break;
426 
427 	    case varop:
428 	      fprintf(dest, "    case 0x%x: /* %s */\n",
429 		      op->value|0xe0, op->name);
430 	      fprintf(dest, "#ifdef DEBUG\nprintf_debug(\"%s\\n\");\n#endif\n",
431 		      op->name);
432 	      used_opcodes[op->value|0xe0] = 1;
433 	      pcadd = 2;
434 	      if (op->flags.islong)
435 		{
436 		  fprintf(dest, "      padding = zmachine_decode_doubleop(stack, &GetCode(pc+1), &argblock);\n");
437 		  pcadd++;
438 		}
439 	      else
440 		fprintf(dest, "      padding = zmachine_decode_varop(stack, &GetCode(pc+1), &argblock);\n");
441 
442 	      if (op->flags.isstore)
443 		{
444 		  fprintf(dest, "      st = GetCode(pc+%i+padding);\n", pcadd);
445 		  pcadd++;
446 		}
447 	      if (op->flags.isbranch)
448 		{
449 		  fprintf(dest, "      tmp = GetCode(pc+%i+padding);\n", pcadd);
450 		  fprintf(dest, "      branch = tmp&0x3f;\n");
451 		  fprintf(dest, "      if (!(tmp&0x40))\n");
452 		  fprintf(dest, "        {\n");
453 		  fprintf(dest, "          padding++;\n");
454 		  fprintf(dest, "          if (branch&0x20)\n");
455 		  fprintf(dest, "            branch -= 64;\n");
456 		  fprintf(dest, "          branch <<= 8;\n");
457 		  fprintf(dest, "          branch |= GetCode(pc+%i+padding);\n",
458 			  pcadd);
459 		  fprintf(dest, "        }\n");
460 		  fprintf(dest, "      negate = tmp&0x80;\n");
461 		  pcadd++;
462 		}
463 
464 	      fprintf(dest, "      pc += %i+padding;\n", pcadd);
465 	      fprintf(dest, "      ");
466 	      output_opname(dest, op->name, op->versions);
467 	      fprintf(dest, "\n");
468 	      break;
469 
470 	    case extop:
471 	      /* Dealt with later */
472 	      break;
473 	    }
474 	}
475       else
476 	{
477 	  fprintf(dest, notimpl, op->name);
478 	}
479     }
480 
481   if (version != -1) /* Extops do not exist generally */
482     {
483       fprintf(dest, "    case 0x%x: /* Extended ops */\n", 190);
484       fprintf(dest, "      switch (GetCode(pc+1))\n");
485       fprintf(dest, "        {\n");
486 
487       for (x=0; x<zmachine.numops; x++)
488 	{
489 	  operation* op;
490 
491 	  op = zmachine.op[x];
492 
493 	  if (op->type == extop && op->versions&vmask)
494 	    {
495 	      fprintf(dest, "        case 0x%x: /* %s */\n", op->value, op->name);
496 	      fprintf(dest, "#ifdef DEBUG\nprintf_debug(\"ExtOp: %s\\n\");\n#endif\n", op->name);
497 	      pcadd = 3;
498 	      if (op->flags.islong)
499 		{
500 		  fprintf(dest, "          padding = zmachine_decode_doubleop(stack, &GetCode(pc+2), &argblock);\n");
501 		  pcadd++;
502 		}
503 	      else
504 		fprintf(dest, "          padding = zmachine_decode_varop(stack, &GetCode(pc+2), &argblock);\n");
505 
506 	      if (op->flags.isstore)
507 		{
508 		  fprintf(dest, "          st = GetCode(pc+%i+padding);\n", pcadd);
509 		  pcadd++;
510 		}
511 	      if (op->flags.isbranch)
512 		{
513 		  fprintf(dest, "          tmp = GetCode(pc+%i+padding);\n", pcadd);
514 		  fprintf(dest, "          branch = tmp&0x3f;\n");
515 		  fprintf(dest, "          if (!(tmp&0x40))\n");
516 		  fprintf(dest, "            {\n");
517 		  fprintf(dest, "              padding++;\n");
518 		  fprintf(dest, "              if (branch&0x20)\n");
519 		  fprintf(dest, "                branch -= 64;\n");
520 		  fprintf(dest, "              branch <<= 8;\n");
521 		  fprintf(dest, "              branch |= GetCode(pc+%i+padding);\n",
522 			  pcadd);
523 		  fprintf(dest, "            }\n");
524 		  fprintf(dest, "          negate = tmp&0x80;\n");
525 		  pcadd++;
526 		}
527 
528 	      fprintf(dest, "          pc+=%i+padding;\n", pcadd);
529 	      fprintf(dest, "          ");
530 	      output_opname(dest, op->name, op->versions);
531 	      fprintf(dest, "\n");
532 	    }
533 	}
534       fprintf(dest, "        default:\n");
535       if (version != -1)
536 	{
537 	  fprintf(dest, "          zmachine_fatal(\"Unknown extended opcode: %%x\", GetCode(pc+1));\n");
538 	}
539       else
540 	{
541 	  fprintf(dest, "          break;\n");
542 	}
543       fprintf(dest, "        }\n");
544     }
545 
546   fprintf(dest, "    default:\n");
547   if (version != -1)
548     {
549       fprintf(dest, "      zmachine_fatal(\"Unknown opcode: %%x\", GetCode(pc));\n");
550     }
551   else
552     {
553       fprintf(dest, "      goto version;\n");
554     }
555   fprintf(dest, "    }\n");
556 
557   fprintf(dest, "  /* Unused opcodes are:\n * ");
558   for (x=0; x<256; x++)
559     {
560       if (used_opcodes[x] == 0)
561 	fprintf(dest, "%02x ", x);
562     }
563   fprintf(dest, "\n */\n");
564 }
565 #else
566 #define DECODE_FLAGS(opf) \
567       if (opf.isbranch) \
568         strcat(name, "b"); \
569       if (opf.isstore) \
570         strcat(name, "s"); \
571       if (opf.isstring) \
572         strcat(name, "S"); \
573       if (opf.islong) \
574         strcat(name, "l"); \
575       if (opf.reallyvar)  \
576         strcat(name, "v");
577 
decode_name(enum optype type,opflags fl)578 char* decode_name(enum optype type, opflags fl)
579 {
580   static char name[256];
581   const char* prefix;
582 
583   switch(type)
584     {
585     case zop:
586       prefix = "zop";
587       break;
588 
589     case unop:
590       prefix = "unop";
591       break;
592 
593     case binop:
594       prefix = "binop";
595       break;
596 
597     case varop:
598       prefix = "varop";
599       break;
600 
601     case extop:
602       prefix = "extop";
603       break;
604 
605     default:
606       prefix = "unk";
607     }
608 
609   sprintf(name, "%s", prefix);
610   DECODE_FLAGS(fl);
611 
612   return name;
613 }
614 
output_interpreter(FILE * dest,int version)615 void output_interpreter(FILE* dest,
616 			int version)
617 {
618   /*
619    * The 'interpreter', such as it is now, is just two tables of goto
620    * addresses... We do need to work out the decode codepoints, though.
621    */
622   int x, y;
623   int vmask;
624   int pcadd;
625 
626   char* decode_table[256];
627   char* exec_table[256];
628   char* decode_ext_table[256];
629   char* exec_ext_table[256];
630 
631   vmask = 1<<version;
632 
633   for (x=0; x<256; x++)
634     {
635       decode_table[x] = exec_table[x] = decode_ext_table[x] =
636 	exec_ext_table[x] = "badop";
637     }
638 
639   /* Instruction decoders */
640   /*
641    * I'm basing this largely on my old code, hence the rather unusual way
642    * of enumerating these things. This technique at least guarantees
643    * no deadcode...
644    */
645   fprintf(dest, "#ifndef TABLES_ONLY\n");
646   for (x=0; x<zmachine.numops; x++)
647     {
648       operation* op;
649 
650       op = zmachine.op[x];
651 
652       if (op->versions&vmask)
653 	{
654 	  char* name;
655 	  char* opname;
656 
657 	  name = decode_name(op->type, op->flags);
658 	  fprintf(dest, "#ifndef D_%s\n", name);
659 	  fprintf(dest, "#define D_%s\n", name);
660 
661 	  opname = malloc(strlen(op->name) + 10);
662 	  sprintf(opname, "op_%s", op->name);
663 	  if (op->versions != -1)
664 	    {
665 	      int z;
666 	      strcat(opname, "_");
667 	      for (z = 1; z<10; z++)
668 		{
669 		  char s[2];
670 
671 		  s[0] = 48+z; s[1] = 0;
672 		  if (op->versions&(1<<z))
673 		    strcat(opname, s);
674 		}
675 	    }
676 
677 	  switch (op->type)
678 	    {
679 	    case zop:
680 	      pcadd = 1;
681 	      fprintf(dest, "  %s:\n", name);
682 
683 	      decode_table[op->value|0xb0] = malloc(strlen(name)+1);
684 	      strcpy(decode_table[op->value|0xb0], name);
685 
686 	      exec_table[op->value|0xb0] = opname;
687 
688 	      if (op->flags.isstore)
689 		{
690 		  fprintf(dest, "    st = GetCode(pc+%i);\n", pcadd);
691 		  pcadd++;
692 		}
693 	      if (op->flags.isbranch)
694 		{
695 		  fprintf(dest, "    tmp = GetCode(pc+%i);\n", pcadd);
696 		  fprintf(dest, "    branch = tmp&0x3f;\n");
697 		  fprintf(dest, "    padding=0;\n");
698 		  fprintf(dest, "    if (!(tmp&0x40))\n");
699 		  fprintf(dest, "      {\n");
700 		  fprintf(dest, "        padding = 1;\n");
701 		  fprintf(dest, "        if (branch&0x20)\n");
702 		  fprintf(dest, "          branch -= 64;\n");
703 		  fprintf(dest, "        branch <<= 8;\n");
704 		  fprintf(dest, "        branch |= GetCode(pc+%i);\n",
705 			  pcadd+1);
706 		  fprintf(dest, "      }\n");
707 		  fprintf(dest, "    negate = tmp&0x80;\n");
708  		  pcadd++;
709 		}
710 	      if (op->flags.isstring)
711 		{
712 		  fprintf(dest, "    string = zscii_to_unicode(&GetCode(pc+%i), &padding);\n", pcadd);
713 		}
714 
715 	      if (op->flags.isbranch || op->flags.isstring)
716 		fprintf(dest, "    pc += %i+padding;\n", pcadd);
717 	      else
718 		fprintf(dest, "    pc += %i;\n", pcadd);
719 
720 	      fprintf(dest, "    goto *exec[instr];\n");
721 	      fprintf(dest, "\n");
722 	      break;
723 
724 	    case unop:
725 	      for (y=0; y<3; y++)
726 		{
727 		  pcadd = 1;
728 		  fprintf(dest, "  %s_%i:\n", name, y);
729 
730 		  decode_table[op->value|0x80|(y<<4)] = malloc(strlen(name)+4);
731 		  sprintf(decode_table[op->value|0x80|(y<<4)], "%s_%i", name, y);
732 
733 		  exec_table[op->value|0x80|(y<<4)] = opname;
734 
735 		  switch (y)
736 		    {
737 		    case 0:
738 		      fprintf(dest, "    arg1 = (GetCode(pc+%i)<<8)|GetCode(pc+%i);\n", pcadd, pcadd+1);
739 		      pcadd+=2;
740 		      break;
741 
742 		    case 1:
743 		      fprintf(dest, "    arg1 = GetCode(pc+%i);\n",
744 			      pcadd);
745 		      pcadd++;
746 		      break;
747 
748 		    case 2:
749 		      fprintf(dest, "    arg1 = GetVar(GetCode(pc+%i));\n",
750 			      pcadd);
751 		      pcadd++;
752 		      break;
753 		    }
754 
755 		  if (op->flags.isstore)
756 		    {
757 		      fprintf(dest, "    st = GetCode(pc+%i);\n", pcadd);
758 		      pcadd++;
759 		    }
760 		  if (op->flags.isbranch)
761 		    {
762 		      fprintf(dest, "    tmp = GetCode(pc+%i);\n", pcadd);
763 		      fprintf(dest, "    branch = tmp&0x3f;\n");
764 		      fprintf(dest, "    padding=0;\n");
765 		      fprintf(dest, "    if (!(tmp&0x40))\n");
766 		      fprintf(dest, "      {\n");
767 		      fprintf(dest, "        padding = 1;\n");
768 		      fprintf(dest, "        if (branch&0x20)\n");
769 		      fprintf(dest, "          branch -= 64;\n");
770 		      fprintf(dest, "        branch <<= 8;\n");
771 		      fprintf(dest, "        branch |= GetCode(pc+%i);\n",
772 			      pcadd+1);
773 		      fprintf(dest, "      }\n");
774 		      fprintf(dest, "    negate = tmp&0x80;\n");
775 		      pcadd++;
776 		    }
777 		  if (op->flags.isstring)
778 		    {
779 		      fprintf(dest, "    /* Implement me */\n");
780 		    }
781 
782 		  if (op->flags.isbranch || op->flags.isstring)
783 		    fprintf(dest, "    pc += %i+padding;\n", pcadd);
784 		  else
785 		    fprintf(dest, "    pc += %i;\n", pcadd);
786 
787 		  fprintf(dest, "    goto *exec[instr];\n");
788 		  fprintf(dest, "\n");
789 		}
790 	      break;
791 
792 	    case binop:
793 	      for (y=0; y<4; y++)
794 		{
795 		  fprintf(dest, "  %s_%i:\n", name, y);
796 
797 		  decode_table[op->value|(y<<5)] = malloc(strlen(name)+4);
798 		  sprintf(decode_table[op->value|(y<<5)],
799 			  "%s_%i", name, y);
800 
801 		  exec_table[op->value|(y<<5)] = opname;
802 
803 		  pcadd = 1;
804 
805 		  if (op->flags.reallyvar)
806 		    fprintf(dest, "    argblock.n_args = 2;\n");
807 		  if (y&2)
808 		    fprintf(dest, "    arg1 = GetVar(GetCode(pc+1));\n");
809 		  else
810 		    fprintf(dest, "    arg1 = GetCode(pc+1);\n");
811 		  if (y&1)
812 		    fprintf(dest, "    arg2 = GetVar(GetCode(pc+2));\n");
813 		  else
814 		    fprintf(dest, "    arg2 = GetCode(pc+2);\n");
815 		  pcadd+=2;
816 
817 		  if (op->flags.isstore)
818 		    {
819 		      fprintf(dest, "    st = GetCode(pc+%i);\n", pcadd);
820 		      pcadd++;
821 		    }
822 		  if (op->flags.isbranch)
823 		    {
824 		      fprintf(dest, "    tmp = GetCode(pc+%i);\n", pcadd);
825 		      fprintf(dest, "    branch = tmp&0x3f;\n");
826 		      fprintf(dest, "    padding=0;\n");
827 		      fprintf(dest, "    if (!(tmp&0x40))\n");
828 		      fprintf(dest, "      {\n");
829 		      fprintf(dest, "        padding = 1;\n");
830 		      fprintf(dest, "        if (branch&0x20)\n");
831 		      fprintf(dest, "          branch -= 64;\n");
832 		      fprintf(dest, "        branch <<= 8;\n");
833 		      fprintf(dest, "        branch |= GetCode(pc+%i);\n",
834 			      pcadd+1);
835 		      fprintf(dest, "      }\n");
836 		      fprintf(dest, "    negate = tmp&0x80;\n");
837 		      pcadd++;
838 		    }
839 
840 		  if (op->flags.isbranch || op->flags.isstring)
841 		    fprintf(dest, "    pc += %i+padding;\n", pcadd);
842 		  else
843 		    fprintf(dest, "    pc += %i;\n", pcadd);
844 
845 		  fprintf(dest, "  goto *exec[instr];\n");
846 		}
847 
848 	      fprintf(dest, "  %s_var:\n", name);
849 	      pcadd = 4;
850 	      fprintf(dest, "    padding = zmachine_decode_varop(stack, &GetCode(pc+1), &argblock)-2;\n");
851 
852 	      decode_table[op->value|0xc0] = malloc(strlen(name)+5);
853 	      sprintf(decode_table[op->value|0xc0], "%s_var", name);
854 
855 	      exec_table[op->value|0xc0] = opname;
856 
857 	      if (op->flags.isstore)
858 		{
859 		  fprintf(dest, "    st = GetCode(pc+%i+padding);\n", pcadd);
860 		  pcadd++;
861 		}
862 	      if (op->flags.isbranch)
863 		{
864 		  fprintf(dest, "    tmp = GetCode(pc+%i+padding);\n", pcadd);
865 		  fprintf(dest, "    branch = tmp&0x3f;\n");
866 		  fprintf(dest, "    if (!(tmp&0x40))\n");
867 		  fprintf(dest, "      {\n");
868 		  fprintf(dest, "        padding++;\n");
869 		  fprintf(dest, "        if (branch&0x20)\n");
870 		  fprintf(dest, "          branch -= 64;\n");
871 		  fprintf(dest, "        branch <<= 8;\n");
872 		  fprintf(dest, "        branch |= GetCode(pc+%i+padding);\n",
873 			  pcadd);
874 		  fprintf(dest, "      }\n");
875 		  fprintf(dest, "    negate = tmp&0x80;\n");
876 		  pcadd++;
877 		}
878 
879 	      fprintf(dest, "    pc += %i+padding;\n", pcadd);
880 	      fprintf(dest, "    goto *exec[instr];\n");
881 	      break;
882 
883 	    case varop:
884 	      fprintf(dest, "  %s:\n", name);
885 
886 	      decode_table[op->value|0xe0] = malloc(strlen(name)+1);
887 	      strcpy(decode_table[op->value|0xe0], name);
888 
889 	      exec_table[op->value|0xe0] = opname;
890 
891 	      pcadd = 2;
892 	      if (op->flags.islong)
893 		{
894 		  fprintf(dest, "    padding = zmachine_decode_doubleop(stack, &GetCode(pc+1), &argblock);\n");
895 		  pcadd++;
896 		}
897 	      else
898 		fprintf(dest, "    padding = zmachine_decode_varop(stack, &GetCode(pc+1), &argblock);\n");
899 
900 	      if (op->flags.isstore)
901 		{
902 		  fprintf(dest, "    st = GetCode(pc+%i+padding);\n", pcadd);
903 		  pcadd++;
904 		}
905 	      if (op->flags.isbranch)
906 		{
907 		  fprintf(dest, "    tmp = GetCode(pc+%i+padding);\n", pcadd);
908 		  fprintf(dest, "    branch = tmp&0x3f;\n");
909 		  fprintf(dest, "    if (!(tmp&0x40))\n");
910 		  fprintf(dest, "      {\n");
911 		  fprintf(dest, "        padding++;\n");
912 		  fprintf(dest, "        if (branch&0x20)\n");
913 		  fprintf(dest, "          branch -= 64;\n");
914 		  fprintf(dest, "        branch <<= 8;\n");
915 		  fprintf(dest, "        branch |= GetCode(pc+%i+padding);\n",
916 			  pcadd);
917 		  fprintf(dest, "      }\n");
918 		  fprintf(dest, "    negate = tmp&0x80;\n");
919 		  pcadd++;
920 		}
921 
922 	      fprintf(dest, "    pc += %i+padding;\n", pcadd);
923 	      fprintf(dest, "    goto *exec[instr];\n");
924 	      break;
925 
926 	    case extop:
927 	      fprintf(dest, "  %s:\n", name);
928 
929 	      decode_ext_table[op->value] = malloc(strlen(name)+1);
930 	      strcpy(decode_ext_table[op->value], name);
931 
932 	      exec_ext_table[op->value] = opname;
933 
934 	      pcadd = 3;
935 	      if (op->flags.islong)
936 		{
937 		  fprintf(dest, "    padding = zmachine_decode_doubleop(stack, &GetCode(pc+2), &argblock);\n");
938 		  pcadd++;
939 		}
940 	      else
941 		fprintf(dest, "    padding = zmachine_decode_varop(stack, &GetCode(pc+2), &argblock);\n");
942 
943 	      if (op->flags.isstore)
944 		{
945 		  fprintf(dest, "    st = GetCode(pc+%i+padding);\n", pcadd);
946 		  pcadd++;
947 		}
948 	      if (op->flags.isbranch)
949 		{
950 		  fprintf(dest, "    tmp = GetCode(pc+%i+padding);\n", pcadd);
951 		  fprintf(dest, "    branch = tmp&0x3f;\n");
952 		  fprintf(dest, "    if (!(tmp&0x40))\n");
953 		  fprintf(dest, "      {\n");
954 		  fprintf(dest, "        padding++;\n");
955 		  fprintf(dest, "        if (branch&0x20)\n");
956 		  fprintf(dest, "          branch -= 64;\n");
957 		  fprintf(dest, "        branch <<= 8;\n");
958 		  fprintf(dest, "        branch |= GetCode(pc+%i+padding);\n",
959 			  pcadd);
960 		  fprintf(dest, "      }\n");
961 		  fprintf(dest, "    negate = tmp&0x80;\n");
962 		  pcadd++;
963 		}
964 
965 	      fprintf(dest, "    pc+=%i+padding;\n", pcadd);
966 	      fprintf(dest, "    goto *exec_ext[instr];\n");
967 	      break;
968 	    }
969 
970 	  fprintf(dest, "#endif\n");
971 	}
972     }
973 
974   decode_table[190] = "execute_ext_op";
975 
976   fprintf(dest, "#else\n");
977   /* Output the tables */
978   if (version > 0)
979     {
980       fprintf (dest, "  static const void* decode_v%i[256] = {", version);
981       for (x=0; x<256; x++)
982 	{
983 	  if ((x&0x3) == 0)
984 	    fprintf(dest, "\n    ");
985 	  fprintf(dest, "&&%s,\t", decode_table[x]);
986 	}
987       fprintf(dest, "\n  };\n");
988 
989       fprintf (dest, "  static const void* decode_ext_v%i[256] = {", version);
990       for (x=0; x<256; x++)
991 	{
992 	  if ((x&0x3) == 0)
993 	    fprintf(dest, "\n    ");
994 	  fprintf(dest, "&&%s,\t", decode_ext_table[x]);
995 	}
996       fprintf(dest, "\n  };\n");
997 
998       fprintf (dest, "  static const void* exec_v%i[256] = {", version);
999       for (x=0; x<256; x++)
1000 	{
1001 	  if ((x&0x3) == 0)
1002 	    fprintf(dest, "\n    ");
1003 	  fprintf(dest, "&&%s,\t", exec_table[x]);
1004 	}
1005       fprintf(dest, "\n  };\n");
1006 
1007       fprintf (dest, "  static const void* exec_ext_v%i[256] = {", version);
1008       for (x=0; x<256; x++)
1009 	{
1010 	  if ((x&0x3) == 0)
1011 	    fprintf(dest, "\n    ");
1012 	  fprintf(dest, "&&%s,\t", exec_ext_table[x]);
1013 	}
1014       fprintf(dest, "\n  };\n");
1015    }
1016   fprintf(dest, "#endif\n");
1017 }
1018 #endif
1019 
output_operations(FILE * dest,int ver)1020 void output_operations(FILE* dest,
1021 		       int   ver)
1022 {
1023   int x, z;
1024   int versions, vmask;
1025 
1026   vmask = 1<<ver;
1027 
1028   for (x=0; x<zmachine.numops; x++)
1029     {
1030       operation* op;
1031 
1032       op = zmachine.op[x];
1033 
1034       versions = op->versions;
1035       if ((op->versions&vmask && op->versions != -1) ||
1036 	  (ver==-1 && op->versions == -1))
1037       {
1038 	fprintf(dest, "#ifndef ZCODE_OP_%s", op->name);
1039 	VERSIONS;
1040 	fprintf(dest, "\n");
1041 	fprintf(dest, "# define ZCODE_OP_%s", op->name);
1042 	VERSIONS;
1043 	fprintf(dest, "\n");
1044 
1045 	fprintf(dest, "  op_%s", op->name);
1046 	VERSIONS;
1047 	fprintf(dest, ":\n");
1048 
1049 	if (op->code == NULL)
1050 	  fprintf(dest, "    zmachine_warning(\"%s not implemented\");\n", op->name);
1051 	else
1052 	  {
1053 	    fprintf(dest, "    {\n");
1054 	    fprintf(dest, "#line %i \"%s\"\n", op->codeline, filename);
1055 	    fprintf(dest, "%s\n", op->code);
1056 	    fprintf(dest, "    }\n");
1057 	  }
1058 
1059 	fprintf(dest, "    goto loop;\n\n");
1060 	fprintf(dest, "#endif\n");
1061       }
1062     }
1063 }
1064 
1065 extern FILE* yyin;
1066 
main(int argc,char ** argv)1067 int main(int argc, char** argv)
1068 {
1069   if (argc==4)
1070     {
1071       FILE* output;
1072 
1073       if (!(yyin = fopen(filename=argv[3], "r")))
1074 	{
1075 	  fprintf(stderr, "Couldn't open input file\n");
1076 	  return 1;
1077 	}
1078 
1079 	  printf("Zoom interpreter builder");
1080 #ifndef HAVE_COMPUTED_GOTOS
1081 	  printf(" (using giant switch statement)\n");
1082 #else
1083 	  printf(" (using computed GOTOs)\n");
1084 #endif
1085 
1086       yyline          = 1;
1087       zmachine.numops = 0;
1088       zmachine.op     = NULL;
1089       yyparse();
1090 
1091       qsort(zmachine.op, zmachine.numops-1, sizeof(operation*), sortops);
1092 
1093       if ((output = fopen(argv[1], "w")))
1094 	{
1095 	  output_interpreter(output, atoi(argv[2]));
1096 	  fprintf(output, "#ifndef TABLES_ONLY\n");
1097 	  output_operations(output, atoi(argv[2]));
1098 	  fprintf(output, "#endif\n");
1099 	  fclose(output);
1100 	}
1101       else
1102 	{
1103 	  fprintf(stderr, "Couldn't output open file\n");
1104 	  return 1;
1105 	}
1106     }
1107   else
1108     {
1109       fprintf(stderr, "Incorrect arguments\n");
1110       return 1;
1111     }
1112 
1113   return 0;
1114 }
1115