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