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