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