1 /* ======================================================================== */
2 /* World assembler for Lunar MP. */
3 /* This is my THIRD(!) attempt at a world encoding. */
4 /* */
5 /* Syntax: */
6 /* [loc] LABEL 'label_name' -- Align to word and emit asm label. */
7 /* loc CUE num -- Cue creeps with cue 'num' 1 unit */
8 /* loc CUE 'label' -- Cue creeps with cue 'label' 1 unit */
9 /* loc ROCK1 -- Small rock 2 units */
10 /* loc ROCK2 -- Medium rock 2 units */
11 /* loc ROCK3 -- Large rock 3 units */
12 /* loc CRAT1 -- Small crater 2 units */
13 /* loc CRAT2 -- Large crater 3 units */
14 /* loc FILLTO -- Fill up to but not including 'loc' */
15 /* loc LEVEL 'char' -- Cue a level marker 1 unit */
16 /* loc CAUTION num -- Cue a caution light 1 unit */
17 /* loc EXIT num -- Tell some creeps to exit 1 unit */
18 /* loc EXIT 'label' -- Tell some creeps to exit 1 unit */
19 /* */
20 /* */
21 /* Numbers are all in decimal. See design notes below for details. */
22 /* Blank lines are ignored. Anything after a # mark is ignored. */
23 /* Whitespace is compressed, and everything outside quotes is case- */
24 /* insensitive. (Note, whitespace isn't really allowed in quotes, */
25 /* though I don't really check for it.) */
26 /* */
27 /* Although the objects allow specifying a location, the assembler */
28 /* requires you to state the objects in monotonically increasing order. */
29 /* All objects (including cues) have an implicit width that must be */
30 /* taken into account when specifying object location. No two objects */
31 /* may be co-located. This includes cues which have a minimum width */
32 /* of 1 (to stagger the processing burden). */
33 /* ======================================================================== */
34
35 /* ======================================================================== */
36 /* WORLD DATA encoding format -- design ramblings. */
37 /* */
38 /* The world data format is really quite simple: */
39 /* */
40 /* Bits 0..7 Encoded object/cue number. */
41 /* Bits 8..14 Delay until next word is processed. */
42 /* Bit 15 Object or cue? 0 == object, 1 == cue. */
43 /* */
44 /* For objects, the lower 8 bits are an index into the tables RCS1/RCS2. */
45 /* For cues, the lower 8 bits are an index into the SPAWNS table. (The */
46 /* details of the SPAWNS table TBD.) */
47 /* */
48 /* This format is a much simpler format than previous attempts. Why? */
49 /* I noticed that the compression ratio achieved by the more clever */
50 /* encodings was pretty lackluster (about 20% for attempt #2), and the */
51 /* work required to decode it was non-trivial. At the very least, there */
52 /* was too much state to carry around. With this scheme, the only state */
53 /* required is a pointer to the current word, and a down-counter. :-) */
54 /* ======================================================================== */
55
56
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <ctype.h>
61
62
63 #define Q(x) #x
64 #define X(x) x
65
66 #define MAX_LEVEL (4096)
67 #define FL_NOP (0)
68 #define FL_OBJ (1)
69 #define FL_CUE (2)
70
71 #define CMD_BLANK (7)
72
73 typedef struct
74 {
75 char *label;
76 char *cuelbl;
77 unsigned char flag;
78 unsigned short count;
79 int object;
80 } level_t;
81
82 FILE *f_out;
83
84
85 int cur_pos = 0;
86 int last_pos = 0;
87 level_t level[MAX_LEVEL];
88
89
90 /* ======================================================================== */
91 /* MOVE_TO -- Add blanks to the run of blanks. This doesn't actually */
92 /* emit any blanks until something non-blank is emitted. */
93 /* ======================================================================== */
move_to(int new_loc)94 void move_to(int new_loc)
95 {
96 if (new_loc < 0 || new_loc >= MAX_LEVEL)
97 {
98 fprintf(stderr, "ERROR: Location %d must be in the range 0 to %d\n",
99 new_loc, MAX_LEVEL);
100 exit(1);
101 }
102 cur_pos = new_loc;
103 if (cur_pos > last_pos)
104 last_pos = cur_pos;
105 }
106
107 /* ======================================================================== */
108 /* CMD_LABEL -- Record a location as needing a label. */
109 /* ======================================================================== */
cmd_label(char * label)110 void cmd_label(char *label)
111 {
112 char *lbl_copy;
113
114 if (level[cur_pos].label != NULL)
115 {
116 fprintf(stderr, "ERROR: Attempt to add '%s' as label to '%d',\n"
117 " which already has label '%s'\n",
118 label, cur_pos, level[cur_pos].label);
119 exit(1);
120 }
121
122 lbl_copy = strdup(label);
123 if (!lbl_copy)
124 {
125 fprintf(stderr, "ERROR: Out of memory in strdup. Buy some more.\n");
126 exit(1);
127 }
128 level[cur_pos].label = lbl_copy;
129 }
130
131
132 /* ======================================================================== */
133 /* CMD_CUE -- Cue some creeps. */
134 /* ======================================================================== */
cmd_cue(int cue)135 void cmd_cue(int cue)
136 {
137 if (level[cur_pos].flag != FL_NOP)
138 {
139 fprintf(stderr, "ERROR: Trying to add CUE to occupied location %d!\n",
140 cur_pos);
141 exit(1);
142 }
143
144 level[cur_pos].cuelbl = NULL;
145 level[cur_pos].object = cue;
146 level[cur_pos].flag = FL_CUE;
147 level[cur_pos].count = 1;
148
149 move_to(cur_pos + 1);
150 }
151
152 /* ======================================================================== */
153 /* CMD_CUELBL -- cue, via label (preferred) */
154 /* ======================================================================== */
cmd_cuelbl(char * cue)155 void cmd_cuelbl(char *cue)
156 {
157 char *lbl_copy;
158
159 if (level[cur_pos].flag != FL_NOP)
160 {
161 fprintf(stderr, "ERROR: Trying to add CUE to occupied location %d!\n",
162 cur_pos);
163 exit(1);
164 }
165
166 lbl_copy = strdup(cue);
167 if (!lbl_copy)
168 {
169 fprintf(stderr, "ERROR: Out of memory in strdup. Buy some more.\n");
170 exit(1);
171 }
172
173 level[cur_pos].cuelbl = lbl_copy;
174 level[cur_pos].object = 0;
175 level[cur_pos].flag = FL_CUE;
176 level[cur_pos].count = 1;
177
178 move_to(cur_pos + 1);
179 }
180
181 /* ======================================================================== */
182 /* CMD_EXIT -- Cue some creeps to leave */
183 /* ======================================================================== */
cmd_exit(int cue)184 void cmd_exit(int cue)
185 {
186 if (level[cur_pos].flag != FL_NOP)
187 {
188 fprintf(stderr, "ERROR: Trying to add EXIT to occupied location %d!\n",
189 cur_pos);
190 exit(1);
191 }
192
193 level[cur_pos].cuelbl = NULL;
194 level[cur_pos].object = cue + 256;
195 level[cur_pos].flag = FL_CUE;
196 level[cur_pos].count = 1;
197
198 move_to(cur_pos + 1);
199 }
200
201 /* ======================================================================== */
202 /* CMD_EXITLBL -- exit, via label (preferred) */
203 /* ======================================================================== */
cmd_exitlbl(char * cue)204 void cmd_exitlbl(char *cue)
205 {
206 char *lbl_copy;
207
208 if (level[cur_pos].flag != FL_NOP)
209 {
210 fprintf(stderr, "ERROR: Trying to add EXIT to occupied location %d!\n",
211 cur_pos);
212 exit(1);
213 }
214
215 lbl_copy = strdup(cue);
216 if (!lbl_copy)
217 {
218 fprintf(stderr, "ERROR: Out of memory in strdup. Buy some more.\n");
219 exit(1);
220 }
221
222 level[cur_pos].cuelbl = lbl_copy;
223 level[cur_pos].object = 256;
224 level[cur_pos].flag = FL_CUE;
225 level[cur_pos].count = 1;
226
227 move_to(cur_pos + 1);
228 }
229
230 char *cmd_name[9] =
231 {
232 "ROCK1",
233 "ROCK2",
234 "ROCK3",
235 "CRAT1",
236 "CRAT2",
237 "CRAT3",
238 "CRAT4",
239 "BLANK",
240 "CUE",
241 };
242
243 char *cmd_lbl[15] =
244 {
245 "@@rock1",
246 "@@rock2",
247 "@@rock3",
248 "@@crat1",
249 "@@crat2",
250 "@@crat3",
251 "@@crat4",
252 "@@blank",
253 "@@cue",
254 "@@level",
255 "@@caut0",
256 "@@caut1",
257 "@@caut2",
258 "@@caut3",
259 "@@exit",
260 };
261
262 int cmd_width[14] = { 2, 2, 3, 2, 3, 5, 5, 1, 1, 1, 1, 1, 1 };
263
264 /* ======================================================================== */
265 /* CMD_OBJECT -- Put an object into the level */
266 /* ======================================================================== */
cmd_object(int n)267 void cmd_object(int n)
268 {
269 if (level[cur_pos].flag != FL_NOP)
270 {
271 fprintf(stderr, "ERROR: Trying to add %s to occupied location %d!\n",
272 cmd_name[n], cur_pos);
273 exit(1);
274 }
275
276 level[cur_pos].object = n;
277 level[cur_pos].flag = FL_OBJ;
278
279 move_to(cur_pos + cmd_width[n]);
280 }
281
282 /* ======================================================================== */
283 /* CMD_LEVEL -- Put an end-of-level marker cue into the level data */
284 /* ======================================================================== */
cmd_level(int n)285 void cmd_level(int n)
286 {
287 if (level[cur_pos].flag != FL_NOP)
288 {
289 fprintf(stderr, "ERROR: Trying to add LEVEL to occupied location %d!\n",
290 cur_pos);
291 exit(1);
292 }
293
294 if (n >= 'A' && n <= 'Z') n = n - 'A';
295 else if (n >= 'a' && n <= 'z') n = n - 'a' + 0x20;
296
297 level[cur_pos].object = n + 32;
298 level[cur_pos].flag = FL_OBJ;
299
300 move_to(cur_pos + 1);
301 }
302
303 /* ======================================================================== */
304 /* CANONICALIZE -- Canonicalizes an input line. */
305 /* ======================================================================== */
canonicalize(char * buf)306 int canonicalize(char *buf)
307 {
308 char *s1, *s2;
309 int in_quote = 0;
310
311 /* Kill any comments or newlines. */
312 if ((s1 = strchr(buf, '#' )) != NULL) *s1 = 0;
313 if ((s1 = strchr(buf, '\r')) != NULL) *s1 = 0;
314 if ((s1 = strchr(buf, '\n')) != NULL) *s1 = 0;
315
316 /* Kill leading whitespace. */
317 s1 = s2 = buf;
318
319 while (*s1 && isspace(*s1)) s1++;
320
321 if (!*s1) { buf[0] = 0; return 0; }
322
323 /* Compress remaining whitespace */
324 while (*s1)
325 {
326 while (!isspace(*s1))
327 *s2++ = *s1++;
328
329 *s2++ = ' '; /* compressed whitespace */
330
331 if (!*s1)
332 break;
333
334 while (isspace(*s1))
335 s1++;
336 }
337
338 *s2 = 0;
339
340 if (s2 == buf)
341 return 0;
342
343
344 /* Re-scan, uppercasing anything lowercase */
345 s1 = buf;
346 while (*s1)
347 {
348 if (*s1 == '\'')
349 in_quote ^= 1;
350
351 if (!in_quote && isalpha(*s1))
352 *s1 = toupper(*s1);
353
354 s1++;
355 }
356
357 return s1 - buf;
358 }
359
360 #define MAX_WORD (64)
361
362 char word1[MAX_WORD];
363 char word2[MAX_WORD];
364 char label[MAX_WORD];
365 int num1, num2;
366
367 /* ======================================================================== */
368 /* PARSE -- Pull a line apart into words. */
369 /* ======================================================================== */
parse(char * buf)370 int parse(char *buf)
371 {
372 char *s1, *s2;
373 int len, lbl, word;
374
375 word1[0] = word2[0] = label[0] = 0;
376 num1 = num2 = -1;
377 word = 0;
378 lbl = 0;
379
380 if (!canonicalize(buf))
381 return 0;
382
383 s1 = buf;
384
385 while (*s1)
386 {
387 if (*s1 == ' ')
388 {
389 s1++;
390 continue;
391 }
392 if (isalpha(*s1))
393 {
394 if (word == 2)
395 {
396 printf("PARSE ERROR: too many words at %s\n", s1);
397 return -1; /* too many words */
398 }
399 s2 = word == 0 ? word1 : word2;
400 word++;
401
402 for (len = 0; len < MAX_WORD-1 && *s1 && isalnum(*s1); len++)
403 *s2++ = *s1++;
404 *s2++ = 0;
405
406 if (*s1) s1++;
407 continue;
408 }
409
410 if (*s1 == '\'')
411 {
412 if (lbl == 1)
413 {
414 printf("PARSE ERROR: too many labels at %s\n", s1);
415 return -1; /* too many labels */
416 }
417
418 lbl = 1;
419
420 s1++;
421 s2 = label;
422 for (len = 0; len < MAX_WORD-1 && *s1 && *s1 != '\''; len++)
423 *s2++ = *s1++;
424 *s2++ = 0;
425
426 if (*s1 != '\'')
427 {
428 printf("PARSE ERROR: bad label syntax\n");
429 return -1; /* bad label syntax */
430 }
431 s1++;
432 continue;
433 }
434
435 if (isdigit(*s1))
436 {
437 if (num1 < 0) num1 = atoi(s1);
438 else if (num2 < 0) num2 = atoi(s1);
439 else
440 {
441 printf("PARSE ERROR: too many numbers at %s\n", s1);
442 return -1; /* too many numbers */
443 }
444
445 while (*s1 && isdigit(*s1))
446 s1++;
447 continue;
448 }
449
450 printf("PARSE ERROR: unexpected character '%c'\n", *s1);
451 return -1;
452 }
453
454 return 1;
455 }
456
457
458 char * keyword[] =
459 {
460 "ROCK1", /* 0 */
461 "ROCK2", /* 1 */
462 "ROCK3", /* 2 */
463 "CRAT1", /* 3 */
464 "CRAT2", /* 4 */
465 "FILLTO", /* 5 */
466 "CUE", /* 6 */
467 "LABEL", /* 7 */
468 "LEVEL", /* 8 */
469 "CAUTION", /* 9 */
470 "EXIT", /* 10 */
471 "CRAT3", /* 11 */
472 "CRAT4", /* 12 */
473 };
474
475
476
477 #define NUM_KEYWORD (sizeof(keyword) / sizeof(char *))
478
479 /* ======================================================================== */
480 /* HANDLE_LINE -- Parse the line, and if it's not empty, execute it. */
481 /* ======================================================================== */
handle_line(char * buf)482 void handle_line(char *buf)
483 {
484 int i, cmd;
485
486 i = parse(buf);
487
488 if (i < 0)
489 {
490 printf("PARSE ERROR: \"%s\"\n", buf);
491 exit(1);
492 }
493
494 if (!i)
495 return;
496
497 cmd = -1;
498 for (i = 0; i < NUM_KEYWORD; i++)
499 if (!strcmp(keyword[i], word1))
500 {
501 cmd = i;
502 break;
503 }
504
505 if (num1 >= 0)
506 move_to(num1);
507
508 /* Check for location argument / required first argument */
509 switch (cmd)
510 {
511 case 0: case 1: case 2: case 3: case 4: /* ROCKn, CRATn */
512 case 5: /* FILLTO */
513 case 11: case 12:
514 {
515 if (num1 < 0)
516 {
517 fprintf(stderr, "ERROR: Location required for %s.",
518 keyword[cmd]);
519 exit(1);
520 }
521
522 break;
523 }
524 case 6: /* CUE */
525 case 10: /* EXIT */
526 {
527 if (num1 < 0)
528 {
529 fprintf(stderr, "ERROR: Location required for %s.",
530 keyword[cmd]);
531 exit(1);
532 }
533 if ((num2 < 0) == (label[0] == 0))
534 {
535 fprintf(stderr, "ERROR: %s requires number or label, "
536 "but not both\n", keyword[cmd]);
537 exit(1);
538 }
539 break;
540 }
541 case 9: /* CAUTION */
542 {
543 if (num1 < 0)
544 {
545 fprintf(stderr, "ERROR: Location required for %s.",
546 keyword[cmd]);
547 exit(1);
548 }
549 if (num2 < 0 || num2 > 3)
550 {
551 fprintf(stderr, "ERROR: Caution requires number from 0 to 2\n");
552 exit(1);
553 }
554 break;
555 }
556
557 case 7: /* LABEL */
558 case 8: /* LEVEL */
559 {
560 if (label[0] == 0)
561 {
562 printf("No label with LABEL/LEVEL directive\n");
563 exit(1);
564 }
565
566 if (cmd == 8 &&
567 (label[1] != 0 ||
568 !((label[0] >= 'A' && label[0] <= 'Z') ||
569 (label[0] >= 'a' && label[0] <= 'z'))
570 )
571 )
572 {
573 printf("Label must be single alpha char for LEVEL directive\n");
574 exit(1);
575 }
576
577
578 break;
579 }
580
581 default:
582 break;
583 }
584
585
586 /* Actually process the command. */
587 switch (cmd)
588 {
589 case 0: case 1: case 2: case 3: case 4: /* ROCKn, CRATn */
590 {
591 cmd_object(cmd);
592 break;
593 }
594 case 11: case 12: /* CRAT3/4 */
595 {
596 cmd_object(cmd - 6);
597 break;
598 }
599
600 case 9:
601 {
602 cmd_object(num2 + 10);
603 break;
604 }
605
606 case 5: /* FILLTO */
607 {
608 break;
609 }
610
611 case 6: /* CUE */
612 {
613 if (label[0] != 0)
614 {
615 cmd_cuelbl(label);
616 break;
617 }
618
619 if (num2 < 0 || num2 > 127)
620 {
621 printf("Numeric argument %d out of range for CUE\n", num1);
622 exit(1);
623 }
624
625 cmd_cue(num2);
626 break;
627 }
628
629
630 case 10: /* EXIT */
631 {
632 if (label[0] != 0)
633 {
634 cmd_exitlbl(label);
635 break;
636 }
637
638 if (num2 < 0 || num2 > 31)
639 {
640 printf("Numeric argument %d out of range for EXIT\n", num1);
641 exit(1);
642 }
643
644 cmd_exit(num2);
645 break;
646 }
647
648
649 case 7: /* LABEL */
650 {
651 cmd_label(label);
652 break;
653 }
654
655 case 8:
656 {
657 cmd_level(label[0]);
658 break;
659 }
660
661 default:
662 {
663 printf("Unknown command '%s'\nInput: '%s'\n", word1, buf);
664 exit(1);
665 break;
666 }
667 }
668 }
669
670 /* ======================================================================== */
671 /* GENERATE_LEVEL */
672 /* ======================================================================== */
generate_level(void)673 void generate_level(void)
674 {
675 int i, j, run;
676 int cmd = CMD_BLANK, cue = 0; /* BLANK */
677 int tot_words = 0;
678 int tot_cmds = 0;
679 int tot_objs = 0;
680 int tot_count = 0;
681 char *lbl = level[0].label;
682 char *cuelbl = level[0].cuelbl;
683
684 if (level[0].flag == FL_NOP)
685 {
686 cmd = CMD_BLANK;
687 cue = 0;
688 } else if (level[0].flag == FL_OBJ)
689 {
690 cmd = level[0].object;
691 } else
692 {
693 cmd = 1000;
694 cue = level[0].object;
695 cuelbl = level[0].cuelbl;
696 }
697
698 run = 1;
699
700 /* -------------------------------------------------------------------- */
701 /* Pass 1: Trace through level[] and run-length encode. */
702 /* -------------------------------------------------------------------- */
703 for (i = 1, j = 0; i <= last_pos; i++)
704 {
705 if (i != (last_pos) &&
706 level[i].flag == FL_NOP &&
707 level[i].label == NULL)
708 {
709 run++;
710 continue;
711 }
712
713 if (cmd != 1000)
714 {
715 level[j].flag = FL_OBJ;
716 level[j].object = cmd;
717 level[j].count = run;
718 level[j].label = lbl;
719 tot_objs++;
720 } else
721 {
722 level[j].flag = FL_CUE;
723 level[j].object = cue;
724 level[j].cuelbl = cuelbl;
725 level[j].count = run;
726 level[j].label = lbl;
727 tot_cmds++;
728 }
729
730 run = 1;
731 j++;
732 lbl = level[i].label;
733 if (level[i].flag == FL_OBJ)
734 {
735 cmd = level[i].object;
736 } else if (level[i].flag == FL_CUE)
737 {
738 cmd = 1000;
739 cue = level[i].object;
740 cuelbl = level[i].cuelbl;
741 } else
742 {
743 cmd = CMD_BLANK;
744 }
745
746 }
747
748 if (cmd != 1000)
749 {
750 level[j].flag = FL_OBJ;
751 level[j].object = cmd;
752 level[j].count = run;
753 level[j].label = lbl;
754 tot_objs++;
755 } else
756 {
757 level[j].flag = FL_CUE;
758 level[j].cuelbl = cuelbl;
759 level[j].object = cue;
760 level[j].count = run;
761 level[j].label = lbl;
762 tot_cmds++;
763 }
764
765 tot_words = ++j;
766
767
768 fprintf(f_out,
769 ";; ====================================="
770 "=================================== ;;\n"
771 " IF (DEFINED @@rock1) = 0\n"
772 "@@rock1 EQU ((RCS1.rock1 - RCS1 + 1) SHL 8)\n"
773 "@@rock2 EQU ((RCS1.rock2 - RCS1 + 1) SHL 8)\n"
774 "@@rock3 EQU ((RCS1.rock3 - RCS1 + 1) SHL 8)\n"
775 "@@crat1 EQU ((RCS1.crat1 - RCS1 + 1) SHL 8)\n"
776 "@@crat2 EQU ((RCS1.crat2 - RCS1 + 1) SHL 8)\n"
777 "@@crat3 EQU ((RCS1.crat3 - RCS1 + 1) SHL 8)\n"
778 "@@crat4 EQU ((RCS1.crat4 - RCS1 + 1) SHL 8)\n"
779 "@@blank EQU ((RCS1.blank - RCS1 + 1) SHL 8)\n"
780 "@@caut0 EQU $1C00\n"
781 "@@caut1 EQU $1D00\n"
782 "@@caut2 EQU $1E00\n"
783 "@@caut3 EQU $1F00\n"
784 "@@level EQU $2000\n"
785 "@@exit EQU $6000\n"
786 "@@cue EQU $8000\n"
787 " ENDI\n"
788 ";; ====================================="
789 "=================================== ;;\n");
790
791 /* -------------------------------------------------------------------- */
792 /* Pass 2: Emit the run-length encoded data. */
793 /* -------------------------------------------------------------------- */
794 for (i = 0; i < tot_words; i++)
795 {
796 if (level[i].label)
797 fprintf(f_out, "%s:\n", level[i].label);
798
799 if (level[i].flag == FL_CUE && level[i].object < 256)
800 {
801 if (level[i].cuelbl == NULL)
802 {
803 fprintf(f_out, " DECLE %-8s + (%3d - 1) + (%3d SHL 8) "
804 "; $%.4X %4d CUE %d\n",
805 cmd_lbl[8], level[i].count, level[i].object,
806 i, tot_count, level[i].object);
807 } else if (level[i].cuelbl != NULL)
808 {
809 fprintf(f_out, " DECLE %-8s + (%3d - 1) + CUE.%-12s"
810 "; $%.4X %4d CUE '%s'\n",
811 cmd_lbl[8], level[i].count, level[i].cuelbl,
812 i, tot_count, level[i].cuelbl);
813 }
814 } else if (level[i].flag == FL_CUE && level[i].object >= 256)
815 {
816 if (level[i].cuelbl == NULL)
817 {
818 fprintf(f_out, " DECLE %-8s + (%3d - 1) + (%3d SHL 8) "
819 "; $%.4X %4d EXIT %d\n",
820 cmd_lbl[14], level[i].count, level[i].object - 256,
821 i, tot_count, level[i].object - 256);
822 } else if (level[i].cuelbl != NULL)
823 {
824 fprintf(f_out, " DECLE %-8s + (%3d - 1) + EXIT.%-11s"
825 "; $%.4X %4d EXIT '%s'\n",
826 cmd_lbl[14], level[i].count, level[i].cuelbl,
827 i, tot_count, level[i].cuelbl);
828 }
829 }
830 if (level[i].flag == FL_OBJ && level[i].object < 10)
831 {
832 fprintf(f_out, " DECLE %-8s + (%3d - 1) "
833 "; $%.4X %4d %s\n",
834 cmd_lbl[level[i].object], level[i].count,
835 i, tot_count, cmd_name[level[i].object]);
836 }
837 if (level[i].flag == FL_OBJ &&
838 level[i].object < 32 &&
839 level[i].object >= 10)
840
841 {
842 fprintf(f_out, " DECLE %-8s + (%3d - 1) "
843 "; $%.4X %4d CAUTION %d\n",
844 cmd_lbl[level[i].object], level[i].count,
845 i, tot_count, level[i].object - 10);
846 }
847 if (level[i].flag == FL_OBJ && level[i].object >= 32)
848 {
849 fprintf(f_out, " DECLE %-8s + (%3d - 1) + (%3d SHL 8) "
850 "; $%.4X %4d LEVEL '%c'\n",
851 cmd_lbl[9], level[i].count, level[i].object - 32,
852 i, tot_count,
853 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
854 "abcdefghijklmnopqrstuvwxyz"[level[i].object - 32]);
855 }
856
857 if (level[i].flag == FL_NOP)
858 {
859 fprintf(stderr, "ERROR: FL_NOP in pass 2?\n");
860 exit(1);
861 }
862
863 tot_count += level[i].count;
864 }
865
866 fprintf(f_out, " "
867 "; %4d END\n", tot_count);
868
869 /* -------------------------------------------------------------------- */
870 /* Print summary information. */
871 /* -------------------------------------------------------------------- */
872 #if 0
873 printf( ";; ====================================="
874 "=================================== ;;\n"
875 ";; SUMMARY\n"
876 ";; TOTAL COMMANDS %8d\n"
877 ";; TOTAL OBJECTS %8d\n"
878 ";; TOTAL WORDS %8d\n"
879 ";; ====================================="
880 "=================================== ;;\n",
881 tot_cmds, tot_objs, tot_words);
882 #endif
883 fprintf(f_out,
884 "\n\n"
885 ";; ====================================="
886 "=================================== ;;\n"
887 ";; SUMMARY\n"
888 ";; TOTAL COMMANDS %8d\n"
889 ";; TOTAL OBJECTS %8d\n"
890 ";; TOTAL WORDS %8d\n"
891 ";; ====================================="
892 "=================================== ;;\n",
893 tot_cmds, tot_objs, tot_words);
894 }
895
896 /* ======================================================================== */
897 /* MAIN -- where it all happens */
898 /* */
899 /* Usage: wasm outfile infile [infile [infile [...]]] */
900 /* ======================================================================== */
main(int argc,char * argv[])901 int main(int argc, char *argv[])
902 {
903 FILE *f_in;
904 int i;
905 char buf[1024];
906
907 if (argc < 3)
908 {
909 printf("Usage: wasm outfile infile [infile [infile [...]]]\n");
910 exit(1);
911 }
912
913
914 for (i = 2; i < argc; i++)
915 {
916 printf("Processing '%s'\n", argv[i]);
917 f_in = fopen(argv[i], "r");
918 if (!f_in)
919 {
920 printf("could not open '%s' for reading\n", argv[i]);
921 exit(1);
922 }
923
924 while (fgets(buf, 1024, f_in) != NULL)
925 {
926 handle_line(buf);
927 }
928
929 fclose(f_in);
930 }
931
932
933
934
935 f_out = fopen(argv[1], "w");
936 if (!f_out)
937 {
938 printf("could not open '%s' for writing\n", argv[1]);
939 exit(1);
940 }
941
942
943 generate_level();
944
945 fclose(f_out);
946
947
948 return 0;
949 }
950
951