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