]> Shamusworld >> Repos - rmac/blob - token.c
Tighten up ea parsing for 020+ ea modes: PC relative 020+ modes are not allowed in...
[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-2020 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 // 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                                                                 d = symbolString[*tk++];
535 DEBUG { printf("ExM: SYMBOL=\"%s\"", d); }
536                                                                 break;
537                                                         case STRING:
538                                                                 d = symbolString[*tk++];
539
540                                                                 if (dst >= edst)
541                                                                         goto overflow;
542
543                                                                 *dst++ = '"';
544
545                                                                 while (*d != EOS)
546                                                                 {
547                                                                         if (dst >= edst)
548                                                                                 goto overflow;
549                                                                         else
550                                                                                 *dst++ = *d++;
551                                                                 }
552
553                                                                 if (dst >= edst)
554                                                                         goto overflow;
555
556                                                                 *dst++ = '"';
557                                                                 continue;
558                                                                 break;
559 // Shamus: Changing the format specifier from %lx to %ux caused the assembler
560 //         to choke on legitimate code... Need to investigate this further
561 //         before changing anything else here!
562                                                         case CONST:
563 //                                                              sprintf(numbuf, "$%lx", (uint64_t)*tk++);
564                                                                 sprintf(numbuf, "$%" PRIX64, (uint64_t)*tk++);
565                                                                 tk++;
566                                                                 d = numbuf;
567                                                                 break;
568                                                         case DEQUALS:
569                                                                 d = "==";
570                                                                 break;
571                                                         case SET:
572                                                                 d = "set";
573                                                                 break;
574                                                         case COLON:
575                                                                 d = ":";
576                                                                 break;
577                                                         case DCOLON:
578                                                                 d = "::";
579                                                                 break;
580                                                         case GE:
581                                                                 d = ">=";
582                                                                 break;
583                                                         case LE:
584                                                                 d = "<=";
585                                                                 break;
586                                                         case NE:
587                                                                 d = "<>";
588                                                                 break;
589                                                         case SHR:
590                                                                 d = ">>";
591                                                                 break;
592                                                         case SHL:
593                                                                 d = "<<";
594                                                                 break;
595                                                         case DOTB:
596                                                                 d = ".b";
597                                                                 break;
598                                                         case DOTW:
599                                                                 d = ".w";
600                                                                 break;
601                                                         case DOTL:
602                                                                 d = ".l";
603                                                                 break;
604                                                         case CR_ABSCOUNT:
605                                                                 d = "^^abscount";
606                                                                 break;
607                                                         case CR_FILESIZE:
608                                                                 d = "^^filesize";
609                                                                 break;
610                                                         case CR_DATE:
611                                                                 d = "^^date";
612                                                                 break;
613                                                         case CR_TIME:
614                                                                 d = "^^time";
615                                                                 break;
616                                                         case CR_DEFINED:
617                                                                 d = "^^defined ";
618                                                                 break;
619                                                         case CR_REFERENCED:
620                                                                 d = "^^referenced ";
621                                                                 break;
622                                                         case CR_STREQ:
623                                                                 d = "^^streq ";
624                                                                 break;
625                                                         case CR_MACDEF:
626                                                                 d = "^^macdef ";
627                                                                 break;
628                                                         default:
629                                                                 if (dst >= edst)
630                                                                         goto overflow;
631
632                                                                 *dst++ = (char)*(tk - 1);
633                                                                 break;
634                                                         }
635                                                 }
636
637                                                 // If 'd' != NULL, copy string to destination
638                                                 if (d != NULL)
639                                                 {
640 strcopy:
641                                                         DEBUG printf("d='%s'\n", d);
642
643                                                         while (*d != EOS)
644                                                         {
645                                                                 if (dst >= edst)
646                                                                         goto overflow;
647                                                                 else
648                                                                         *dst++ = *d++;
649                                                         }
650                                                 }
651                                         }
652                                 }
653                         }
654                 }
655         }
656
657 skipcomments:
658
659         *dst = EOS;
660         DEBUG { printf("ExM: dst=\"%s\"\n", dest); }
661         return OK;
662
663 overflow:
664         *dst = EOS;
665         DEBUG { printf("*** OVERFLOW LINE ***\n%s\n", dest); }
666         return fatal("line too long as a result of macro expansion");
667 }
668
669
670 //
671 // Get next line of text from a macro
672 //
673 char * GetNextMacroLine(void)
674 {
675         IMACRO * imacro = cur_inobj->inobj.imacro;
676 //      LONG * strp = imacro->im_nextln;
677         LLIST * strp = imacro->im_nextln;
678
679         if (strp == NULL)                                               // End-of-macro
680                 return NULL;
681
682         imacro->im_nextln = strp->next;
683 //      ExpandMacro((char *)(strp + 1), imacro->im_lnbuf, LNSIZ);
684         ExpandMacro(strp->line, imacro->im_lnbuf, LNSIZ);
685
686         return imacro->im_lnbuf;
687 }
688
689
690 //
691 // Get next line of text from a repeat block
692 //
693 char * GetNextRepeatLine(void)
694 {
695         IREPT * irept = cur_inobj->inobj.irept;
696 //      LONG * strp = irept->ir_nextln;                 // initial null
697
698         // Do repeat at end of .rept block's string list
699 //      if (strp == NULL)
700         if (irept->ir_nextln == NULL)
701         {
702                 DEBUG { printf("back-to-top-of-repeat-block count=%d\n", (int)irept->ir_count); }
703                 irept->ir_nextln = irept->ir_firstln;   // copy first line
704
705                 if (irept->ir_count-- == 0)
706                 {
707                         DEBUG { printf("end-repeat-block\n"); }
708                         return NULL;
709                 }
710
711 //              strp = irept->ir_nextln;
712         }
713         // Mark the current macro line in the irept object
714         // This is probably overkill - a global variable
715         // would suffice here (it only gets used during
716         // error reporting anyway)
717         irept->lineno = irept->ir_nextln->lineno;
718
719 //      strcpy(irbuf, (char *)(irept->ir_nextln + 1));
720         strcpy(irbuf, irept->ir_nextln->line);
721         DEBUG { printf("repeat line='%s'\n", irbuf); }
722 //      irept->ir_nextln = (LONG *)*strp;
723         irept->ir_nextln = irept->ir_nextln->next;
724
725         return irbuf;
726 }
727
728
729 //
730 // Include a source file used at the root, and for ".include" files
731 //
732 int include(int handle, char * fname)
733 {
734         // Debug mode
735         DEBUG { printf("[include: %s, cfileno=%u]\n", fname, cfileno); }
736
737         // Alloc and initialize include-descriptors
738         INOBJ * inobj = a_inobj(SRC_IFILE);
739         IFILE * ifile = inobj->inobj.ifile;
740
741         ifile->ifhandle = handle;                       // Setup file handle
742         ifile->ifind = ifile->ifcnt = 0;        // Setup buffer indices
743         ifile->ifoldlineno = curlineno;         // Save old line number
744         ifile->ifoldfname = curfname;           // Save old filename
745         ifile->ifno = cfileno;                          // Save old file number
746
747         // NB: This *must* be preincrement, we're adding one to the filecount here!
748         cfileno = ++filecount;                          // Compute NEW file number
749         curfname = strdup(fname);                       // Set current filename (alloc storage)
750         curlineno = 0;                                          // Start on line zero
751
752         // Add another file to the file-record
753         FILEREC * fr = (FILEREC *)malloc(sizeof(FILEREC));
754         fr->frec_next = NULL;
755         fr->frec_name = curfname;
756
757         if (last_fr == NULL)
758                 filerec = fr;                                   // Add first filerec
759         else
760                 last_fr->frec_next = fr;                // Append to list of filerecs
761
762         last_fr = fr;
763         DEBUG { printf("[include: curfname: %s, cfileno=%u]\n", curfname, cfileno); }
764
765         return OK;
766 }
767
768
769 //
770 // Pop the current input level
771 //
772 int fpop(void)
773 {
774         INOBJ * inobj = cur_inobj;
775
776         if (inobj == NULL)
777                 return 0;
778
779         // Pop IFENT levels until we reach the conditional assembly context we
780         // were at when the input object was entered.
781         int numUnmatched = 0;
782
783         while (ifent != inobj->in_ifent)
784         {
785                 if (d_endif() != 0)     // Something bad happened during endif parsing?
786                         return -1;              // If yes, bail instead of getting stuck in a loop
787
788                 numUnmatched++;
789         }
790
791         // Give a warning to the user that we had to wipe their bum for them
792         if (numUnmatched > 0)
793                 warn("missing %d .endif(s)", numUnmatched);
794
795         tok = inobj->in_otok;   // Restore tok and etok
796         etok = inobj->in_etok;
797
798         switch (inobj->in_type)
799         {
800         case SRC_IFILE:                 // Pop and release an IFILE
801         {
802                 DEBUG { printf("[Leaving: %s]\n", curfname); }
803
804                 IFILE * ifile = inobj->inobj.ifile;
805                 ifile->if_link = f_ifile;
806                 f_ifile = ifile;
807                 close(ifile->ifhandle);                 // Close source file
808 DEBUG { printf("[fpop (pre):  curfname=%s]\n", curfname); }
809                 curfname = ifile->ifoldfname;   // Set current filename
810 DEBUG { printf("[fpop (post): curfname=%s]\n", curfname); }
811 DEBUG { printf("[fpop: (pre)  cfileno=%d ifile->ifno=%d]\n", (int)cfileno, (int)ifile->ifno); }
812                 curlineno = ifile->ifoldlineno; // Set current line#
813                 DEBUG { printf("cfileno=%d ifile->ifno=%d\n", (int)cfileno, (int)ifile->ifno); }
814                 cfileno = ifile->ifno;                  // Restore current file number
815 DEBUG { printf("[fpop: (post) cfileno=%d ifile->ifno=%d]\n", (int)cfileno, (int)ifile->ifno); }
816                 break;
817         }
818
819         case SRC_IMACRO:                                        // Pop and release an IMACRO
820         {
821                 IMACRO * imacro = inobj->inobj.imacro;
822                 imacro->im_link = f_imacro;
823                 f_imacro = imacro;
824                 break;
825         }
826
827         case SRC_IREPT:                                         // Pop and release an IREPT
828         {
829                 DEBUG { printf("dealloc IREPT\n"); }
830                 LLIST * p = inobj->inobj.irept->ir_firstln;
831
832                 // Deallocate repeat lines
833                 while (p != NULL)
834                 {
835                         free(p->line);
836                         p = p->next;
837                 }
838
839                 break;
840         }
841         }
842
843         cur_inobj = inobj->in_link;
844         inobj->in_link = f_inobj;
845         f_inobj = inobj;
846
847         return 0;
848 }
849
850
851 //
852 // Get line from file into buf, return NULL on EOF or ptr to the start of a
853 // null-term line
854 //
855 char * GetNextLine(void)
856 {
857         int i, j;
858         char * p, * d;
859         int readamt = -1;                                               // 0 if last read() yeilded 0 bytes
860         IFILE * fl = cur_inobj->inobj.ifile;
861
862         for(;;)
863         {
864                 // Scan for next end-of-line; handle stupid text formats by treating
865                 // \r\n the same as \n. (lone '\r' at end of buffer means we have to
866                 // check for '\n').
867                 d = &fl->ifbuf[fl->ifind];
868
869                 for(p=d, i=0, j=fl->ifcnt; i<j; i++, p++)
870                 {
871                         if (*p == '\r' || *p == '\n')
872                         {
873                                 i++;
874
875                                 if (*p == '\r')
876                                 {
877                                         if (i >= j)
878                                                 break;  // Need to read more, then look for '\n' to eat
879                                         else if (p[1] == '\n')
880                                                 i++;
881                                 }
882
883                                 // Cover up the newline with end-of-string sentinel
884                                 *p = '\0';
885
886                                 fl->ifind += i;
887                                 fl->ifcnt -= i;
888                                 return d;
889                         }
890                 }
891
892                 // Handle hanging lines by ignoring them (Input file is exhausted, no
893                 // \r or \n on last line)
894                 // Shamus: This is retarded. Never ignore any input!
895                 if (!readamt && fl->ifcnt)
896                 {
897 #if 0
898                         fl->ifcnt = 0;
899                         *p = '\0';
900                         return NULL;
901 #else
902                         // Really should check to see if we're at the end of the buffer!
903                         // :-P
904                         fl->ifbuf[fl->ifind + fl->ifcnt] = '\0';
905                         fl->ifcnt = 0;
906                         return &fl->ifbuf[fl->ifind];
907 #endif
908                 }
909
910                 // Truncate and return absurdly long lines.
911                 if (fl->ifcnt >= QUANTUM)
912                 {
913                         fl->ifbuf[fl->ifind + fl->ifcnt - 1] = '\0';
914                         fl->ifcnt = 0;
915                         return &fl->ifbuf[fl->ifind];
916                 }
917
918                 // Relocate what's left of a line to the beginning of the buffer, and
919                 // read some more of the file in; return NULL if the buffer's empty and
920                 // on EOF.
921                 if (fl->ifind != 0)
922                 {
923                         p = &fl->ifbuf[fl->ifind];
924                         d = &fl->ifbuf[fl->ifcnt & 1];
925
926                         for(i=0; i<fl->ifcnt; i++)
927                                 *d++ = *p++;
928
929                         fl->ifind = fl->ifcnt & 1;
930                 }
931
932                 readamt = read(fl->ifhandle, &fl->ifbuf[fl->ifind + fl->ifcnt], QUANTUM);
933
934                 if (readamt < 0)
935                         return NULL;
936
937                 if ((fl->ifcnt += readamt) == 0)
938                         return NULL;
939         }
940 }
941
942
943 //
944 // Tokenize a line
945 //
946 int TokenizeLine(void)
947 {
948         uint8_t * ln = NULL;            // Ptr to current position in line
949         uint8_t * p;                            // Random character ptr
950         PTR tk;                                         // Token-deposit ptr
951         int state = 0;                          // State for keyword detector
952         int j = 0;                                      // Var for keyword detector
953         uint8_t c;                                      // Random char
954         uint64_t v;                                     // Random value
955         uint32_t cursize = 0;           // Current line's size (.b, .w, .l, .s, .q, .d)
956         uint8_t * nullspot = NULL;      // Spot to clobber for SYMBOL termination
957         int stuffnull;                          // 1:terminate SYMBOL '\0' at *nullspot
958         uint8_t c1;
959         int stringNum = 0;                      // Pointer to string locations in tokenized line
960
961 retry:
962
963         if (cur_inobj == NULL)          // Return EOF if input stack is empty
964                 return TKEOF;
965
966         // Get another line of input from the current input source: a file, a
967         // macro, or a repeat-block
968         switch (cur_inobj->in_type)
969         {
970         // Include-file:
971         // o  handle EOF;
972         // o  bump source line number;
973         // o  tag the listing-line with a space;
974         // o  kludge lines generated by Alcyon C.
975         case SRC_IFILE:
976                 if ((ln = GetNextLine()) == NULL)
977                 {
978 DEBUG { printf("TokenizeLine: Calling fpop() from SRC_IFILE...\n"); }
979                         if (fpop() == 0)        // Pop input level
980                                 goto retry;             // Try for more lines
981                         else
982                         {
983                                 ifent->if_prev = (IFENT *)-1;   //Signal Assemble() that we have reached EOF with unbalanced if/endifs
984                                 return TKEOF;
985                         }
986                 }
987
988                 curlineno++;                    // Bump line number
989                 lntag = SPACE;
990
991                 if (as68_flag)
992                 {
993                         // AS68 compatibility, throw away all lines starting with
994                         // back-quotes, tildes, or '*'
995                         // On other lines, turn the first '*' into a semi-colon.
996                         if (*ln == '`' || *ln == '~' || *ln == '*')
997                                 *ln = ';';
998                         else
999                         {
1000                                 for(p=ln; *p!=EOS; p++)
1001                                 {
1002                                         if (*p == '*')
1003                                         {
1004                                                 *p = ';';
1005                                                 break;
1006                                         }
1007                                 }
1008                         }
1009                 }
1010
1011                 break;
1012
1013         // Macro-block:
1014         // o  Handle end-of-macro;
1015         // o  tag the listing-line with an at (@) sign.
1016         case SRC_IMACRO:
1017                 if ((ln = GetNextMacroLine()) == NULL)
1018                 {
1019                         if (ExitMacro() == 0)   // Exit macro (pop args, do fpop(), etc)
1020                                 goto retry;                     // Try for more lines...
1021                         else
1022                                 return TKEOF;           // Oops, we got a non zero return code, signal EOF
1023                 }
1024
1025                 lntag = '@';
1026                 break;
1027
1028         // Repeat-block:
1029         // o  Handle end-of-repeat-block;
1030         // o  tag the listing-line with a pound (#) sign.
1031         case SRC_IREPT:
1032                 if ((ln = GetNextRepeatLine()) == NULL)
1033                 {
1034                         DEBUG { printf("TokenizeLine: Calling fpop() from SRC_IREPT...\n"); }
1035                         fpop();
1036                         goto retry;
1037                 }
1038
1039                 lntag = '#';
1040                 break;
1041         }
1042
1043         // Save text of the line. We only do this during listings and within
1044         // macro-type blocks, since it is expensive to unconditionally copy every
1045         // line.
1046         if (lnsave)
1047         {
1048                 // Sanity check
1049                 if (strlen(ln) > LNSIZ)
1050                         return error("line too long (%d, max %d)", strlen(ln), LNSIZ);
1051
1052                 strcpy(lnbuf, ln);
1053         }
1054
1055         // General housekeeping
1056         tok = tokeol;                   // Set "tok" to EOL in case of error
1057         tk.u32 = etok;                  // Reset token ptr
1058         stuffnull = 0;                  // Don't stuff nulls
1059         totlines++;                             // Bump total #lines assembled
1060
1061         // See if the entire line is a comment. This is a win if the programmer
1062         // puts in lots of comments
1063         if (*ln == '*' || *ln == ';' || ((*ln == '/') && (*(ln + 1) == '/')))
1064                 goto goteol;
1065
1066         // And here we have a very ugly hack for signalling a single line 'turn off
1067         // optimization'. There's really no nice way to do this, so hack it is!
1068         optimizeOff = 0;                // Default is to take optimizations as they come
1069
1070         if (*ln == '!')
1071         {
1072                 optimizeOff = 1;        // Signal that we don't want to optimize this line
1073                 ln++;                           // & skip over the darned thing
1074         }
1075
1076         // Main tokenization loop;
1077         //  o  skip whitespace;
1078         //  o  handle end-of-line;
1079         //  o  handle symbols;
1080         //  o  handle single-character tokens (operators, etc.);
1081         //  o  handle multiple-character tokens (constants, strings, etc.).
1082         for(; *ln!=EOS;)
1083         {
1084                 // Check to see if there's enough space in the token buffer
1085                 if (tk.cp >= ((uint8_t *)(&tokbuf[TOKBUFSIZE])) - 20)
1086                 {
1087                         return error("token buffer overrun");
1088                 }
1089
1090                 // Skip whitespace, handle EOL
1091                 while (chrtab[*ln] & WHITE)
1092                         ln++;
1093
1094                 // Handle EOL, comment with ';'
1095                 if (*ln == EOS || *ln == ';'|| ((*ln == '/') && (*(ln + 1) == '/')))
1096                         break;
1097
1098                 // Handle start of symbol. Symbols are null-terminated in place. The
1099                 // termination is always one symbol behind, since there may be no place
1100                 // for a null in the case that an operator immediately follows the name.
1101                 c = chrtab[*ln];
1102
1103                 if (c & STSYM)
1104                 {
1105                         if (stuffnull)                  // Terminate old symbol from previous pass
1106                                 *nullspot = EOS;
1107
1108                         v = 0;                                  // Assume no DOT attrib follows symbol
1109                         stuffnull = 1;
1110
1111                         // In some cases, we need to check for a DOTx at the *beginning*
1112                         // of a symbol, as the "start" of the line we're currently looking
1113                         // at could be somewhere in the middle of that line!
1114                         if (*ln == '.')
1115                         {
1116                                 // Make sure that it's *only* a .[bwsl] following, and not the
1117                                 // start of a local symbol:
1118                                 if ((chrtab[*(ln + 1)] & DOT)
1119                                         && (dotxtab[*(ln + 1)] != 0)
1120                                         && !(chrtab[*(ln + 2)] & CTSYM))
1121                                 {
1122                                         // We found a legitimate DOTx construct, so add it to the
1123                                         // token stream:
1124                                         ln++;
1125                                         stuffnull = 0;
1126                                         *tk.u32++ = (TOKEN)dotxtab[*ln++];
1127                                         continue;
1128                                 }
1129                         }
1130
1131                         p = nullspot = ln++;    // Nullspot -> start of this symbol
1132
1133                         // Find end of symbol (and compute its length)
1134                         for(j=1; (int)chrtab[*ln]&CTSYM; j++)
1135                                 ln++;
1136
1137                         // Handle "DOT" special forms (like ".b") that follow a normal
1138                         // symbol or keyword:
1139                         if (*ln == '.')
1140                         {
1141                                 *ln++ = EOS;            // Terminate symbol
1142                                 stuffnull = 0;          // And never try it again
1143
1144                                 // Character following the '.' must have a DOT attribute, and
1145                                 // the chararacter after THAT one must not have a start-symbol
1146                                 // attribute (to prevent symbols that look like, for example,
1147                                 // "zingo.barf", which might be a good idea anyway....)
1148                                 if (((chrtab[*ln] & DOT) == 0) || (dotxtab[*ln] == 0))
1149                                         return error("[bwsl] must follow '.' in symbol");
1150
1151                                 v = (uint32_t)dotxtab[*ln++];
1152                                 cursize = (uint32_t)v;
1153
1154                                 if (chrtab[*ln] & CTSYM)
1155                                         return error("misuse of '.'; not allowed in symbols");
1156                         }
1157
1158                         // If the symbol is small, check to see if it's really the name of
1159                         // a register.
1160                         if (j <= KWSIZE)
1161                         {
1162                                 for(state=0; state>=0;)
1163                                 {
1164                                         j = (int)tolowertab[*p++];
1165                                         j += kwbase[state];
1166
1167                                         if (kwcheck[j] != state)
1168                                         {
1169                                                 j = -1;
1170                                                 break;
1171                                         }
1172
1173                                         if (*p == EOS || p == ln)
1174                                         {
1175                                                 j = kwaccept[j];
1176                                                 break;
1177                                         }
1178
1179                                         state = kwtab[j];
1180                                 }
1181                         }
1182                         else
1183                         {
1184                                 j = -1;
1185                         }
1186
1187                         // Make j = -1 if user tries to use a RISC register while in 68K mode
1188                         if (!(rgpu || rdsp || dsp56001) && ((TOKEN)j >= KW_R0 && (TOKEN)j <= KW_R31))
1189                         {
1190                                 j = -1;
1191                         }
1192
1193                         // Make j = -1 if time, date etc with no preceeding ^^
1194                         // defined, referenced, streq, macdef, date and time
1195                         switch ((TOKEN)j)
1196                         {
1197                         case 112:   // defined
1198                         case 113:   // referenced
1199                         case 118:   // streq
1200                         case 119:   // macdef
1201                         case 120:   // time
1202                         case 121:   // date
1203                                 j = -1;
1204                         }
1205
1206                         // If not tokenized keyword OR token was not found
1207                         if ((j < 0) || (state < 0))
1208                         {
1209                                 *tk.u32++ = SYMBOL;
1210                                 string[stringNum] = nullspot;
1211                                 *tk.u32++ = stringNum;
1212                                 stringNum++;
1213                         }
1214                         else
1215                         {
1216                                 *tk.u32++ = (TOKEN)j;
1217                                 stuffnull = 0;
1218                         }
1219
1220                         if (v)                  // Record attribute token (if any)
1221                                 *tk.u32++ = (TOKEN)v;
1222
1223                         if (stuffnull)  // Arrange for string termination on next pass
1224                                 nullspot = ln;
1225
1226                         continue;
1227                 }
1228
1229                 // Handle identity tokens
1230                 if (c & SELF)
1231                 {
1232                         *tk.u32++ = *ln++;
1233                         continue;
1234                 }
1235
1236                 // Handle multiple-character tokens
1237                 if (c & MULTX)
1238                 {
1239                         switch (*ln++)
1240                         {
1241                         case '!':               // ! or !=
1242                                 if (*ln == '=')
1243                                 {
1244                                         *tk.u32++ = NE;
1245                                         ln++;
1246                                 }
1247                                 else
1248                                         *tk.u32++ = '!';
1249
1250                                 continue;
1251                         case '\'':              // 'string'
1252                                 if (m6502)
1253                                 {
1254                                         // Hardcoded for now, maybe this will change in the future
1255                                         *tk.u32++ = STRINGA8;
1256                                         goto dostring;
1257                                 }
1258                                 // Fall through
1259                         case '\"':              // "string"
1260                                 *tk.u32++ = STRING;
1261 dostring:
1262                                 c1 = ln[-1];
1263                                 string[stringNum] = ln;
1264                                 *tk.u32++ = stringNum;
1265                                 stringNum++;
1266
1267                                 for(p=ln; *ln!=EOS && *ln!=c1;)
1268                                 {
1269                                         c = *ln++;
1270
1271                                         if (c == '\\')
1272                                         {
1273                                                 switch (*ln++)
1274                                                 {
1275                                                 case EOS:
1276                                                         return(error("unterminated string"));
1277                                                 case 'e':
1278                                                         c = '\033';
1279                                                         break;
1280                                                 case 'n':
1281                                                         c = '\n';
1282                                                         break;
1283                                                 case 'b':
1284                                                         c = '\b';
1285                                                         break;
1286                                                 case 't':
1287                                                         c = '\t';
1288                                                         break;
1289                                                 case 'r':
1290                                                         c = '\r';
1291                                                         break;
1292                                                 case 'f':
1293                                                         c = '\f';
1294                                                         break;
1295                                                 case '\"':
1296                                                         c = '\"';
1297                                                         break;
1298                                                 case '\'':
1299                                                         c = '\'';
1300                                                         break;
1301                                                 case '\\':
1302                                                         c = '\\';
1303                                                         break;
1304                                                 case '{':
1305                                                         // If we're evaluating a macro
1306                                                         // this is valid because it's
1307                                                         // a parameter expansion
1308                                                 case '!':
1309                                                         // If we're evaluating a macro
1310                                                         // this is valid and expands to
1311                                                         // "dot-size"
1312                                                         break;
1313                                                 default:
1314                                                         warn("bad backslash code in string");
1315                                                         ln--;
1316                                                         break;
1317                                                 }
1318                                         }
1319
1320                                         *p++ = c;
1321                                 }
1322
1323                                 if (*ln++ != c1)
1324                                         return error("unterminated string");
1325
1326                                 *p++ = EOS;
1327                                 continue;
1328                         case '$':               // $, hex constant
1329                                 if (chrtab[*ln] & HDIGIT)
1330                                 {
1331                                         v = 0;
1332
1333                                         // Parse the hex value
1334                                         while (hextab[*ln] >= 0)
1335                                                 v = (v << 4) + (int)hextab[*ln++];
1336
1337                                         *tk.u32++ = CONST;
1338                                         *tk.u64++ = v;
1339
1340                                         if (*ln == '.')
1341                                         {
1342                                                 if ((*(ln + 1) == 'w') || (*(ln + 1) == 'W'))
1343                                                 {
1344                                                         *tk.u32++ = DOTW;
1345                                                         ln += 2;
1346                                                 }
1347                                                 else if ((*(ln + 1) == 'l') || (*(ln + 1) == 'L'))
1348                                                 {
1349                                                         *tk.u32++ = DOTL;
1350                                                         ln += 2;
1351                                                 }
1352                                         }
1353                                 }
1354                                 else
1355                                         *tk.u32++ = '$';
1356
1357                                 continue;
1358                         case '<':               // < or << or <> or <=
1359                                 switch (*ln)
1360                                 {
1361                                 case '<':
1362                                         *tk.u32++ = SHL;
1363                                         ln++;
1364                                         continue;
1365                                 case '>':
1366                                         *tk.u32++ = NE;
1367                                         ln++;
1368                                         continue;
1369                                 case '=':
1370                                         *tk.u32++ = LE;
1371                                         ln++;
1372                                         continue;
1373                                 default:
1374                                         *tk.u32++ = '<';
1375                                         continue;
1376                                 }
1377                         case ':':               // : or ::
1378                                 if (*ln == ':')
1379                                 {
1380                                         *tk.u32++ = DCOLON;
1381                                         ln++;
1382                                 }
1383                                 else
1384                                         *tk.u32++ = ':';
1385
1386                                 continue;
1387                         case '=':               // = or ==
1388                                 if (*ln == '=')
1389                                 {
1390                                         *tk.u32++ = DEQUALS;
1391                                         ln++;
1392                                 }
1393                                 else
1394                                         *tk.u32++ = '=';
1395
1396                                 continue;
1397                         case '>':               // > or >> or >=
1398                                 switch (*ln)
1399                                 {
1400                                 case '>':
1401                                         *tk.u32++ = SHR;
1402                                         ln++;
1403                                         continue;
1404                                 case '=':
1405                                         *tk.u32++ = GE;
1406                                         ln++;
1407                                         continue;
1408                                 default:
1409                                         *tk.u32++ = '>';
1410                                         continue;
1411                                 }
1412                         case '%':               // % or binary constant
1413                                 if (*ln < '0' || *ln > '1')
1414                                 {
1415                                         *tk.u32++ = '%';
1416                                         continue;
1417                                 }
1418
1419                                 v = 0;
1420
1421                                 while (*ln >= '0' && *ln <= '1')
1422                                         v = (v << 1) + *ln++ - '0';
1423
1424                                 if (*ln == '.')
1425                                 {
1426                                         if ((*(ln + 1) == 'b') || (*(ln + 1) == 'B'))
1427                                         {
1428                                                 v &= 0x000000FF;
1429                                                 ln += 2;
1430                                         }
1431
1432                                         if ((*(ln + 1) == 'w') || (*(ln + 1) == 'W'))
1433                                         {
1434                                                 v &= 0x0000FFFF;
1435                                                 ln += 2;
1436                                         }
1437
1438                                         if ((*(ln + 1) == 'l') || (*(ln + 1) == 'L'))
1439                                         {
1440                                                 v &= 0xFFFFFFFF;
1441                                                 ln += 2;
1442                                         }
1443                                 }
1444
1445                                 *tk.u32++ = CONST;
1446                                 *tk.u64++ = v;
1447                                 continue;
1448                         case '@':               // @ or octal constant
1449                                 if (*ln < '0' || *ln > '7')
1450                                 {
1451                                         *tk.u32++ = '@';
1452                                         continue;
1453                                 }
1454
1455                                 v = 0;
1456
1457                                 while (*ln >= '0' && *ln <= '7')
1458                                         v = (v << 3) + *ln++ - '0';
1459
1460                                 if (*ln == '.')
1461                                 {
1462                                         if ((*(ln + 1) == 'b') || (*(ln + 1) == 'B'))
1463                                         {
1464                                                 v &= 0x000000FF;
1465                                                 ln += 2;
1466                                         }
1467
1468                                         if ((*(ln + 1) == 'w') || (*(ln + 1) == 'W'))
1469                                         {
1470                                                 v &= 0x0000FFFF;
1471                                                 ln += 2;
1472                                         }
1473
1474                                         if ((*(ln + 1) == 'l') || (*(ln + 1) == 'L'))
1475                                         {
1476                                                 v &= 0xFFFFFFFF;
1477                                                 ln += 2;
1478                                         }
1479                                 }
1480
1481                                 *tk.u32++ = CONST;
1482                                 *tk.u64++ = v;
1483                                 continue;
1484                         case '^':               // ^ or ^^ <operator-name>
1485                                 if (*ln != '^')
1486                                 {
1487                                         *tk.u32++ = '^';
1488                                         continue;
1489                                 }
1490
1491                                 if (((int)chrtab[*++ln] & STSYM) == 0)
1492                                 {
1493                                         error("invalid symbol following ^^");
1494                                         continue;
1495                                 }
1496
1497                                 p = ln++;
1498
1499                                 while ((int)chrtab[*ln] & CTSYM)
1500                                         ++ln;
1501
1502                                 for(state=0; state>=0;)
1503                                 {
1504                                         // Get char, convert to lowercase
1505                                         j = *p++;
1506
1507                                         if (j >= 'A' && j <= 'Z')
1508                                                 j += 0x20;
1509
1510                                         j += kwbase[state];
1511
1512                                         if (kwcheck[j] != state)
1513                                         {
1514                                                 j = -1;
1515                                                 break;
1516                                         }
1517
1518                                         if (*p == EOS || p == ln)
1519                                         {
1520                                                 j = kwaccept[j];
1521                                                 break;
1522                                         }
1523
1524                                         state = kwtab[j];
1525                                 }
1526
1527                                 if (j < 0 || state < 0)
1528                                 {
1529                                         error("unknown symbol following ^^");
1530                                         continue;
1531                                 }
1532
1533                                 *tk.u32++ = (TOKEN)j;
1534                                 continue;
1535                         default:
1536                                 interror(2);    // Bad MULTX entry in chrtab
1537                                 continue;
1538                         }
1539                 }
1540
1541                 // Handle decimal constant
1542                 if (c & DIGIT)
1543                 {
1544                         uint8_t * numStart = ln;
1545                         v = 0;
1546
1547                         while ((int)chrtab[*ln] & DIGIT)
1548                                 v = (v * 10) + *ln++ - '0';
1549
1550                         // See if there's a .[bwl] after the constant & deal with it if so
1551                         if (*ln == '.')
1552                         {
1553                                 if ((*(ln + 1) == 'b') || (*(ln + 1) == 'B'))
1554                                 {
1555                                         v &= 0x000000FF;
1556                                         ln += 2;
1557                                         *tk.u32++ = CONST;
1558                                         *tk.u64++ = v;
1559                                         *tk.u32++ = DOTB;
1560                                 }
1561                                 else if ((*(ln + 1) == 'w') || (*(ln + 1) == 'W'))
1562                                 {
1563                                         v &= 0x0000FFFF;
1564                                         ln += 2;
1565                                         *tk.u32++ = CONST;
1566                                         *tk.u64++ = v;
1567                                         *tk.u32++ = DOTW;
1568                                 }
1569                                 else if ((*(ln + 1) == 'l') || (*(ln + 1) == 'L'))
1570                                 {
1571                                         v &= 0xFFFFFFFF;
1572                                         ln += 2;
1573                                         *tk.u32++ = CONST;
1574                                         *tk.u64++ = v;
1575                                         *tk.u32++ = DOTL;
1576                                 }
1577                                 else if ((int)chrtab[*(ln + 1)] & DIGIT)
1578                                 {
1579                                         // Hey, more digits after the dot, so we assume it's a
1580                                         // floating point number of some kind... numEnd will point
1581                                         // to the first non-float character after it's done
1582                                         char * numEnd;
1583                                         errno = 0;
1584                                         double f = strtod(numStart, &numEnd);
1585                                         ln = (uint8_t *)numEnd;
1586
1587                                         if (errno != 0)
1588                                                 return error("floating point parse error");
1589
1590                                         // N.B.: We use the C compiler's internal double
1591                                         //       representation for all internal float calcs and
1592                                         //       are reasonably sure that the size of said double
1593                                         //       is 8 bytes long (which we check for in fltpoint.c)
1594                                         *tk.u32++ = FCONST;
1595                                         *tk.dp = f;
1596                                         tk.u64++;
1597                                         continue;
1598                                 }
1599                         }
1600                         else
1601                         {
1602                                 *tk.u32++ = CONST;
1603                                 *tk.u64++ = v;
1604                         }
1605
1606 //printf("CONST: %i\n", v);
1607                         continue;
1608                 }
1609
1610                 // Handle illegal character
1611                 return error("illegal character $%02X found", *ln);
1612         }
1613
1614         // Terminate line of tokens and return "success."
1615
1616 goteol:
1617         tok = etok;                             // Set tok to beginning of line
1618
1619         if (stuffnull)                  // Terminate last SYMBOL
1620                 *nullspot = EOS;
1621
1622         *tk.u32++ = EOL;
1623
1624         return OK;
1625 }
1626
1627
1628 //
1629 // .GOTO <label>        goto directive
1630 //
1631 // The label is searched for starting from the first line of the current,
1632 // enclosing macro definition. If no enclosing macro exists, an error is
1633 // generated.
1634 //
1635 // A label is of the form:
1636 //
1637 // :<name><whitespace>
1638 //
1639 // The colon must appear in column 1.  The label is stripped prior to macro
1640 // expansion, and is NOT subject to macro expansion.  The whitespace may also
1641 // be EOL.
1642 //
1643 int d_goto(WORD unused)
1644 {
1645         // Setup for the search
1646         if (*tok != SYMBOL)
1647                 return error("missing label");
1648
1649         char * sym = string[tok[1]];
1650         tok += 2;
1651
1652         if (cur_inobj->in_type != SRC_IMACRO)
1653                 return error("goto not in macro");
1654
1655         IMACRO * imacro = cur_inobj->inobj.imacro;
1656         LLIST * defln = imacro->im_macro->lineList;
1657
1658         // Attempt to find the label, starting with the first line.
1659         for(; defln!=NULL; defln=defln->next)
1660         {
1661                 // Must start with a colon
1662                 if (defln->line[0] == ':')
1663                 {
1664                         // Compare names (sleazo string compare)
1665                         char * s1 = sym;
1666                         char * s2 = defln->line;
1667
1668                         // Either we will match the strings to EOS on both, or we will
1669                         // match EOS on string 1 to whitespace on string 2. Otherwise, we
1670                         // have no match.
1671                         while ((*s1 == *s2) || ((*s1 == EOS) && (chrtab[*s2] & WHITE)))
1672                         {
1673                                 // If we reached the end of string 1 (sym), we're done.
1674                                 // Note that we're also checking for the end of string 2 as
1675                                 // well, since we've established they're equal above.
1676                                 if (*s1 == EOS)
1677                                 {
1678                                         // Found the label, set new macro next-line and return.
1679                                         imacro->im_nextln = defln;
1680                                         return 0;
1681                                 }
1682
1683                                 s1++;
1684                                 s2++;
1685                         }
1686                 }
1687         }
1688
1689         return error("goto label not found");
1690 }
1691
1692
1693 void DumpToken(TOKEN t)
1694 {
1695         if (t == COLON)
1696                 printf("[COLON]");
1697         else if (t == CONST)
1698                 printf("[CONST]");
1699         else if (t == FCONST)
1700                 printf("[FCONST]");
1701         else if (t == ACONST)
1702                 printf("[ACONST]");
1703         else if (t == STRING)
1704                 printf("[STRING]");
1705         else if (t == SYMBOL)
1706                 printf("[SYMBOL]");
1707         else if (t == EOS)
1708                 printf("[EOS]");
1709         else if (t == TKEOF)
1710                 printf("[TKEOF]");
1711         else if (t == DEQUALS)
1712                 printf("[DEQUALS]");
1713         else if (t == SET)
1714                 printf("[SET]");
1715         else if (t == REG)
1716                 printf("[REG]");
1717         else if (t == DCOLON)
1718                 printf("[DCOLON]");
1719         else if (t == GE)
1720                 printf("[GE]");
1721         else if (t == LE)
1722                 printf("[LE]");
1723         else if (t == NE)
1724                 printf("[NE]");
1725         else if (t == SHR)
1726                 printf("[SHR]");
1727         else if (t == SHL)
1728                 printf("[SHL]");
1729         else if (t == UNMINUS)
1730                 printf("[UNMINUS]");
1731         else if (t == DOTB)
1732                 printf("[DOTB]");
1733         else if (t == DOTW)
1734                 printf("[DOTW]");
1735         else if (t == DOTL)
1736                 printf("[DOTL]");
1737         else if (t == DOTQ)
1738                 printf("[DOTQ]");
1739         else if (t == DOTS)
1740                 printf("[DOTS]");
1741         else if (t == DOTD)
1742                 printf("[DOTD]");
1743         else if (t == DOTI)
1744                 printf("[DOTI]");
1745         else if (t == ENDEXPR)
1746                 printf("[ENDEXPR]");
1747         else if (t == CR_ABSCOUNT)
1748                 printf("[CR_ABSCOUNT]");
1749         else if (t == CR_FILESIZE)
1750                 printf("[CR_FILESIZE]");
1751         else if (t == CR_DEFINED)
1752                 printf("[CR_DEFINED]");
1753         else if (t == CR_REFERENCED)
1754                 printf("[CR_REFERENCED]");
1755         else if (t == CR_STREQ)
1756                 printf("[CR_STREQ]");
1757         else if (t == CR_MACDEF)
1758                 printf("[CR_MACDEF]");
1759         else if (t == CR_TIME)
1760                 printf("[CR_TIME]");
1761         else if (t == CR_DATE)
1762                 printf("[CR_DATE]");
1763         else if (t >= 0x20 && t <= 0x2F)
1764                 printf("[%c]", (char)t);
1765         else if (t >= 0x3A && t <= 0x3F)
1766                 printf("[%c]", (char)t);
1767         else if (t >= 0x80 && t <= 0x87)
1768                 printf("[D%u]", ((uint32_t)t) - 0x80);
1769         else if (t >= 0x88 && t <= 0x8F)
1770                 printf("[A%u]", ((uint32_t)t) - 0x88);
1771         else
1772                 printf("[%X:%c]", (uint32_t)t, (char)t);
1773 }
1774
1775
1776 void DumpTokenBuffer(void)
1777 {
1778         printf("Tokens [%X]: ", sloc);
1779
1780         for(TOKEN * t=tokbuf; *t!=EOL; t++)
1781         {
1782                 if (*t == COLON)
1783                         printf("[COLON]");
1784                 else if (*t == CONST)
1785                 {
1786                         PTR tp;
1787                         tp.u32 = t + 1;
1788                         printf("[CONST: $%lX]", *tp.u64);
1789                         t += 2;
1790                 }
1791                 else if (*t == FCONST)
1792                 {
1793                         PTR tp;
1794                         tp.u32 = t + 1;
1795                         printf("[FCONST: $%lX]", *tp.u64);
1796                         t += 2;
1797                 }
1798                 else if (*t == ACONST)
1799                 {
1800                         printf("[ACONST: $%X, $%X]", (uint32_t)t[1], (uint32_t)t[2]);
1801                         t += 2;
1802                 }
1803                 else if (*t == STRING)
1804                 {
1805                         t++;
1806                         printf("[STRING:\"%s\"]", string[*t]);
1807                 }
1808                 else if (*t == SYMBOL)
1809                 {
1810                         t++;
1811                         printf("[SYMBOL:\"%s\"]", string[*t]);
1812                 }
1813                 else if (*t == EOS)
1814                         printf("[EOS]");
1815                 else if (*t == TKEOF)
1816                         printf("[TKEOF]");
1817                 else if (*t == DEQUALS)
1818                         printf("[DEQUALS]");
1819                 else if (*t == SET)
1820                         printf("[SET]");
1821                 else if (*t == REG)
1822                         printf("[REG]");
1823                 else if (*t == DCOLON)
1824                         printf("[DCOLON]");
1825                 else if (*t == GE)
1826                         printf("[GE]");
1827                 else if (*t == LE)
1828                         printf("[LE]");
1829                 else if (*t == NE)
1830                         printf("[NE]");
1831                 else if (*t == SHR)
1832                         printf("[SHR]");
1833                 else if (*t == SHL)
1834                         printf("[SHL]");
1835                 else if (*t == UNMINUS)
1836                         printf("[UNMINUS]");
1837                 else if (*t == DOTB)
1838                         printf("[DOTB]");
1839                 else if (*t == DOTW)
1840                         printf("[DOTW]");
1841                 else if (*t == DOTL)
1842                         printf("[DOTL]");
1843                 else if (*t == DOTQ)
1844                         printf("[DOTQ]");
1845                 else if (*t == DOTS)
1846                         printf("[DOTS]");
1847                 else if (*t == DOTD)
1848                         printf("[DOTD]");
1849                 else if (*t == DOTI)
1850                         printf("[DOTI]");
1851                 else if (*t == ENDEXPR)
1852                         printf("[ENDEXPR]");
1853                 else if (*t == CR_ABSCOUNT)
1854                         printf("[CR_ABSCOUNT]");
1855                 else if (*t == CR_FILESIZE)
1856                         printf("[CR_FILESIZE]");
1857                 else if (*t == CR_DEFINED)
1858                         printf("[CR_DEFINED]");
1859                 else if (*t == CR_REFERENCED)
1860                         printf("[CR_REFERENCED]");
1861                 else if (*t == CR_STREQ)
1862                         printf("[CR_STREQ]");
1863                 else if (*t == CR_MACDEF)
1864                         printf("[CR_MACDEF]");
1865                 else if (*t == CR_TIME)
1866                         printf("[CR_TIME]");
1867                 else if (*t == CR_DATE)
1868                         printf("[CR_DATE]");
1869                 else if (*t >= 0x20 && *t <= 0x2F)
1870                         printf("[%c]", (char)*t);
1871                 else if (*t >= 0x3A && *t <= 0x3F)
1872                         printf("[%c]", (char)*t);
1873                 else if (*t >= 0x80 && *t <= 0x87)
1874                         printf("[D%u]", ((uint32_t)*t) - 0x80);
1875                 else if (*t >= 0x88 && *t <= 0x8F)
1876                         printf("[A%u]", ((uint32_t)*t) - 0x88);
1877                 else
1878                         printf("[%X:%c]", (uint32_t)*t, (char)*t);
1879         }
1880
1881         printf("[EOL]\n");
1882 }
1883