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