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