]> Shamusworld >> Repos - rmac/blob - token.c
Fixed problem with nested MACROs.
[rmac] / token.c
1 //
2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // TOKEN.C - Token Handling
4 // Copyright (C) 199x Landon Dyer, 2011-2012 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source Utilised with the Kind Permission of Landon Dyer
7 //
8
9 #include "token.h"
10 #include "error.h"
11 #include "macro.h"
12 #include "procln.h"
13 #include "symbol.h"
14
15 #define DECL_KW                         // Declare keyword arrays
16 #define DEF_KW                          // Declare keyword values 
17 #include "kwtab.h"                      // Incl generated keyword tables & defs
18
19 int lnsave;                                     // 1; strcpy() text of current line
20 int curlineno;                          // Current line number
21 int totlines;                           // Total # of lines
22 int mjump_align = 0;            // mjump alignment flag
23 char lntag;                                     // Line tag
24 char * curfname;                        // Current filename
25 char tolowertab[128];           // Uppercase ==> lowercase 
26 char hextab[128];                       // Table of hex values
27 char dotxtab[128];                      // Table for ".b", ".s", etc.
28 char irbuf[LNSIZ];                      // Text for .rept block line
29 char lnbuf[LNSIZ];                      // Text of current line
30 WORD filecount;                         // Unique file number counter
31 WORD cfileno;                           // Current file number
32 TOKEN * tok;                            // Ptr to current token
33 TOKEN * etok;                           // Ptr past last token in tokbuf[]
34 TOKEN tokeol[1] = {EOL};        // Bailout end-of-line token
35 char * string[TOKBUFSIZE*2];    // Token buffer string pointer storage
36
37 // File record, used to maintain a list of every include file ever visited
38 #define FILEREC struct _filerec
39 FILEREC
40 {
41    FILEREC * frec_next;
42    char * frec_name;
43 };
44
45 FILEREC * filerec;
46 FILEREC * last_fr;
47
48 INOBJ * cur_inobj;                                              // Ptr current input obj (IFILE/IMACRO)
49 static INOBJ * f_inobj;                                 // Ptr list of free INOBJs
50 static IFILE * f_ifile;                                 // Ptr list of free IFILEs
51 static IMACRO * f_imacro;                               // Ptr list of free IMACROs
52
53 static TOKEN tokbuf[TOKBUFSIZE];                // Token buffer (stack-like, all files)
54
55 char chrtab[] = {
56         ILLEG, ILLEG, ILLEG, ILLEG,                     // NUL SOH STX ETX 
57         ILLEG, ILLEG, ILLEG, ILLEG,                     // EOT ENQ ACK BEL 
58         ILLEG, WHITE, ILLEG, ILLEG,                     // BS HT LF VT 
59         WHITE, ILLEG, ILLEG, ILLEG,                     // FF CR SO SI 
60
61         ILLEG, ILLEG, ILLEG, ILLEG,                     // DLE DC1 DC2 DC3 
62         ILLEG, ILLEG, ILLEG, ILLEG,                     // DC4 NAK SYN ETB 
63         ILLEG, ILLEG, ILLEG, ILLEG,                     // CAN EM SUB ESC 
64         ILLEG, ILLEG, ILLEG, ILLEG,                     // FS GS RS US 
65
66         WHITE, MULTX, MULTX, SELF,                      // SP ! " #
67         MULTX+CTSYM, MULTX, SELF, MULTX,        // $ % & '
68         SELF, SELF, SELF, SELF,                         // ( ) * +
69         SELF, SELF, STSYM, SELF,                        // , - . /
70
71         DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM,         // 0 1 
72         DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM,         // 2 3 
73         DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM,         // 4 5 
74         DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM,         // 6 7 
75         DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM,         // 8 9 
76         MULTX, MULTX,                                                           // : ; 
77         MULTX, MULTX, MULTX, STSYM+CTSYM,                       // < = > ? 
78
79         MULTX, STSYM+CTSYM+HDIGIT,                                                                      // @ A
80         (char)((BYTE)DOT)+STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT,       // B C
81         STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT,                                         // D E
82         STSYM+CTSYM+HDIGIT, STSYM+CTSYM,                                                        // F G
83         STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM,                     // H I J K
84         (char)((BYTE)DOT)+STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM,   // L M N O
85
86         STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM,   // P Q R S
87         STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM,   // T U V W
88         STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, SELF,                            // X Y Z [
89         SELF, SELF, MULTX, STSYM+CTSYM,                                                         // \ ] ^ _
90
91         ILLEG, STSYM+CTSYM+HDIGIT,                                                                      // ` a
92         (char)((BYTE)DOT)+STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT,       // b c
93         STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT,                                         // d e
94         STSYM+CTSYM+HDIGIT, STSYM+CTSYM,                                                        // f g
95         STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM,                     // h i j k
96         (char)((BYTE)DOT)+STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM,   // l m n o
97
98         STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM,   // p q r s 
99         STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM,   // t u v w 
100         STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, SELF,                            // x y z { 
101         SELF, SELF, SELF, ILLEG                                                                         // | } ~ DEL 
102 };
103
104 // Names of registers
105 static char * regname[] = {
106         "d0", "d1",  "d2",  "d3", "d4", "d5", "d6", "d7",
107         "a0", "a1",  "a2",  "a3", "a4", "a5", "a6", "a7",
108         "pc", "ssp", "usp", "sr", "ccr"
109 };
110
111 static char * riscregname[] = {
112          "r0",  "r1",  "r2",  "r3",  "r4", "r5",   "r6",  "r7", 
113          "r8",  "r9", "r10", "r11", "r12", "r13", "r14", "r15",
114         "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
115         "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
116 };
117
118
119 //
120 // Make `fnum' the Current `curfname'
121 //
122 void setfnum(WORD fnum)
123 {
124         FILEREC * fr;
125
126         for(fr=filerec; fr!=NULL && fnum--; fr=fr->frec_next);
127
128         if (fr == NULL)
129                 curfname = "(*top*)";
130         else
131                 curfname = fr->frec_name;
132 }
133
134
135 //
136 // Allocate an IFILE or IMACRO
137 //
138 INOBJ * a_inobj(int typ)
139 {
140         INOBJ * inobj;
141         IFILE * ifile;
142         IMACRO * imacro;
143
144         // Allocate and initialize INOBJ first
145         if (f_inobj == NULL)
146                 inobj = malloc(sizeof(INOBJ));
147         else
148         {
149                 inobj = f_inobj;
150                 f_inobj = f_inobj->in_link;
151         }
152
153         switch (typ)
154         {
155         case SRC_IFILE:                                                 // Alloc and init an IFILE
156                 if (f_ifile == NULL)
157                         ifile = malloc(sizeof(IFILE));
158                 else
159                 {
160                         ifile = f_ifile;
161                         f_ifile = f_ifile->if_link;
162                 }
163
164                 inobj->inobj.ifile = ifile;
165                 break;
166         case SRC_IMACRO:                                                // Alloc and init an IMACRO 
167                 if (f_imacro == NULL)
168                         imacro = malloc(sizeof(IMACRO));
169                 else
170                 {
171                         imacro = f_imacro;
172                         f_imacro = f_imacro->im_link;
173                 }
174
175                 inobj->inobj.imacro = imacro;
176                 break;
177         case SRC_IREPT:                                                 // Alloc and init an IREPT
178                 inobj->inobj.irept = malloc(sizeof(IREPT));
179                 DEBUG printf("alloc IREPT\n");
180                 break;
181         }
182
183         // Install INOBJ on top of input stack
184         inobj->in_ifent = ifent;                                // Record .if context on entry
185         inobj->in_type = (WORD)typ;
186         inobj->in_otok = tok;
187         inobj->in_etok = etok;
188         inobj->in_link = cur_inobj;
189         cur_inobj = inobj;
190
191         return inobj;
192 }
193
194
195 //
196 // Perform macro substitution from 'orig' to 'dest'. Return OK or some error.
197 // A macro reference is in one of two forms:
198 // \name <non-name-character>
199 // \{name}
200 // A doubled backslash (\\) is compressed to a single backslash (\).
201 // Argument definitions have been pre-tokenized, so we have to turn them back
202 // into text. This means that numbers, in particular, become hex, regardless of
203 // their representation when the macro was invoked. This is a hack.
204 // A label may appear at the beginning of the line:
205 // :<name><whitespace>
206 // (the colon must be in the first column). These labels are stripped before
207 // macro expansion takes place.
208 //
209 int ExpandMacro(char * src, char * dest, int destsiz)
210 {
211         int i;
212         int questmark;                  // \? for testing argument existence
213         char mname[128];                // Assume max size of a formal arg name
214         char numbuf[20];                // Buffer for text of CONSTs
215         TOKEN * tk;
216         SYM * arg;
217         char ** symbolString;
218
219         DEBUG { printf("ExM: src=\"%s\"\n", src); }
220
221         IMACRO * imacro = cur_inobj->inobj.imacro;
222         int macnum = (int)(imacro->im_macro->sattr);
223
224 //      destsiz--;
225         char * dst = dest;                                              // Next dest slot
226         char * edst = dest + destsiz - 1;               // End + 1(?) of dest buffer
227
228         // Check for (and skip over) any "label" on the line
229         char * s = src;
230         char * d = NULL;
231
232         if (*s == ':')
233         {
234                 while (*s != EOS && !(chrtab[*s] & WHITE))
235                         s++;
236
237                 if (*s != EOS)
238                         s++;                                                    // Skip first whitespace
239         }
240
241         // Expand the rest of the line
242         while (*s != EOS)
243         {
244                 // Copy single character
245                 if (*s != '\\')
246                 {
247                         if (dst >= edst)
248                                 goto overflow;
249
250                         *dst++ = *s++;
251                 }
252                 // Do macro expansion
253                 else
254                 {
255                         questmark = 0;
256
257                         // Do special cases
258                         switch (*++s)
259                         {
260                         case '\\':                                              // \\, \ (collapse to single backslash)
261                                 if (dst >= edst)
262                                         goto overflow;
263
264                                 *dst++ = *s++;
265                                 continue;
266                         case '?':                                               // \? <macro>  set `questmark' flag 
267                                 ++s;
268                                 questmark = 1;
269                                 break;
270                         case '#':                                               // \#, number of arguments 
271                                 sprintf(numbuf, "%d", (int)imacro->im_nargs);
272                                 goto copystr;
273                         case '!':                                               // \! size suffix supplied on invocation
274                                 switch ((int)imacro->im_siz)
275                                 {
276                                 case SIZN: d = "";   break;
277                                 case SIZB: d = ".b"; break;
278                                 case SIZW: d = ".w"; break;
279                                 case SIZL: d = ".l"; break;
280                                 }
281
282                                 goto copy_d;
283                         case '~':                                               // ==> unique label string Mnnnn... 
284                                 sprintf(numbuf, "M%u", curuniq);
285 copystr:
286                                 d = numbuf;
287 copy_d:
288                                 s++;
289
290                                 while (*d != EOS)
291                                 {
292                                         if (dst >= edst)
293                                                 goto overflow;
294                                         else
295                                                 *dst++ = *d++;
296                                 }
297
298                                 continue;
299                         case EOS:
300                                 return error("missing argument name");
301                         }
302
303                         // \n ==> argument number 'n', 0..9
304                         if (chrtab[*s] & DIGIT)
305                         {
306                                 i = *s++ - '1';
307
308                                 if (i < 0)
309                                         i = 9;
310
311                                 goto arg_num;
312                         }
313
314                         // Get argument name: \name, \{name}
315                         d = mname;
316
317                         // \label
318                         if (*s != '{')
319                         {
320                                 do
321                                 {
322                                         *d++ = *s++;
323                                 }
324                                 while (chrtab[*s] & CTSYM);
325                         }
326                         // \\{label}
327                         else
328                         {
329                                 for(++s; *s != EOS && *s != '}';)
330                                         *d++ = *s++;
331
332                                 if (*s != '}')
333                                         return error("missing '}'");
334                                 else
335                                         s++;
336                         }
337
338                         *d = EOS;
339
340                         // Lookup the argument and copy its (string) value into the
341                         // destination string
342                         DEBUG printf("argument='%s'\n", mname);
343
344                         if ((arg = lookup(mname, MACARG, macnum)) == NULL)
345                                 return errors("undefined argument: '%s'", mname);
346                         else
347                         {
348                                 // Convert a string of tokens (terminated with EOL) back into
349                                 // text. If an argument is out of range (not specified in the
350                                 // macro invocation) then it is ignored.
351                                 i = (int)arg->svalue;
352 arg_num:
353                                 DEBUG printf("~argnumber=%d (argBase=%u)\n", i, imacro->argBase);
354                                 tk = NULL;
355
356                                 if (i < imacro->im_nargs)
357                                 {
358 #if 0
359 //                                      tk = argp[i];
360 //                                      tk = argPtrs[i];
361                                         tk = argPtrs[imacro->argBase + i];
362 #else
363                                         tk = imacro->argument[i].token;
364                                         symbolString = imacro->argument[i].string;
365 //DEBUG
366 //{
367 //      printf("ExM: Preparing to parse argument #%u...\n", i);
368 //      dumptok(tk);
369 //}
370 #endif
371                                 }
372
373                                 // \?arg yields:
374                                 //    0  if the argument is empty or non-existant,
375                                 //    1  if the argument is not empty
376                                 if (questmark)
377                                 {
378                                         if (tk == NULL || *tk == EOL)
379                                                 questmark = 0;
380
381                                         if (dst >= edst)
382                                                 goto overflow;
383
384                                         *dst++ = (char)(questmark + '0');
385                                         continue;
386                                 }
387
388                                 if (tk != NULL)                         // arg # is in range, so expand it
389                                 {
390                                         while (*tk != EOL)
391                                         {
392                                                 // Reverse-translation from a token number to a string.
393                                                 // This is a hack. It might be better table-driven.
394                                                 d = NULL;
395
396                                                 if ((*tk >= KW_D0) && !rdsp && !rgpu)
397                                                 {
398                                                         d = regname[(int)*tk++ - KW_D0];
399                                                         goto strcopy;
400                                                 }
401                                                 else if ((*tk >= KW_R0) && (*tk <= KW_R31))
402                                                 {
403                                                         d = riscregname[(int)*tk++ - KW_R0];
404                                                         goto strcopy;
405                                                 }
406                                                 else
407                                                 {
408                                                         switch ((int)*tk++)
409                                                         {
410                                                         case SYMBOL:
411 #if 0
412 //                                                              d = (char *)*tk++;
413                                                                 d = string[*tk++];
414 #else
415                                                                 // This fix should be done for strings too
416                                                                 d = symbolString[*tk++];
417 DEBUG printf("ExM: SYMBOL=\"%s\"", d);
418 #endif
419                                                                 break;
420                                                         case STRING:
421 #if 0
422 //                                                              d = (char *)*tk++;
423                                                                 d = string[*tk++];
424 #else
425                                                                 d = symbolString[*tk++];
426 #endif
427                                                                 if (dst >= edst)
428                                                                         goto overflow;
429
430                                                                 *dst++ = '"';
431
432                                                                 while (*d != EOS)
433                                                                 {
434                                                                         if (dst >= edst)
435                                                                                 goto overflow;
436                                                                         else
437                                                                                 *dst++ = *d++;
438                                                                 }
439
440                                                                 if (dst >= edst)
441                                                                         goto overflow;
442
443                                                                 *dst++ = '"';
444                                                                 continue;
445                                                                 break;
446 // Shamus: Changing the format specifier from %lx to %ux caused
447 //         the assembler to choke on legitimate code... Need to investigate
448 //         this further before changing anything else here!
449                                                         case CONST:
450                                                                 sprintf(numbuf, "$%lx", (LONG)*tk++);
451                                                                 d = numbuf;
452                                                                 break;
453                                                         case DEQUALS:
454                                                                 d = "==";
455                                                                 break;
456                                                         case SET:
457                                                                 d = "set";
458                                                                 break;
459                                                         case COLON:
460                                                                 d = ":";
461                                                                 break;
462                                                         case DCOLON:
463                                                                 d = "::";
464                                                                 break;
465                                                         case GE:
466                                                                 d = ">=";
467                                                                 break;
468                                                         case LE:
469                                                                 d = "<=";
470                                                                 break;
471                                                         case NE:
472                                                                 d = "<>";
473                                                                 break;
474                                                         case SHR:
475                                                                 d = ">>";
476                                                                 break;
477                                                         case SHL:
478                                                                 d = "<<";
479                                                                 break;
480                                                         case DOTB:
481                                                                 d = ".b";
482                                                                 break;
483                                                         case DOTW:
484                                                                 d = ".w";
485                                                                 break;
486                                                         case DOTL:
487                                                                 d = ".l";
488                                                                 break;
489                                                         case CR_DATE:
490                                                                 d = "^^date";
491                                                                 break;
492                                                         case CR_TIME:
493                                                                 d = "^^time";
494                                                                 break;
495                                                         case CR_DEFINED:
496                                                                 d = "^^defined ";
497                                                                 break;
498                                                         case CR_REFERENCED:
499                                                                 d = "^^referenced ";
500                                                                 break;
501                                                         case CR_STREQ:
502                                                                 d = "^^streq ";
503                                                                 break;
504                                                         case CR_MACDEF:
505                                                                 d = "^^macdef ";
506                                                                 break;
507                                                         default:
508                                                                 if (dst >= edst)
509                                                                         goto overflow;
510
511                                                                 *dst++ = (char)*(tk - 1);
512                                                                 break;
513                                                         }
514                                                 }
515
516                                                 // If 'd' != NULL, copy string to destination
517                                                 if (d != NULL)
518                                                 {
519 strcopy:
520                                                         DEBUG printf("d='%s'\n", d);
521
522                                                         while (*d != EOS)
523                                                         {
524                                                                 if (dst >= edst)
525                                                                         goto overflow;
526                                                                 else
527                                                                         *dst++ = *d++;
528                                                         }
529                                                 }
530                                         }
531                                 }
532                         }
533                 }
534         }
535
536         *dst = EOS;
537         DEBUG { printf("ExM: dst=\"%s\"\n", dest); }
538         return OK;
539
540 overflow:
541         *dst = EOS;
542         DEBUG printf("*** OVERFLOW LINE ***\n%s\n", dest);
543         return fatal("line too long as a result of macro expansion");
544 }
545
546
547 //
548 // Get Next Line of Text from a Macro
549 //
550 char * getmln(void)
551 {
552         unsigned source_addr;
553
554         IMACRO * imacro = cur_inobj->inobj.imacro;
555 //      LONG * strp = imacro->im_nextln;
556         struct LineList * strp = imacro->im_nextln;
557
558         if (strp == NULL)                                               // End-of-macro
559                 return NULL;
560
561 //      imacro->im_nextln = (LONG *)*strp;
562         imacro->im_nextln = strp->next;
563 //      ExpandMacro((char *)(strp + 1), imacro->im_lnbuf, LNSIZ);
564         ExpandMacro(strp->line, imacro->im_lnbuf, LNSIZ);
565
566         if (!strcmp(imacro->im_macro->sname, "mjump") && !mjump_align)
567         {
568                 // if we need to adjust the alignment of the jump source address to
569                 // meet the rules of gpu main execution we need to skip the first nop
570                 // of the macro. This is simpler than trying to insert nop's mid macro.
571                 source_addr = (orgactive ? orgaddr : sloc);
572                 source_addr += 8;
573
574                 if (source_addr % 4)
575                 {
576                         strp = imacro->im_nextln;
577
578                         if (strp == NULL)
579                                 return NULL;
580
581 //                      imacro->im_nextln = (LONG *)*strp;
582 //                      ExpandMacro((char *)(strp + 1), imacro->im_lnbuf, LNSIZ);
583                         imacro->im_nextln = strp->next;
584                         ExpandMacro(strp->line, imacro->im_lnbuf, LNSIZ);
585                 }
586
587                 mjump_align = 1;
588         }
589
590         return imacro->im_lnbuf;
591 }
592
593
594 //
595 // Get Next Line of Text from a Repeat Block
596 //
597 char * getrln(void)
598 {
599
600         IREPT * irept = cur_inobj->inobj.irept;
601         LONG * strp = irept->ir_nextln;                 // initial null
602
603         // Do repeat at end of .rept block's string list
604         if (strp == NULL)
605         {
606                 DEBUG printf("back-to-top-of-repeat-block count=%d\n", (int)irept->ir_count);
607                 irept->ir_nextln = irept->ir_firstln;   // copy first line
608
609                 if (irept->ir_count-- == 0)
610                 {
611                         DEBUG printf("end-repeat-block\n");
612                         return NULL;
613                 }
614
615                 strp = irept->ir_nextln;                        //strp
616         }
617
618         strcpy(irbuf, (char *)(irept->ir_nextln + 1));
619         DEBUG printf("repeat line='%s'\n", irbuf);
620         irept->ir_nextln = (LONG *)*strp;
621
622         return irbuf;
623 }
624
625
626 //
627 // Include a Source File used at the Root, and for ".include" Files
628 //
629 int include(int handle, char * fname)
630 {
631         IFILE * ifile;
632         INOBJ * inobj;
633         FILEREC * fr;
634
635         // Verbose mode
636         if (verb_flag)
637                 printf("[Including: %s]\n", fname);
638
639         // Alloc and initialize include-descriptors
640         inobj = a_inobj(SRC_IFILE);
641         ifile = inobj->inobj.ifile;
642
643         ifile->ifhandle = handle;                               // Setup file handle
644         ifile->ifind = ifile->ifcnt = 0;                // Setup buffer indices
645         ifile->ifoldlineno = curlineno;                 // Save old line number
646         ifile->ifoldfname = curfname;                   // Save old filename
647         ifile->ifno = cfileno;                                  // Save old file number
648         cfileno = filecount++;                                  // Compute new file number
649         curfname = strdup(fname);                               // Set current filename (alloc storage)
650         curlineno = 0;                                                  // Start on line zero
651
652         // Add another file to the file-record
653 //      fr = (FILEREC *)amem((LONG)sizeof(FILEREC));
654         fr = (FILEREC *)malloc(sizeof(FILEREC));
655         fr->frec_next = NULL;
656         fr->frec_name = curfname;
657
658         if (last_fr == NULL)
659                 filerec = fr;                                           // Add first filerec 
660         else
661                 last_fr->frec_next = fr;                        // Append to list of filerecs 
662
663         last_fr = fr;
664
665         return OK;
666 }
667
668
669 //
670 // Initialize Tokenizer
671 //
672 void init_token(void)
673 {
674         int i;                                                                  // Iterator
675         char * htab = "0123456789abcdefABCDEF"; // Hex character table
676
677         lnsave = 0;                                                             // Don't save lines
678         curfname = "";                                                  // No file, empty filename
679         filecount = (WORD)-1;
680         cfileno = (WORD)-1;                                             // cfileno gets bumped to 0
681         curlineno = 0;
682         totlines = 0;
683         etok = tokbuf;
684         f_inobj = NULL;
685         f_ifile = NULL;
686         f_imacro = NULL;
687         cur_inobj = NULL;
688         filerec = NULL;
689         last_fr = NULL;
690         lntag = SPACE;
691
692         // Initialize hex, "dot" and tolower tables
693         for(i=0; i<128; i++)
694         {
695                 hextab[i] = -1;
696                 dotxtab[i] = 0;
697                 tolowertab[i] = (char)i;
698         }
699
700         for(i=0; htab[i]!=EOS; i++)
701                 hextab[htab[i]] = (char)((i < 16) ? i : i - 6);
702
703         for(i='A'; i<='Z'; i++)
704                 tolowertab[i] |= 0x20;
705
706         // These characters are legal immediately after a period
707         dotxtab['b'] = DOTB;                                    // .b .B .s .S 
708         dotxtab['B'] = DOTB;
709         dotxtab['s'] = DOTB;
710         dotxtab['S'] = DOTB;
711         dotxtab['w'] = DOTW;                                    // .w .W 
712         dotxtab['W'] = DOTW;
713         dotxtab['l'] = DOTL;                                    // .l .L 
714         dotxtab['L'] = DOTL;
715         dotxtab['I'] = DOTI;                                    // .l .L 
716         dotxtab['I'] = DOTI;
717 }
718
719
720 //
721 // Pop the Current Input Level
722 //
723 int fpop(void)
724 {
725         IFILE * ifile;
726         IMACRO * imacro;
727         LONG * p, * p1;
728         INOBJ * inobj = cur_inobj;
729
730         if (inobj != NULL)
731         {
732                 // Pop IFENT levels until we reach the conditional assembly context we
733                 // were at when the input object was entered.
734                 while (ifent != inobj->in_ifent)
735                         d_endif();
736
737                 tok = inobj->in_otok;                           // Restore tok and otok
738                 etok = inobj->in_etok;
739
740                 switch (inobj->in_type)
741                 {
742                 case SRC_IFILE:                                         // Pop and release an IFILE
743                         if (verb_flag)
744                                 printf("[Leaving: %s]\n", curfname);
745
746                         ifile = inobj->inobj.ifile;
747                         ifile->if_link = f_ifile;
748                         f_ifile = ifile;
749                         close(ifile->ifhandle);                 // Close source file
750                         curfname = ifile->ifoldfname;   // Set current filename
751                         curlineno = ifile->ifoldlineno; // Set current line# 
752                         DEBUG printf("cfileno=%d ifile->ifno=%d\n", (int)cfileno, (int)ifile->ifno);
753                         cfileno = ifile->ifno;                  // Restore current file number
754                         break;
755                 case SRC_IMACRO:                                        // Pop and release an IMACRO
756                         imacro = inobj->inobj.imacro;
757                         imacro->im_link = f_imacro;
758                         f_imacro = imacro;
759                         break;
760                 case SRC_IREPT:                                         // Pop and release an IREPT
761                         DEBUG printf("dealloc IREPT\n");
762                         p = inobj->inobj.irept->ir_firstln;
763
764                         while (p != NULL)
765                         {
766                                 p1 = (LONG *)*p;
767                                 p = p1;
768                         }
769
770                         break;
771                 }
772
773                 cur_inobj = inobj->in_link;
774                 inobj->in_link = f_inobj;
775                 f_inobj = inobj;
776         }
777
778         return 0;
779 }
780
781
782 //
783 // Get line from file into buf, return NULL on EOF or ptr to the start of a
784 // null-term line
785 //
786 char * getln(void)
787 {
788         int i, j;
789         char * p, * d;
790         int readamt = -1;                                               // 0 if last read() yeilded 0 bytes
791         IFILE * fl = cur_inobj->inobj.ifile;
792
793         for(;;)
794         {
795                 // Scan for next end-of-line; handle stupid text formats by treating
796                 // \r\n the same as \n. (lone '\r' at end of buffer means we have to
797                 // check for '\n').
798                 i = 0;
799                 j = fl->ifcnt;
800                 d = &fl->ifbuf[fl->ifind];
801
802                 for(p=d; i<j; i++, p++)
803                 {
804                         if (*p == '\r' || *p == '\n')
805                         {
806                                 i++;
807
808                                 if (*p == '\r')
809                                 {
810                                         if (i >= j)
811                                         {
812                                                 break;                          // Look for '\n' to eat 
813                                         }
814                                         else if (p[1] == '\n')
815                                         {
816                                                 i++;
817                                         }
818                                 }
819
820                                 *p = '\0';
821
822                                 fl->ifind += i;
823                                 fl->ifcnt -= i;
824                                 return d;
825                         }
826                 }
827
828                 // Handle hanging lines by ignoring them (Input file is exhausted, no
829                 // \r or \n on last line)
830                 if (!readamt && fl->ifcnt)
831                 {
832                         fl->ifcnt = 0;
833                         *p = '\0';
834                         return NULL;
835                 }
836
837                 // Truncate and return absurdly long lines.
838                 if (fl->ifcnt >= QUANTUM)
839                 {
840                         fl->ifbuf[fl->ifind + fl->ifcnt - 1] = '\0';
841                         fl->ifcnt = 0;
842                         return &fl->ifbuf[fl->ifind];
843                 }
844
845                 // Relocate what's left of a line to the beginning of the buffer, and
846                 // read some more of the file in; return NULL if the buffer's empty and
847                 // on EOF.
848                 if (fl->ifind != 0)
849                 {
850                         p = &fl->ifbuf[fl->ifind];
851                         d = &fl->ifbuf[fl->ifcnt & 1];
852
853                         for(i=0; i<fl->ifcnt; i++)
854                                 *d++ = *p++;
855
856                         fl->ifind = fl->ifcnt & 1;
857                 }
858
859                 if ((readamt = read(fl->ifhandle, &fl->ifbuf[fl->ifind + fl->ifcnt], QUANTUM)) < 0)
860                         return NULL;
861
862                 if ((fl->ifcnt += readamt) == 0)
863                         return NULL;
864         }
865 }
866
867
868 //
869 // Tokenize a Line
870 //
871 int tokln(void)
872 {
873         char * ln = NULL;                               // Ptr to current position in line
874         char * p;                                               // Random character ptr
875         TOKEN * tk;                                             // Token-deposit ptr
876         int state = 0;                                  // State for keyword detector
877         int j = 0;                                              // Var for keyword detector
878         char c;                                                 // Random char
879         VALUE v;                                                // Random value
880         char * nullspot = NULL;                 // Spot to clobber for SYMBOL terminatn
881         int stuffnull;                                  // 1:terminate SYMBOL '\0' at *nullspot
882         char c1;
883         int stringNum = 0;                              // Pointer to string locations in tokenized line
884
885         retry:
886
887         if (cur_inobj == NULL)                                  // Return EOF if input stack is empty
888                 return TKEOF;
889
890         // Get another line of input from the current input source: a file,
891         // a macro, or a repeat-block
892         switch (cur_inobj->in_type)
893         {
894         // Include-file:
895         // o  handle EOF;
896         // o  bump source line number;
897         // o  tag the listing-line with a space;
898         // o  kludge lines generated by Alcyon C.
899         case SRC_IFILE:
900                 if ((ln = getln()) == NULL)
901                 {
902                         fpop();                                                 // Pop input level
903                         goto retry;                                             // Try for more lines 
904                 }
905
906                 curlineno++;                                            // Bump line number
907                 lntag = SPACE;
908
909                 if (as68_flag)
910                 {
911                         // AS68 compatibility, throw away all lines starting with
912                         // back-quotes, tildes, or '*'
913                         // On other lines, turn the first '*' into a semi-colon.
914                         if (*ln == '`' || *ln == '~' || *ln == '*')
915                                 *ln = ';';
916                         else
917                         {
918                                 for(p=ln; *p!=EOS; p++)
919                                 {
920                                         if (*p == '*')
921                                         {
922                                                 *p = ';';
923                                                 break;
924                                         }
925                                 }
926                         }
927                 }
928
929                 break;
930         // Macro-block:
931         // o  Handle end-of-macro;
932         // o  tag the listing-line with an at (@) sign.
933         case SRC_IMACRO:
934                 if ((ln = getmln()) == NULL)
935                 {
936                         ExitMacro();                                    // Exit macro (pop args, do fpop(), etc)
937                         goto retry;                                             // Try for more lines...
938                 }
939
940                 lntag = '@';
941                 break;
942         // Repeat-block:
943         // o  Handle end-of-repeat-block;
944         // o  tag the listing-line with a pound (#) sign.
945         case SRC_IREPT:
946                 if ((ln = getrln()) == NULL)
947                 {
948                         fpop();
949                         goto retry;
950                 }
951
952                 lntag = '#';
953                 break;
954         }
955
956         // Save text of the line.  We only do this during listings and within
957         // macro-type blocks, since it is expensive to unconditionally copy every
958         // line.
959         if (lnsave)
960                 strcpy(lnbuf, ln);
961
962         // General house-keeping
963         tok = tokeol;                                                   // Set "tok" to EOL in case of error
964         tk = etok;                                                              // Reset token ptr
965         stuffnull = 0;                                                  // Don't stuff nulls
966         totlines++;                                                             // Bump total #lines assembled
967
968         // See if the entire line is a comment. This is a win if the programmer
969         // puts in lots of comments
970         if (*ln == '*' || *ln == ';' || ((*ln == '/') && (*(ln + 1) == '/')))
971                 goto goteol;
972
973         // Main tokenization loop;
974         // o  skip whitespace;
975         // o  handle end-of-line;
976         // o  handle symbols;
977         // o  handle single-character tokens (operators, etc.);
978         // o  handle multiple-character tokens (constants, strings, etc.).
979         for(; *ln!=EOS;)
980         {
981                 // Skip whitespace, handle EOL
982                 while ((int)chrtab[*ln] & WHITE)
983                         ln++;
984
985                 // Handle EOL, comment with ';'
986                 if (*ln == EOS || *ln == ';'|| ((*ln == '/') && (*(ln + 1) == '/'))) 
987                         break;
988
989                 // Handle start of symbol. Symbols are null-terminated in place. The
990                 // termination is always one symbol behind, since there may be no place
991                 // for a null in the case that an operator immediately follows the name.
992                 c = chrtab[*ln];
993
994                 if (c & STSYM)
995                 {
996                         if (stuffnull)                                  // Terminate old symbol from previous pass
997                                 *nullspot = EOS;
998
999                         v = 0;                                                  // Assume no DOT attrib follows symbol
1000                         stuffnull = 1;
1001                         p = nullspot = ln++;                    // Nullspot -> start of this symbol
1002
1003                         // Find end of symbol (and compute its length)
1004                         for(j=1; (int)chrtab[*ln]&CTSYM; j++)
1005                                 ln++;
1006
1007                         // Handle "DOT" special forms (like ".b") that follow a normal
1008                         // symbol or keyword:
1009                         if (*ln == '.')
1010                         {
1011                                 *ln++ = EOS;                            // Terminate symbol
1012                                 stuffnull = 0;                          // And never try it again 
1013
1014                                 // Character following the `.' must have a DOT attribute, and
1015                                 // the chararacter after THAT one must not have a start-symbol
1016                                 // attribute (to prevent symbols that look like, for example,
1017                                 // "zingo.barf", which might be a good idea anyway....)
1018                                 if ((((int)chrtab[*ln] & DOT) == 0) || ((int)dotxtab[*ln] <= 0))
1019                                         return error("[bwsl] must follow `.' in symbol");
1020
1021                                 v = (VALUE)dotxtab[*ln++];
1022
1023                                 if ((int)chrtab[*ln] & CTSYM)
1024                                         return error("misuse of `.', not allowed in symbols");
1025                         }
1026
1027                         // If the symbol is small, check to see if it's really the name of
1028                         // a register.
1029                         if (j <= KWSIZE)
1030                         {
1031                                 for(state=0; state>=0;)
1032                                 {
1033                                         j = (int)tolowertab[*p++];
1034                                         j += kwbase[state];
1035
1036                                         if (kwcheck[j] != state)
1037                                         {
1038                                                 j = -1;
1039                                                 break;
1040                                         }
1041
1042                                         if (*p == EOS || p == ln)
1043                                         {
1044                                                 j = kwaccept[j];
1045                                                 break;
1046                                         }
1047
1048                                         state = kwtab[j];
1049                                 }
1050                         }
1051                         else
1052                         {
1053                                 j = -1;
1054                         }
1055
1056                         //make j = -1 if time, date etc with no preceeding ^^
1057                         //defined, referenced, streq, macdef, date and time
1058                         switch ((TOKEN)j)
1059                         {
1060                         case 112:   // defined
1061                         case 113:   // referenced
1062                         case 118:   // streq
1063                         case 119:   // macdef
1064                         case 120:   // time
1065                         case 121:   // date
1066                                 j = -1;
1067                                 break;
1068                         }
1069
1070                         if (j < 0 || state < 0)
1071                         {
1072                                 *tk++ = SYMBOL;
1073 //#warning
1074 //problem here: nullspot is a char * but TOKEN is a uint32_t. On a 64-bit system,
1075 //this will cause all kinds of mischief.
1076 #if 0
1077                                 *tk++ = (TOKEN)nullspot;
1078 #else
1079                                 string[stringNum] = nullspot;
1080                                 *tk++ = stringNum;
1081                                 stringNum++;
1082 #endif
1083                         }
1084                         else
1085                         {
1086                                 *tk++ = (TOKEN)j;
1087                                 stuffnull = 0;
1088                         }
1089
1090                         if (v)                                                  // Record attribute token (if any)
1091                                 *tk++ = (TOKEN)v;
1092
1093                         if (stuffnull)                                  // Arrange for string termination on next pass
1094                                 nullspot = ln;
1095
1096                         continue;
1097                 }
1098
1099                 // Handle identity tokens
1100                 if (c & SELF)
1101                 {
1102                         *tk++ = *ln++;
1103                         continue;
1104                 }
1105
1106                 // Handle multiple-character tokens
1107                 if (c & MULTX)
1108                 {
1109                         switch (*ln++)
1110                         {
1111                         case '!':                                       // ! or != 
1112                                 if (*ln == '=')
1113                                 {
1114                                         *tk++ = NE;
1115                                         ++ln;
1116                                 }
1117                                 else
1118                                         *tk++ = '!';
1119
1120                                 continue;
1121                         case '\'':                                      // 'string' 
1122                         case '\"':                                      // "string" 
1123                                 c1 = ln[-1];
1124                                 *tk++ = STRING;
1125 //#warning
1126 // More char * stuffing (8 bytes) into the space of 4 (TOKEN).
1127 // Need to figure out how to fix this crap.
1128 #if 0
1129                                 *tk++ = (TOKEN)ln;
1130 #else
1131                                 string[stringNum] = ln;
1132                                 *tk++ = stringNum;
1133                                 stringNum++;
1134 #endif
1135
1136                                 for(p=ln; *ln!=EOS && *ln!=c1;)
1137                                 {
1138                                         c = *ln++;
1139
1140                                         if (c == '\\')
1141                                         {
1142                                                 switch (*ln++)
1143                                                 {
1144                                                 case EOS:
1145                                                         return(error("unterminated string"));
1146                                                 case 'e':
1147                                                         c = '\033';
1148                                                         break;
1149                                                 case 'n':
1150                                                         c = '\n';
1151                                                         break;
1152                                                 case 'b':
1153                                                         c = '\b';
1154                                                         break;
1155                                                 case 't':
1156                                                         c = '\t';
1157                                                         break;
1158                                                 case 'r':
1159                                                         c = '\r';
1160                                                         break;
1161                                                 case 'f':
1162                                                         c = '\f';
1163                                                         break;
1164                                                 case '\"':
1165                                                         c = '\"';
1166                                                         break;
1167                                                 case '\'':
1168                                                         c = '\'';
1169                                                         break;
1170                                                 case '\\':
1171                                                         c = '\\';
1172                                                         break;
1173                                                 default:
1174                                                         warn("bad backslash code in string");
1175                                                         --ln;
1176                                                         break;
1177                                                 }
1178                                         }
1179
1180                                         *p++ = c;
1181                                 }
1182
1183                                 if (*ln++ != c1)
1184                                         return error("unterminated string");
1185
1186                                 *p++ = EOS;
1187                                 continue;
1188                         case '$':                                       // $, hex constant
1189                                 if ((int)chrtab[*ln] & HDIGIT)
1190                                 {
1191                                         v = 0;
1192
1193                                         while ((int)hextab[*ln] >= 0)
1194                                                 v = (v << 4) + (int)hextab[*ln++];
1195
1196                                         if (*ln == '.')
1197                                         {
1198                                                 if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1199                                                 {
1200                                                         v &= 0x000000FF;
1201                                                         ln += 2;
1202                                                 }
1203
1204                                                 if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1205                                                 {
1206                                                         v &= 0x0000FFFF;
1207                                                         ln += 2;
1208                                                 }
1209
1210                                                 if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1211                                                 {
1212                                                         ln += 2;
1213                                                 }
1214                                         }
1215
1216                                         *tk++ = CONST;
1217                                         *tk++ = v;
1218                                 }
1219                                 else
1220                                         *tk++ = '$';
1221
1222                                 continue;
1223                         case '<':                                       // < or << or <> or <= 
1224                                 switch (*ln)
1225                                 {
1226                                 case '<':
1227                                         *tk++ = SHL;
1228                                         ++ln;
1229                                         continue;
1230                                 case '>':
1231                                         *tk++ = NE;
1232                                         ++ln;
1233                                         continue;
1234                                 case '=':
1235                                         *tk++ = LE;
1236                                         ++ln;
1237                                         continue;
1238                                 default:
1239                                         *tk++ = '<';
1240                                         continue;
1241                                 }
1242                         case ':':                                       // : or ::
1243                                 if (*ln == ':')
1244                                 {
1245                                         *tk++ = DCOLON;
1246                                         ++ln;
1247                                 }
1248                                 else
1249                                         *tk++ = ':';
1250
1251                                 continue;
1252                         case '=':                                       // = or == 
1253                                 if (*ln == '=')
1254                                 {
1255                                         *tk++ = DEQUALS;
1256                                         ++ln;
1257                                 }
1258                                 else
1259                                         *tk++ = '=';
1260
1261                                 continue;
1262                         case '>':                                       // > or >> or >= 
1263                                 switch (*ln)
1264                                 {
1265                                 case '>':
1266                                         *tk++ = SHR;
1267                                         ++ln;
1268                                         continue;
1269                                 case '=':
1270                                         *tk++ = GE;
1271                                         ++ln;
1272                                         continue;
1273                                 default:
1274                                         *tk++ = '>';
1275                                         continue;
1276                                 }
1277                         case '%':                                       // % or binary constant 
1278                                 if (*ln < '0' || *ln > '1')
1279                                 {
1280                                         *tk++ = '%';
1281                                         continue;
1282                                 }
1283
1284                                 v = 0;
1285
1286                                 while (*ln >= '0' && *ln <= '1')
1287                                         v = (v << 1) + *ln++ - '0';
1288
1289                                 if (*ln == '.')
1290                                 {
1291                                         if ((*(ln + 1) == 'b') || (*(ln + 1) == 'B'))
1292                                         {
1293                                                 v &= 0x000000FF;
1294                                                 ln += 2;
1295                                         }
1296
1297                                         if ((*(ln + 1) == 'w') || (*(ln + 1) == 'W'))
1298                                         {
1299                                                 v &= 0x0000FFFF;
1300                                                 ln += 2;
1301                                         }
1302
1303                                         if ((*(ln + 1) == 'l') || (*(ln + 1) == 'L'))
1304                                         {
1305                                                 ln += 2;
1306                                         }
1307                                 }
1308
1309                                 *tk++ = CONST;
1310                                 *tk++ = v;
1311                                 continue;
1312                         case '@':                                       // @ or octal constant 
1313                                 if (*ln < '0' || *ln > '7')
1314                                 {
1315                                         *tk++ = '@';
1316                                         continue;
1317                                 }
1318
1319                                 v = 0;
1320
1321                                 while (*ln >= '0' && *ln <= '7')
1322                                         v = (v << 3) + *ln++ - '0';
1323
1324                                 if (*ln == '.')
1325                                 {
1326                                         if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1327                                         {
1328                                                 v &= 0x000000FF;
1329                                                 ln += 2;
1330                                         }
1331
1332                                         if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1333                                         {
1334                                                 v &= 0x0000FFFF;
1335                                                 ln += 2;
1336                                         }
1337
1338                                         if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1339                                         {
1340                                                 ln += 2;
1341                                         }
1342                                 }
1343
1344                                 *tk++ = CONST;
1345                                 *tk++ = v;
1346                                 continue;
1347                         case '^':                                       // ^ or ^^ <operator-name>
1348                                 if (*ln != '^')
1349                                 {
1350                                         *tk++ = '^';
1351                                         continue;
1352                                 }
1353
1354                                 if (((int)chrtab[*++ln] & STSYM) == 0)
1355                                 {
1356                                         error("invalid symbol following ^^");
1357                                         continue;
1358                                 }
1359
1360                                 p = ln++;
1361
1362                                 while ((int)chrtab[*ln] & CTSYM)
1363                                         ++ln;
1364
1365                                 for(state=0; state>=0;)
1366                                 {
1367                                         // Get char, convert to lowercase 
1368                                         j = *p++;
1369
1370                                         if (j >= 'A' && j <= 'Z')
1371                                                 j += 0x20;
1372
1373                                         j += kwbase[state];
1374
1375                                         if (kwcheck[j] != state)
1376                                         {
1377                                                 j = -1;
1378                                                 break;
1379                                         }
1380
1381                                         if (*p == EOS || p == ln)
1382                                         {
1383                                                 j = kwaccept[j];
1384                                                 break;
1385                                         }
1386
1387                                         state = kwtab[j];
1388                                 }
1389
1390                                 if (j < 0 || state < 0)
1391                                 {
1392                                         error("unknown symbol following ^^");
1393                                         continue;
1394                                 }
1395
1396                                 *tk++ = (TOKEN)j;
1397                                 continue;
1398                         default:
1399                                 interror(2);                                 // Bad MULTX entry in chrtab
1400                                 continue;
1401                         }
1402                 }
1403
1404                 // Handle decimal constant
1405                 if (c & DIGIT)
1406                 {
1407                         v = 0;
1408
1409                         while ((int)chrtab[*ln] & DIGIT)
1410                                 v = (v * 10) + *ln++ - '0';
1411
1412                         // See if there's a .[bwl] after the constant, & deal with it
1413                         if (*ln == '.')
1414                         {
1415                                 if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1416                                 {
1417                                         v &= 0x000000FF;
1418                                         ln += 2;
1419                                 }
1420
1421                                 if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1422                                 {
1423                                         v &= 0x0000FFFF;
1424                                         ln += 2;
1425                                 }
1426
1427                                 if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1428                                 {
1429                                         ln += 2;
1430                                 }
1431                         }
1432
1433                         *tk++ = CONST;
1434                         *tk++ = v;
1435                         continue;
1436                 }
1437
1438                 // Handle illegal character
1439                 return error("illegal character");
1440         }
1441
1442         // Terminate line of tokens and return "success."
1443
1444 goteol:
1445         tok = etok;                                                             // Set tok to beginning of line
1446
1447         if (stuffnull)                                                  // Terminate last SYMBOL
1448                 *nullspot = EOS;
1449
1450         *tk++ = EOL;
1451
1452         return OK;
1453 }
1454
1455
1456 //
1457 // .GOTO <label>        goto directive
1458 // 
1459 // The label is searched for starting from the first line of the current,
1460 // enclosing macro definition. If no enclosing macro exists, an error is
1461 // generated.
1462 // 
1463 // A label is of the form:
1464 // 
1465 // :<name><whitespace>
1466 // 
1467 // The colon must appear in column 1.  The label is stripped prior to macro
1468 // expansion, and is NOT subject to macro expansion.  The whitespace may also
1469 // be EOL.
1470 //
1471 //int d_goto(WORD siz) {
1472 //int d_goto(void)
1473 int d_goto(WORD unused)
1474 {
1475 //      char * sym;                                               // Label to search for 
1476 //      LONG * defln;                                             // Macro definition strings 
1477         char * s1;                                                // Temps for string comparison 
1478         char * s2;
1479 //      IMACRO * imacro;                                          // Macro invocation block
1480
1481         // Setup for the search
1482         if (*tok != SYMBOL)
1483                 return error("missing label");
1484
1485 //      sym = (char *)tok[1];
1486         char * sym = string[tok[1]];
1487         tok += 2;
1488
1489         if (cur_inobj->in_type != SRC_IMACRO)
1490                 return error("goto not in macro");
1491
1492         IMACRO * imacro = cur_inobj->inobj.imacro;
1493 //      defln = (LONG *)imacro->im_macro->svalue;
1494         struct LineList * defln = imacro->im_macro->lineList;
1495
1496         // Find the label, starting with the first line.
1497 //      for(; defln!=NULL; defln=(LONG *)*defln)
1498         for(; defln!=NULL; defln=defln->next)
1499         {
1500 //              if (*(char *)(defln + 1) == ':')
1501                 if (defln->line[0] == ':')
1502                 {
1503                         // Compare names (sleazo string compare)
1504                         // This string compare is not right. Doesn't check for lengths.
1505 #warning "!!! Bad string comparison !!!"
1506                         s1 = sym;
1507 //                      s2 = (char *)(defln + 1) + 1;
1508                         s2 = defln->line;
1509
1510                         while (*s1 == *s2)
1511                         {
1512                                 if (*s1 == EOS)
1513                                         break;
1514                                 else
1515                                 {
1516                                         s1++;
1517                                         s2++;
1518                                 }
1519                         }
1520
1521                         // Found the label, set new macro next-line and return.
1522                         if ((*s2 == EOS) || ((int)chrtab[*s2] & WHITE))
1523                         {
1524                                 imacro->im_nextln = defln;
1525                                 return 0;
1526                         }
1527                 }
1528         }
1529
1530         return error("goto label not found");
1531 }
1532
1533 void DumpTokenBuffer(void)
1534 {
1535         TOKEN * t;
1536         printf("Tokens [%X]: ", sloc);
1537
1538         for(t=tokbuf; *t!=EOL; t++)
1539         {
1540                 if (*t == COLON)
1541                         printf("[COLON]");
1542                 else if (*t == CONST)
1543                 {
1544                         t++;
1545                         printf("[CONST: $%X]", (uint32_t)*t);
1546                 }
1547                 else if (*t == ACONST)
1548                         printf("[ACONST]");
1549                 else if (*t == STRING)
1550 //                      printf("[STRING]");
1551                 {
1552                         t++;
1553                         printf("[STRING:\"%s\"]", string[*t]);
1554                 }
1555                 else if (*t == SYMBOL)
1556                 {
1557                         t++;
1558                         printf("[SYMBOL:\"%s\"]", string[*t]);
1559                 }
1560                 else if (*t == EOS)
1561                         printf("[EOS]");
1562                 else if (*t == TKEOF)
1563                         printf("[TKEOF]");
1564                 else if (*t == DEQUALS)
1565                         printf("[DEQUALS]");
1566                 else if (*t == SET)
1567                         printf("[SET]");
1568                 else if (*t == REG)
1569                         printf("[REG]");
1570                 else if (*t == DCOLON)
1571                         printf("[DCOLON]");
1572                 else if (*t == GE)
1573                         printf("[GE]");
1574                 else if (*t == LE)
1575                         printf("[LE]");
1576                 else if (*t == NE)
1577                         printf("[NE]");
1578                 else if (*t == SHR)
1579                         printf("[SHR]");
1580                 else if (*t == SHL)
1581                         printf("[SHL]");
1582                 else if (*t == UNMINUS)
1583                         printf("[UNMINUS]");
1584                 else if (*t == DOTB)
1585                         printf("[DOTB]");
1586                 else if (*t == DOTW)
1587                         printf("[DOTW]");
1588                 else if (*t == DOTL)
1589                         printf("[DOTL]");
1590                 else if (*t == DOTI)
1591                         printf("[DOTI]");
1592                 else if (*t == ENDEXPR)
1593                         printf("[ENDEXPR]");
1594                 else if (*t == CR_DEFINED)
1595                         printf("[CR_DEFINED]");
1596                 else if (*t == CR_REFERENCED)
1597                         printf("[CR_REFERENCED]");
1598                 else if (*t == CR_STREQ)
1599                         printf("[CR_STREQ]");
1600                 else if (*t == CR_MACDEF)
1601                         printf("[CR_MACDEF]");
1602                 else if (*t == CR_TIME)
1603                         printf("[CR_TIME]");
1604                 else if (*t == CR_DATE)
1605                         printf("[CR_DATE]");
1606                 else if (*t >= 0x20 && *t <= 0x2F)
1607                         printf("[%c]", (char)*t);
1608                 else if (*t >= 0x3A && *t <= 0x3F)
1609                         printf("[%c]", (char)*t);
1610                 else if (*t >= 0x80 && *t <= 0x87)
1611                         printf("[D%u]", ((uint32_t)*t) - 0x80);
1612                 else if (*t >= 0x88 && *t <= 0x8F)
1613                         printf("[A%u]", ((uint32_t)*t) - 0x88);
1614                 else
1615                         printf("[%X:%c]", (uint32_t)*t, (char)*t);
1616 //                      printf("[%X]", (uint32_t)*t);
1617         }
1618
1619         printf("[EOL]\n");
1620 }