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