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