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