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