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