]> Shamusworld >> Repos - rmac/blob - token.c
5b3d0737b02ea308f19938d86ec1ec3bfd3fcc53
[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 int8_t 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_ABSCOUNT:
558                                                                 d = "^^abscount";
559                                                                 break;
560                                                         case CR_DATE:
561                                                                 d = "^^date";
562                                                                 break;
563                                                         case CR_TIME:
564                                                                 d = "^^time";
565                                                                 break;
566                                                         case CR_DEFINED:
567                                                                 d = "^^defined ";
568                                                                 break;
569                                                         case CR_REFERENCED:
570                                                                 d = "^^referenced ";
571                                                                 break;
572                                                         case CR_STREQ:
573                                                                 d = "^^streq ";
574                                                                 break;
575                                                         case CR_MACDEF:
576                                                                 d = "^^macdef ";
577                                                                 break;
578                                                         default:
579                                                                 if (dst >= edst)
580                                                                         goto overflow;
581
582                                                                 *dst++ = (char)*(tk - 1);
583                                                                 break;
584                                                         }
585                                                 }
586
587                                                 // If 'd' != NULL, copy string to destination
588                                                 if (d != NULL)
589                                                 {
590 strcopy:
591                                                         DEBUG printf("d='%s'\n", d);
592
593                                                         while (*d != EOS)
594                                                         {
595                                                                 if (dst >= edst)
596                                                                         goto overflow;
597                                                                 else
598                                                                         *dst++ = *d++;
599                                                         }
600                                                 }
601                                         }
602                                 }
603                         }
604                 }
605         }
606
607         *dst = EOS;
608         DEBUG { printf("ExM: dst=\"%s\"\n", dest); }
609         return OK;
610
611 overflow:
612         *dst = EOS;
613         DEBUG printf("*** OVERFLOW LINE ***\n%s\n", dest);
614         return fatal("line too long as a result of macro expansion");
615 }
616
617
618 //
619 // Get next line of text from a macro
620 //
621 char * GetNextMacroLine(void)
622 {
623 //      unsigned source_addr;
624
625         IMACRO * imacro = cur_inobj->inobj.imacro;
626 //      LONG * strp = imacro->im_nextln;
627         struct LineList * strp = imacro->im_nextln;
628
629         if (strp == NULL)                                               // End-of-macro
630                 return NULL;
631
632 //      imacro->im_nextln = (LONG *)*strp;
633         imacro->im_nextln = strp->next;
634 //      ExpandMacro((char *)(strp + 1), imacro->im_lnbuf, LNSIZ);
635         ExpandMacro(strp->line, imacro->im_lnbuf, LNSIZ);
636
637         return imacro->im_lnbuf;
638 }
639
640
641 //
642 // Get next line of text from a repeat block
643 //
644 char * GetNextRepeatLine(void)
645 {
646
647         IREPT * irept = cur_inobj->inobj.irept;
648         LONG * strp = irept->ir_nextln;                 // initial null
649
650         // Do repeat at end of .rept block's string list
651         if (strp == NULL)
652         {
653                 DEBUG printf("back-to-top-of-repeat-block count=%d\n", (int)irept->ir_count);
654                 irept->ir_nextln = irept->ir_firstln;   // copy first line
655
656                 if (irept->ir_count-- == 0)
657                 {
658                         DEBUG printf("end-repeat-block\n");
659                         return NULL;
660                 }
661
662                 strp = irept->ir_nextln;
663         }
664
665         strcpy(irbuf, (char *)(irept->ir_nextln + 1));
666         DEBUG printf("repeat line='%s'\n", irbuf);
667         irept->ir_nextln = (LONG *)*strp;
668
669         return irbuf;
670 }
671
672
673 //
674 // Include a source file used at the root, and for ".include" files
675 //
676 int include(int handle, char * fname)
677 {
678         IFILE * ifile;
679         INOBJ * inobj;
680         FILEREC * fr;
681
682         // Debug mode
683         if (debug)
684                 printf("[include: %s, cfileno=%u]\n", fname, cfileno);
685
686         // Alloc and initialize include-descriptors
687         inobj = a_inobj(SRC_IFILE);
688         ifile = inobj->inobj.ifile;
689
690         ifile->ifhandle = handle;                               // Setup file handle
691         ifile->ifind = ifile->ifcnt = 0;                // Setup buffer indices
692         ifile->ifoldlineno = curlineno;                 // Save old line number
693         ifile->ifoldfname = curfname;                   // Save old filename
694         ifile->ifno = cfileno;                                  // Save old file number
695
696 //      cfileno = filecount++;                                  // Compute new file number
697         // NB: This *must* be preincrement, we're adding one to the filecount here!
698         cfileno = ++filecount;                                  // Compute NEW file number
699         curfname = strdup(fname);                               // Set current filename (alloc storage)
700         curlineno = 0;                                                  // Start on line zero
701
702         // Add another file to the file-record
703         fr = (FILEREC *)malloc(sizeof(FILEREC));
704         fr->frec_next = NULL;
705         fr->frec_name = curfname;
706
707         if (last_fr == NULL)
708                 filerec = fr;                                           // Add first filerec 
709         else
710                 last_fr->frec_next = fr;                        // Append to list of filerecs 
711
712         last_fr = fr;
713         DEBUG printf("[include: curfname: %s, cfileno=%u]\n", curfname, cfileno);
714
715         return OK;
716 }
717
718
719 //
720 // Pop the current input level
721 //
722 int fpop(void)
723 {
724         IFILE * ifile;
725         IMACRO * imacro;
726         LONG * p, * p1;
727         INOBJ * inobj = cur_inobj;
728
729         if (inobj != NULL)
730         {
731                 // Pop IFENT levels until we reach the conditional assembly context we
732                 // were at when the input object was entered.
733                 int numUnmatched = 0;
734
735                 while (ifent != inobj->in_ifent)
736                 {
737                         if (d_endif() != 0)             // Something bad happened during endif parsing?
738                                 return -1;                      // If yes, bail instead of getting stuck in a loop
739
740                         numUnmatched++;
741                 }
742
743                 // Give a warning to the user that we had to wipe their bum for them
744                 if (numUnmatched > 0)
745                         warni("missing %d .endif(s)", numUnmatched);
746
747                 tok = inobj->in_otok;           // Restore tok and otok
748                 etok = inobj->in_etok;
749
750                 switch (inobj->in_type)
751                 {
752                 case SRC_IFILE:                         // Pop and release an IFILE
753                         if (debug)
754                                 printf("[Leaving: %s]\n", curfname);
755
756                         ifile = inobj->inobj.ifile;
757                         ifile->if_link = f_ifile;
758                         f_ifile = ifile;
759                         close(ifile->ifhandle);                 // Close source file
760 if (debug)      printf("[fpop (pre):  curfname=%s]\n", curfname);
761                         curfname = ifile->ifoldfname;   // Set current filename
762 if (debug)      printf("[fpop (post): curfname=%s]\n", curfname);
763 if (debug)      printf("[fpop: (pre)  cfileno=%d ifile->ifno=%d]\n", (int)cfileno, (int)ifile->ifno);
764                         curlineno = ifile->ifoldlineno; // Set current line# 
765                         DEBUG printf("cfileno=%d ifile->ifno=%d\n", (int)cfileno, (int)ifile->ifno);
766                         cfileno = ifile->ifno;                  // Restore current file number
767 if (debug)      printf("[fpop: (post) cfileno=%d ifile->ifno=%d]\n", (int)cfileno, (int)ifile->ifno);
768                         break;
769                 case SRC_IMACRO:                                        // Pop and release an IMACRO
770                         imacro = inobj->inobj.imacro;
771                         imacro->im_link = f_imacro;
772                         f_imacro = imacro;
773                         break;
774                 case SRC_IREPT:                                         // Pop and release an IREPT
775                         DEBUG printf("dealloc IREPT\n");
776                         p = inobj->inobj.irept->ir_firstln;
777
778                         while (p != NULL)
779                         {
780                                 p1 = (LONG *)*p;
781                                 p = p1;
782                         }
783
784                         break;
785                 }
786
787                 cur_inobj = inobj->in_link;
788                 inobj->in_link = f_inobj;
789                 f_inobj = inobj;
790         }
791
792         return 0;
793 }
794
795
796 //
797 // Get line from file into buf, return NULL on EOF or ptr to the start of a
798 // null-term line
799 //
800 char * GetNextLine(void)
801 {
802         int i, j;
803         char * p, * d;
804         int readamt = -1;                                               // 0 if last read() yeilded 0 bytes
805         IFILE * fl = cur_inobj->inobj.ifile;
806
807         for(;;)
808         {
809                 // Scan for next end-of-line; handle stupid text formats by treating
810                 // \r\n the same as \n. (lone '\r' at end of buffer means we have to
811                 // check for '\n').
812                 d = &fl->ifbuf[fl->ifind];
813
814                 for(p=d, i=0, j=fl->ifcnt; i<j; i++, p++)
815                 {
816                         if (*p == '\r' || *p == '\n')
817                         {
818                                 i++;
819
820                                 if (*p == '\r')
821                                 {
822                                         if (i >= j)
823                                                 break;  // Need to read more, then look for '\n' to eat 
824                                         else if (p[1] == '\n')
825                                                 i++;
826                                 }
827
828                                 // Cover up the newline with end-of-string sentinel
829                                 *p = '\0';
830
831                                 fl->ifind += i;
832                                 fl->ifcnt -= i;
833                                 return d;
834                         }
835                 }
836
837                 // Handle hanging lines by ignoring them (Input file is exhausted, no
838                 // \r or \n on last line)
839                 // Shamus: This is retarded. Never ignore any input!
840                 if (!readamt && fl->ifcnt)
841                 {
842 #if 0
843                         fl->ifcnt = 0;
844                         *p = '\0';
845                         return NULL;
846 #else
847                         // Really should check to see if we're at the end of the buffer!
848                         // :-P
849                         fl->ifbuf[fl->ifind + fl->ifcnt] = '\0';
850                         fl->ifcnt = 0;
851                         return &fl->ifbuf[fl->ifind];
852 #endif
853                 }
854
855                 // Truncate and return absurdly long lines.
856                 if (fl->ifcnt >= QUANTUM)
857                 {
858                         fl->ifbuf[fl->ifind + fl->ifcnt - 1] = '\0';
859                         fl->ifcnt = 0;
860                         return &fl->ifbuf[fl->ifind];
861                 }
862
863                 // Relocate what's left of a line to the beginning of the buffer, and
864                 // read some more of the file in; return NULL if the buffer's empty and
865                 // on EOF.
866                 if (fl->ifind != 0)
867                 {
868                         p = &fl->ifbuf[fl->ifind];
869                         d = &fl->ifbuf[fl->ifcnt & 1];
870
871                         for(i=0; i<fl->ifcnt; i++)
872                                 *d++ = *p++;
873
874                         fl->ifind = fl->ifcnt & 1;
875                 }
876
877                 readamt = read(fl->ifhandle, &fl->ifbuf[fl->ifind + fl->ifcnt], QUANTUM);
878
879                 if (readamt < 0)
880                         return NULL;
881
882                 if ((fl->ifcnt += readamt) == 0)
883                         return NULL;
884         }
885 }
886
887
888 //
889 // Tokenize a line
890 //
891 int TokenizeLine(void)
892 {
893         char * ln = NULL;                       // Ptr to current position in line
894         char * p;                                       // Random character ptr
895         TOKEN * tk;                                     // Token-deposit ptr
896         int state = 0;                          // State for keyword detector
897         int j = 0;                                      // Var for keyword detector
898         char c;                                         // Random char
899         VALUE v;                                        // Random value
900         char * nullspot = NULL;         // Spot to clobber for SYMBOL termination
901         int stuffnull;                          // 1:terminate SYMBOL '\0' at *nullspot
902         char c1;
903         int stringNum = 0;                      // Pointer to string locations in tokenized line
904
905 retry:
906
907         if (cur_inobj == NULL)                                  // Return EOF if input stack is empty
908                 return TKEOF;
909
910         // Get another line of input from the current input source: a file, a
911         // macro, or a repeat-block
912         switch (cur_inobj->in_type)
913         {
914         // Include-file:
915         // o  handle EOF;
916         // o  bump source line number;
917         // o  tag the listing-line with a space;
918         // o  kludge lines generated by Alcyon C.
919         case SRC_IFILE:
920                 if ((ln = GetNextLine()) == NULL)
921                 {
922 if (debug) printf("TokenizeLine: Calling fpop() from SRC_IFILE...\n");
923                         if (fpop() == 0)                                // Pop input level
924                                 goto retry;                                     // Try for more lines 
925                         else
926                         {
927                                 ifent->if_prev = (IFENT *) - 1; //Signal Assemble() that we have reached EOF with unbalanced if/endifs
928                                 return TKEOF;
929                         }
930                 }
931
932                 curlineno++;                                            // Bump line number
933                 lntag = SPACE;
934
935                 if (as68_flag)
936                 {
937                         // AS68 compatibility, throw away all lines starting with
938                         // back-quotes, tildes, or '*'
939                         // On other lines, turn the first '*' into a semi-colon.
940                         if (*ln == '`' || *ln == '~' || *ln == '*')
941                                 *ln = ';';
942                         else
943                         {
944                                 for(p=ln; *p!=EOS; p++)
945                                 {
946                                         if (*p == '*')
947                                         {
948                                                 *p = ';';
949                                                 break;
950                                         }
951                                 }
952                         }
953                 }
954
955                 break;
956         // Macro-block:
957         // o  Handle end-of-macro;
958         // o  tag the listing-line with an at (@) sign.
959         case SRC_IMACRO:
960                 if ((ln = GetNextMacroLine()) == NULL)
961                 {
962                         if (ExitMacro() == 0)                   // Exit macro (pop args, do fpop(), etc)
963                                 goto retry;                                     // Try for more lines...
964                         else
965                                 return TKEOF;                           // Oops, we got a non zero return code, signal EOF
966                 }
967
968                 lntag = '@';
969                 break;
970         // Repeat-block:
971         // o  Handle end-of-repeat-block;
972         // o  tag the listing-line with a pound (#) sign.
973         case SRC_IREPT:
974                 if ((ln = GetNextRepeatLine()) == NULL)
975                 {
976 if (debug) printf("TokenizeLine: Calling fpop() from SRC_IREPT...\n");
977                         fpop();
978                         goto retry;
979                 }
980
981                 lntag = '#';
982                 break;
983         }
984
985         // Save text of the line.  We only do this during listings and within
986         // macro-type blocks, since it is expensive to unconditionally copy every
987         // line.
988         if (lnsave)
989                 strcpy(lnbuf, ln);
990
991         // General house-keeping
992         tok = tokeol;                   // Set "tok" to EOL in case of error
993         tk = etok;                              // Reset token ptr
994         stuffnull = 0;                  // Don't stuff nulls
995         totlines++;                             // Bump total #lines assembled
996
997         // See if the entire line is a comment. This is a win if the programmer
998         // puts in lots of comments
999         if (*ln == '*' || *ln == ';' || ((*ln == '/') && (*(ln + 1) == '/')))
1000                 goto goteol;
1001
1002         // Main tokenization loop;
1003         // o  skip whitespace;
1004         // o  handle end-of-line;
1005         // o  handle symbols;
1006         // o  handle single-character tokens (operators, etc.);
1007         // o  handle multiple-character tokens (constants, strings, etc.).
1008         for(; *ln!=EOS;)
1009         {
1010                 // Skip whitespace, handle EOL
1011                 while ((int)chrtab[*ln] & WHITE)
1012                         ln++;
1013
1014                 // Handle EOL, comment with ';'
1015                 if (*ln == EOS || *ln == ';'|| ((*ln == '/') && (*(ln + 1) == '/'))) 
1016                         break;
1017
1018                 // Handle start of symbol. Symbols are null-terminated in place. The
1019                 // termination is always one symbol behind, since there may be no place
1020                 // for a null in the case that an operator immediately follows the name.
1021                 c = chrtab[*ln];
1022
1023                 if (c & STSYM)
1024                 {
1025                         if (stuffnull)                  // Terminate old symbol from previous pass
1026                                 *nullspot = EOS;
1027
1028                         v = 0;                                  // Assume no DOT attrib follows symbol
1029                         stuffnull = 1;
1030
1031                         // In some cases, we need to check for a DOTx at the *beginning*
1032                         // of a symbol, as the "start" of the line we're currently looking
1033                         // at could be somewhere in the middle of that line!
1034                         if (*ln == '.')
1035                         {
1036                                 // Make sure that it's *only* a .[bwsl] following, and not the
1037                                 // start of a local symbol:
1038                                 if ((chrtab[*(ln + 1)] & DOT)
1039                                         && (dotxtab[*(ln + 1)] != 0)
1040                                         && !(chrtab[*(ln + 2)] & CTSYM))
1041                                 {
1042                                         // We found a legitimate DOTx construct, so add it to the
1043                                         // token stream:
1044                                         ln++;
1045                                         stuffnull = 0;
1046                                         *tk++ = (TOKEN)dotxtab[*ln++];
1047                                         continue;
1048                                 }
1049                         }
1050
1051                         p = nullspot = ln++;    // Nullspot -> start of this symbol
1052
1053                         // Find end of symbol (and compute its length)
1054                         for(j=1; (int)chrtab[*ln]&CTSYM; j++)
1055                                 ln++;
1056
1057                         // Handle "DOT" special forms (like ".b") that follow a normal
1058                         // symbol or keyword:
1059                         if (*ln == '.')
1060                         {
1061                                 *ln++ = EOS;            // Terminate symbol
1062                                 stuffnull = 0;          // And never try it again 
1063
1064                                 // Character following the `.' must have a DOT attribute, and
1065                                 // the chararacter after THAT one must not have a start-symbol
1066                                 // attribute (to prevent symbols that look like, for example,
1067                                 // "zingo.barf", which might be a good idea anyway....)
1068                                 if (((chrtab[*ln] & DOT) == 0) || (dotxtab[*ln] == 0))
1069                                         return error("[bwsl] must follow '.' in symbol");
1070
1071                                 v = (VALUE)dotxtab[*ln++];
1072
1073                                 if (chrtab[*ln] & CTSYM)
1074                                         return error("misuse of '.', not allowed in symbols");
1075                         }
1076
1077                         // If the symbol is small, check to see if it's really the name of
1078                         // a register.
1079                         if (j <= KWSIZE)
1080                         {
1081                                 for(state=0; state>=0;)
1082                                 {
1083                                         j = (int)tolowertab[*p++];
1084                                         j += kwbase[state];
1085
1086                                         if (kwcheck[j] != state)
1087                                         {
1088                                                 j = -1;
1089                                                 break;
1090                                         }
1091
1092                                         if (*p == EOS || p == ln)
1093                                         {
1094                                                 j = kwaccept[j];
1095                                                 break;
1096                                         }
1097
1098                                         state = kwtab[j];
1099                                 }
1100                         }
1101                         else
1102                         {
1103                                 j = -1;
1104                         }
1105
1106                         // Make j = -1 if user tries to use a RISC register while in 68K mode
1107                         if (!(rgpu || rdsp) && ((TOKEN)j >= KW_R0 && (TOKEN)j <= KW_R31))
1108                         {
1109                                 j = -1;
1110                         }
1111
1112                         // Make j = -1 if time, date etc with no preceeding ^^
1113                         // defined, referenced, streq, macdef, date and time
1114                         switch ((TOKEN)j)
1115                         {
1116                         case 112:   // defined
1117                         case 113:   // referenced
1118                         case 118:   // streq
1119                         case 119:   // macdef
1120                         case 120:   // time
1121                         case 121:   // date
1122                                 j = -1;
1123                         }
1124
1125                         // If not tokenized keyword OR token was not found
1126                         if ((j < 0) || (state < 0))
1127                         {
1128                                 *tk++ = SYMBOL;
1129 //#warning
1130 //problem here: nullspot is a char * but TOKEN is a uint32_t. On a 64-bit
1131 //system, this will cause all kinds of mischief.
1132 #if 0
1133                                 *tk++ = (TOKEN)nullspot;
1134 #else
1135                                 string[stringNum] = nullspot;
1136                                 *tk++ = stringNum;
1137                                 stringNum++;
1138 #endif
1139                         }
1140                         else
1141                         {
1142                                 *tk++ = (TOKEN)j;
1143                                 stuffnull = 0;
1144                         }
1145
1146                         if (v)                                                  // Record attribute token (if any)
1147                                 *tk++ = (TOKEN)v;
1148
1149                         if (stuffnull)                                  // Arrange for string termination on next pass
1150                                 nullspot = ln;
1151
1152                         continue;
1153                 }
1154
1155                 // Handle identity tokens
1156                 if (c & SELF)
1157                 {
1158                         *tk++ = *ln++;
1159                         continue;
1160                 }
1161
1162                 // Handle multiple-character tokens
1163                 if (c & MULTX)
1164                 {
1165                         switch (*ln++)
1166                         {
1167                         case '!':               // ! or != 
1168                                 if (*ln == '=')
1169                                 {
1170                                         *tk++ = NE;
1171                                         ++ln;
1172                                 }
1173                                 else
1174                                         *tk++ = '!';
1175
1176                                 continue;
1177                         case '\'':              // 'string' 
1178                         case '\"':              // "string" 
1179                                 c1 = ln[-1];
1180                                 *tk++ = STRING;
1181 //#warning
1182 // More char * stuffing (8 bytes) into the space of 4 (TOKEN).
1183 // Need to figure out how to fix this crap.
1184 #if 0
1185                                 *tk++ = (TOKEN)ln;
1186 #else
1187                                 string[stringNum] = ln;
1188                                 *tk++ = stringNum;
1189                                 stringNum++;
1190 #endif
1191
1192                                 for(p=ln; *ln!=EOS && *ln!=c1;)
1193                                 {
1194                                         c = *ln++;
1195
1196                                         if (c == '\\')
1197                                         {
1198                                                 switch (*ln++)
1199                                                 {
1200                                                 case EOS:
1201                                                         return(error("unterminated string"));
1202                                                 case 'e':
1203                                                         c = '\033';
1204                                                         break;
1205                                                 case 'n':
1206                                                         c = '\n';
1207                                                         break;
1208                                                 case 'b':
1209                                                         c = '\b';
1210                                                         break;
1211                                                 case 't':
1212                                                         c = '\t';
1213                                                         break;
1214                                                 case 'r':
1215                                                         c = '\r';
1216                                                         break;
1217                                                 case 'f':
1218                                                         c = '\f';
1219                                                         break;
1220                                                 case '\"':
1221                                                         c = '\"';
1222                                                         break;
1223                                                 case '\'':
1224                                                         c = '\'';
1225                                                         break;
1226                                                 case '\\':
1227                                                         c = '\\';
1228                                                         break;
1229                                                 default:
1230                                                         warn("bad backslash code in string");
1231                                                         ln--;
1232                                                         break;
1233                                                 }
1234                                         }
1235
1236                                         *p++ = c;
1237                                 }
1238
1239                                 if (*ln++ != c1)
1240                                         return error("unterminated string");
1241
1242                                 *p++ = EOS;
1243                                 continue;
1244                         case '$':               // $, hex constant
1245                                 if (chrtab[*ln] & HDIGIT)
1246                                 {
1247                                         v = 0;
1248
1249                                         // Parse the hex value
1250                                         while (hextab[*ln] >= 0)
1251                                                 v = (v << 4) + (int)hextab[*ln++];
1252
1253                                         // ggn: Okay, some comments here are in order I think....
1254                                         // The original madmac sources didn't parse the size at
1255                                         // this point (i.e. .b/.w/.l). It was probably done at
1256                                         // another point, although it's unclear to me exactly
1257                                         // where. So why change this? My understanding (at least
1258                                         // from what SCPCD said on IRC) is that .w addressing
1259                                         // formats produce wrong code on jaguar (or doesn't execute
1260                                         // properly? something like that). So the code was changed
1261                                         // to mask off the upper bits depending on length (note: I
1262                                         // don't think .b is valid at all! I only know of .w/.l, so
1263                                         // this should probably be wiped). Then the code that
1264                                         // parses the constant and checks to see if it's between
1265                                         // $ffff0000 and $8000 never got triggered, so yay job
1266                                         // done! ...now say we want to assemble a st .prg. One of
1267                                         // the most widely spread optimisations is move.X expr.w,Y
1268                                         // (or vice versa, or both, anyway...) to access hardware
1269                                         // registers (which are mapped to $fxxxxx). This botchy
1270                                         // thing would create "hilarious" code while trying to
1271                                         // access hardware registers. So I made a condition to see
1272                                         // if st mode or jaguar is active and apply the both or
1273                                         // not. One last note: this is hardcoded to get optimised
1274                                         // for now on ST mode, i.e. it can't generate code like
1275                                         // move.w $00001234,d0 - it'll always get optimised to
1276                                         // move.w $1234.w,d0. It's probably ok, but maybe a warning
1277                                         // should be emitted? Or maybe finding a way to make it not
1278                                         // auto-optimise? I think it's ok for now...
1279                                         if (*ln == '.')
1280                                         {
1281                                                 if (obj_format == ALCYON)
1282                                                 {
1283                                                         if ((*(ln + 1) == 'b') || (*(ln + 1) == 'B') || (*(ln + 1) == 'w') || (*(ln + 1) == 'W') || (*(ln + 1) == 'l') || (*(ln + 1) == 'L'))
1284                                                         {
1285                                                                 ln += 2;
1286                                                         }
1287                                                 }
1288                                                 else
1289                                                 {
1290                                                         if ((*(ln + 1) & 0xDF) == 'B')
1291                                                         {
1292                                                                 v &= 0x000000FF;
1293                                                                 ln += 2;
1294                                                         }
1295                                                         else if ((*(ln + 1) & 0xDF) == 'W')
1296                                                         {
1297                                                                 v &= 0x0000FFFF;
1298                                                                 ln += 2;
1299                                                         }
1300                                                         else if ((*(ln + 1) & 0xDF) == 'L')
1301                                                         {
1302                                                                 ln += 2;
1303                                                         }
1304                                                 }
1305                                         }
1306
1307                                         *tk++ = CONST;
1308                                         *tk++ = v;
1309                                 }
1310                                 else
1311                                         *tk++ = '$';
1312
1313                                 continue;
1314                         case '<':               // < or << or <> or <= 
1315                                 switch (*ln)
1316                                 {
1317                                 case '<':
1318                                         *tk++ = SHL;
1319                                         ++ln;
1320                                         continue;
1321                                 case '>':
1322                                         *tk++ = NE;
1323                                         ++ln;
1324                                         continue;
1325                                 case '=':
1326                                         *tk++ = LE;
1327                                         ++ln;
1328                                         continue;
1329                                 default:
1330                                         *tk++ = '<';
1331                                         continue;
1332                                 }
1333                         case ':':               // : or ::
1334                                 if (*ln == ':')
1335                                 {
1336                                         *tk++ = DCOLON;
1337                                         ++ln;
1338                                 }
1339                                 else
1340                                         *tk++ = ':';
1341
1342                                 continue;
1343                         case '=':               // = or == 
1344                                 if (*ln == '=')
1345                                 {
1346                                         *tk++ = DEQUALS;
1347                                         ++ln;
1348                                 }
1349                                 else
1350                                         *tk++ = '=';
1351
1352                                 continue;
1353                         case '>':               // > or >> or >= 
1354                                 switch (*ln)
1355                                 {
1356                                 case '>':
1357                                         *tk++ = SHR;
1358                                         ln++;
1359                                         continue;
1360                                 case '=':
1361                                         *tk++ = GE;
1362                                         ln++;
1363                                         continue;
1364                                 default:
1365                                         *tk++ = '>';
1366                                         continue;
1367                                 }
1368                         case '%':               // % or binary constant 
1369                                 if (*ln < '0' || *ln > '1')
1370                                 {
1371                                         *tk++ = '%';
1372                                         continue;
1373                                 }
1374
1375                                 v = 0;
1376
1377                                 while (*ln >= '0' && *ln <= '1')
1378                                         v = (v << 1) + *ln++ - '0';
1379
1380                                 if (*ln == '.')
1381                                 {
1382                                         if ((*(ln + 1) == 'b') || (*(ln + 1) == 'B'))
1383                                         {
1384                                                 v &= 0x000000FF;
1385                                                 ln += 2;
1386                                         }
1387
1388                                         if ((*(ln + 1) == 'w') || (*(ln + 1) == 'W'))
1389                                         {
1390                                                 v &= 0x0000FFFF;
1391                                                 ln += 2;
1392                                         }
1393
1394                                         if ((*(ln + 1) == 'l') || (*(ln + 1) == 'L'))
1395                                         {
1396                                                 ln += 2;
1397                                         }
1398                                 }
1399
1400                                 *tk++ = CONST;
1401                                 *tk++ = v;
1402                                 continue;
1403                         case '@':               // @ or octal constant 
1404                                 if (*ln < '0' || *ln > '7')
1405                                 {
1406                                         *tk++ = '@';
1407                                         continue;
1408                                 }
1409
1410                                 v = 0;
1411
1412                                 while (*ln >= '0' && *ln <= '7')
1413                                         v = (v << 3) + *ln++ - '0';
1414
1415                                 if (*ln == '.')
1416                                 {
1417                                         if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1418                                         {
1419                                                 v &= 0x000000FF;
1420                                                 ln += 2;
1421                                         }
1422
1423                                         if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1424                                         {
1425                                                 v &= 0x0000FFFF;
1426                                                 ln += 2;
1427                                         }
1428
1429                                         if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1430                                         {
1431                                                 ln += 2;
1432                                         }
1433                                 }
1434
1435                                 *tk++ = CONST;
1436                                 *tk++ = v;
1437                                 continue;
1438                         case '^':               // ^ or ^^ <operator-name>
1439                                 if (*ln != '^')
1440                                 {
1441                                         *tk++ = '^';
1442                                         continue;
1443                                 }
1444
1445                                 if (((int)chrtab[*++ln] & STSYM) == 0)
1446                                 {
1447                                         error("invalid symbol following ^^");
1448                                         continue;
1449                                 }
1450
1451                                 p = ln++;
1452
1453                                 while ((int)chrtab[*ln] & CTSYM)
1454                                         ++ln;
1455
1456                                 for(state=0; state>=0;)
1457                                 {
1458                                         // Get char, convert to lowercase 
1459                                         j = *p++;
1460
1461                                         if (j >= 'A' && j <= 'Z')
1462                                                 j += 0x20;
1463
1464                                         j += kwbase[state];
1465
1466                                         if (kwcheck[j] != state)
1467                                         {
1468                                                 j = -1;
1469                                                 break;
1470                                         }
1471
1472                                         if (*p == EOS || p == ln)
1473                                         {
1474                                                 j = kwaccept[j];
1475                                                 break;
1476                                         }
1477
1478                                         state = kwtab[j];
1479                                 }
1480
1481                                 if (j < 0 || state < 0)
1482                                 {
1483                                         error("unknown symbol following ^^");
1484                                         continue;
1485                                 }
1486
1487                                 *tk++ = (TOKEN)j;
1488                                 continue;
1489                         default:
1490                                 interror(2);    // Bad MULTX entry in chrtab
1491                                 continue;
1492                         }
1493                 }
1494
1495                 // Handle decimal constant
1496                 if (c & DIGIT)
1497                 {
1498                         v = 0;
1499
1500                         while ((int)chrtab[*ln] & DIGIT)
1501                                 v = (v * 10) + *ln++ - '0';
1502
1503                         // See if there's a .[bwl] after the constant & deal with it if so
1504                         if (*ln == '.')
1505                         {
1506                                 if ((*(ln + 1) == 'b') || (*(ln + 1) == 'B'))
1507                                 {
1508                                         v &= 0x000000FF;
1509                                         ln += 2;
1510                                 }
1511                                 else if ((*(ln + 1) == 'w') || (*(ln + 1) == 'W'))
1512                                 {
1513                                         v &= 0x0000FFFF;
1514                                         ln += 2;
1515                                 }
1516                                 else if ((*(ln + 1) == 'l') || (*(ln + 1) == 'L'))
1517                                 {
1518                                         ln += 2;
1519                                 }
1520                         }
1521
1522                         *tk++ = CONST;
1523                         *tk++ = v;
1524 //printf("CONST: %i\n", v);
1525                         continue;
1526                 }
1527
1528                 // Handle illegal character
1529                 return error("illegal character");
1530         }
1531
1532         // Terminate line of tokens and return "success."
1533
1534 goteol:
1535         tok = etok;                                                             // Set tok to beginning of line
1536
1537         if (stuffnull)                                                  // Terminate last SYMBOL
1538                 *nullspot = EOS;
1539
1540         *tk++ = EOL;
1541
1542         return OK;
1543 }
1544
1545
1546 //
1547 // .GOTO <label>        goto directive
1548 // 
1549 // The label is searched for starting from the first line of the current,
1550 // enclosing macro definition. If no enclosing macro exists, an error is
1551 // generated.
1552 // 
1553 // A label is of the form:
1554 // 
1555 // :<name><whitespace>
1556 // 
1557 // The colon must appear in column 1.  The label is stripped prior to macro
1558 // expansion, and is NOT subject to macro expansion.  The whitespace may also
1559 // be EOL.
1560 //
1561 //int d_goto(WORD siz) {
1562 //int d_goto(void)
1563 int d_goto(WORD unused)
1564 {
1565         char * s1, * s2;
1566
1567         // Setup for the search
1568         if (*tok != SYMBOL)
1569                 return error("missing label");
1570
1571 //      sym = (char *)tok[1];
1572         char * sym = string[tok[1]];
1573         tok += 2;
1574
1575         if (cur_inobj->in_type != SRC_IMACRO)
1576                 return error("goto not in macro");
1577
1578         IMACRO * imacro = cur_inobj->inobj.imacro;
1579 //      defln = (LONG *)imacro->im_macro->svalue;
1580         struct LineList * defln = imacro->im_macro->lineList;
1581
1582         // Find the label, starting with the first line.
1583 //      for(; defln!=NULL; defln=(LONG *)*defln)
1584         for(; defln!=NULL; defln=defln->next)
1585         {
1586 //              if (*(char *)(defln + 1) == ':')
1587                 if (defln->line[0] == ':')
1588                 {
1589                         // Compare names (sleazo string compare)
1590                         // This string compare is not right. Doesn't check for lengths.
1591                         // (actually it does, but in a crappy, unclear way.)
1592 WARNING(!!!! Bad string comparison !!!)
1593                         s1 = sym;
1594 //                      s2 = (char *)(defln + 1) + 1;
1595                         s2 = defln->line;
1596
1597                         while (*s1 == *s2)
1598                         {
1599                                 if (*s1 == EOS)
1600                                         break;
1601                                 else
1602                                 {
1603                                         s1++;
1604                                         s2++;
1605                                 }
1606                         }
1607
1608                         // Found the label, set new macro next-line and return.
1609                         if ((*s2 == EOS) || ((int)chrtab[*s2] & WHITE))
1610                         {
1611                                 imacro->im_nextln = defln;
1612                                 return 0;
1613                         }
1614                 }
1615         }
1616
1617         return error("goto label not found");
1618 }
1619
1620
1621 void DumpTokenBuffer(void)
1622 {
1623         TOKEN * t;
1624         printf("Tokens [%X]: ", sloc);
1625
1626         for(t=tokbuf; *t!=EOL; t++)
1627         {
1628                 if (*t == COLON)
1629                         printf("[COLON]");
1630                 else if (*t == CONST)
1631                 {
1632                         t++;
1633                         printf("[CONST: $%X]", (uint32_t)*t);
1634                 }
1635                 else if (*t == ACONST)
1636                         printf("[ACONST]");
1637                 else if (*t == STRING)
1638                 {
1639                         t++;
1640                         printf("[STRING:\"%s\"]", string[*t]);
1641                 }
1642                 else if (*t == SYMBOL)
1643                 {
1644                         t++;
1645                         printf("[SYMBOL:\"%s\"]", string[*t]);
1646                 }
1647                 else if (*t == EOS)
1648                         printf("[EOS]");
1649                 else if (*t == TKEOF)
1650                         printf("[TKEOF]");
1651                 else if (*t == DEQUALS)
1652                         printf("[DEQUALS]");
1653                 else if (*t == SET)
1654                         printf("[SET]");
1655                 else if (*t == REG)
1656                         printf("[REG]");
1657                 else if (*t == DCOLON)
1658                         printf("[DCOLON]");
1659                 else if (*t == GE)
1660                         printf("[GE]");
1661                 else if (*t == LE)
1662                         printf("[LE]");
1663                 else if (*t == NE)
1664                         printf("[NE]");
1665                 else if (*t == SHR)
1666                         printf("[SHR]");
1667                 else if (*t == SHL)
1668                         printf("[SHL]");
1669                 else if (*t == UNMINUS)
1670                         printf("[UNMINUS]");
1671                 else if (*t == DOTB)
1672                         printf("[DOTB]");
1673                 else if (*t == DOTW)
1674                         printf("[DOTW]");
1675                 else if (*t == DOTL)
1676                         printf("[DOTL]");
1677                 else if (*t == DOTI)
1678                         printf("[DOTI]");
1679                 else if (*t == ENDEXPR)
1680                         printf("[ENDEXPR]");
1681                 else if (*t == CR_ABSCOUNT)
1682                         printf("[CR_ABSCOUNT]");
1683                 else if (*t == CR_DEFINED)
1684                         printf("[CR_DEFINED]");
1685                 else if (*t == CR_REFERENCED)
1686                         printf("[CR_REFERENCED]");
1687                 else if (*t == CR_STREQ)
1688                         printf("[CR_STREQ]");
1689                 else if (*t == CR_MACDEF)
1690                         printf("[CR_MACDEF]");
1691                 else if (*t == CR_TIME)
1692                         printf("[CR_TIME]");
1693                 else if (*t == CR_DATE)
1694                         printf("[CR_DATE]");
1695                 else if (*t >= 0x20 && *t <= 0x2F)
1696                         printf("[%c]", (char)*t);
1697                 else if (*t >= 0x3A && *t <= 0x3F)
1698                         printf("[%c]", (char)*t);
1699                 else if (*t >= 0x80 && *t <= 0x87)
1700                         printf("[D%u]", ((uint32_t)*t) - 0x80);
1701                 else if (*t >= 0x88 && *t <= 0x8F)
1702                         printf("[A%u]", ((uint32_t)*t) - 0x88);
1703                 else
1704                         printf("[%X:%c]", (uint32_t)*t, (char)*t);
1705         }
1706
1707         printf("[EOL]\n");
1708 }
1709