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