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