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