]> Shamusworld >> Repos - rmac/blob - token.c
01c0c4c5d49f6f6bed4839553ff9e9d5537a2f41
[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 uint16_t curlineno;                     // Current line number (64K max currently)
24 int totlines;                           // Total # of lines
25 int mjump_align = 0;            // mjump alignment flag
26 char lntag;                                     // Line tag
27 char * curfname;                        // Current filename
28 char tolowertab[128];           // Uppercase ==> lowercase
29 int8_t hextab[128];                     // Table of hex values
30 char dotxtab[128];                      // Table for ".b", ".s", etc.
31 char irbuf[LNSIZ];                      // Text for .rept block line
32 char lnbuf[LNSIZ];                      // Text of current line
33 WORD filecount;                         // Unique file number counter
34 WORD cfileno;                           // Current file number
35 TOKEN * tok;                            // Ptr to current token
36 TOKEN * etok;                           // Ptr past last token in tokbuf[]
37 TOKEN tokeol[1] = {EOL};        // Bailout end-of-line token
38 char * string[TOKBUFSIZE*2];    // Token buffer string pointer storage
39
40 // File record, used to maintain a list of every include file ever visited
41 #define FILEREC struct _filerec
42 FILEREC
43 {
44    FILEREC * frec_next;
45    char * frec_name;
46 };
47
48 FILEREC * filerec;
49 FILEREC * last_fr;
50
51 INOBJ * cur_inobj;                                              // Ptr current input obj (IFILE/IMACRO)
52 static INOBJ * f_inobj;                                 // Ptr list of free INOBJs
53 static IFILE * f_ifile;                                 // Ptr list of free IFILEs
54 static IMACRO * f_imacro;                               // Ptr list of free IMACROs
55
56 static TOKEN tokbuf[TOKBUFSIZE];                // Token buffer (stack-like, all files)
57
58 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 the assembler
521 //         to choke on legitimate code... Need to investigate this further
522 //         before changing anything else here!
523                                                         case CONST:
524                                                                 sprintf(numbuf, "$%lx", (long unsigned int)*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         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
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                                         // Hardcoded for now, maybe this will change in the future
1181                                         *tk++ = STRINGA8;
1182                                         goto dostring;
1183                                 }
1184                                 // Fall through
1185                         case '\"':              // "string"
1186                                 *tk++ = STRING;
1187 dostring:
1188                                 c1 = ln[-1];
1189                                 string[stringNum] = ln;
1190                                 *tk++ = stringNum;
1191                                 stringNum++;
1192
1193                                 for(p=ln; *ln!=EOS && *ln!=c1;)
1194                                 {
1195                                         c = *ln++;
1196
1197                                         if (c == '\\')
1198                                         {
1199                                                 switch (*ln++)
1200                                                 {
1201                                                 case EOS:
1202                                                         return(error("unterminated string"));
1203                                                 case 'e':
1204                                                         c = '\033';
1205                                                         break;
1206                                                 case 'n':
1207                                                         c = '\n';
1208                                                         break;
1209                                                 case 'b':
1210                                                         c = '\b';
1211                                                         break;
1212                                                 case 't':
1213                                                         c = '\t';
1214                                                         break;
1215                                                 case 'r':
1216                                                         c = '\r';
1217                                                         break;
1218                                                 case 'f':
1219                                                         c = '\f';
1220                                                         break;
1221                                                 case '\"':
1222                                                         c = '\"';
1223                                                         break;
1224                                                 case '\'':
1225                                                         c = '\'';
1226                                                         break;
1227                                                 case '\\':
1228                                                         c = '\\';
1229                                                         break;
1230                                                 default:
1231                                                         warn("bad backslash code in string");
1232                                                         ln--;
1233                                                         break;
1234                                                 }
1235                                         }
1236
1237                                         *p++ = c;
1238                                 }
1239
1240                                 if (*ln++ != c1)
1241                                         return error("unterminated string");
1242
1243                                 *p++ = EOS;
1244                                 continue;
1245                         case '$':               // $, hex constant
1246                                 if (chrtab[*ln] & HDIGIT)
1247                                 {
1248                                         v = 0;
1249
1250                                         // Parse the hex value
1251                                         while (hextab[*ln] >= 0)
1252                                                 v = (v << 4) + (int)hextab[*ln++];
1253
1254                                         // ggn: Okay, some comments here are in order I think....
1255                                         // The original madmac sources didn't parse the size at
1256                                         // this point (i.e. .b/.w/.l). It was probably done at
1257                                         // another point, although it's unclear to me exactly
1258                                         // where. So why change this? My understanding (at least
1259                                         // from what SCPCD said on IRC) is that .w addressing
1260                                         // formats produce wrong code on jaguar (or doesn't execute
1261                                         // properly? something like that). So the code was changed
1262                                         // to mask off the upper bits depending on length (note: I
1263                                         // don't think .b is valid at all! I only know of .w/.l, so
1264                                         // this should probably be wiped). Then the code that
1265                                         // parses the constant and checks to see if it's between
1266                                         // $ffff0000 and $8000 never got triggered, so yay job
1267                                         // done! ...now say we want to assemble a st .prg. One of
1268                                         // the most widely spread optimisations is move.X expr.w,Y
1269                                         // (or vice versa, or both, anyway...) to access hardware
1270                                         // registers (which are mapped to $fxxxxx). This botchy
1271                                         // thing would create "hilarious" code while trying to
1272                                         // access hardware registers. So I made a condition to see
1273                                         // if st mode or jaguar is active and apply the both or
1274                                         // not. One last note: this is hardcoded to get optimised
1275                                         // for now on ST mode, i.e. it can't generate code like
1276                                         // move.w $00001234,d0 - it'll always get optimised to
1277                                         // move.w $1234.w,d0. It's probably ok, but maybe a warning
1278                                         // should be emitted? Or maybe finding a way to make it not
1279                                         // auto-optimise? I think it's ok for now...
1280                                         if (*ln == '.')
1281                                         {
1282                                                 if (obj_format == BSD)
1283                                                 {
1284                                                         if ((*(ln + 1) & 0xDF) == 'B')
1285                                                         {
1286                                                                 v &= 0x000000FF;
1287                                                                 ln += 2;
1288                                                         }
1289                                                         else if ((*(ln + 1) & 0xDF) == 'W')
1290                                                         {
1291                                                                 v &= 0x0000FFFF;
1292                                                                 ln += 2;
1293                                                         }
1294                                                         else if ((*(ln + 1) & 0xDF) == 'L')
1295                                                         {
1296                                                                 ln += 2;
1297                                                         }
1298                                                 }
1299                                         }
1300
1301                                         *tk++ = CONST;
1302                                         *tk++ = v;
1303
1304                                         if (obj_format == ALCYON)
1305                                         {
1306                                                 if (*ln == '.')
1307                                                 {
1308                                                         if ((*(ln + 1) == 'w') || (*(ln + 1) == 'W'))
1309                                                         {
1310                                                                 *tk++ = DOTW;
1311                                                                 ln += 2;
1312                                                         }
1313                                                         else if ((*(ln + 1) == 'l') || (*(ln + 1) == 'L'))
1314                                                         {
1315                                                                 *tk++ = DOTL;
1316                                                                 ln += 2;
1317                                                         }
1318                                                 }
1319                                         }
1320                                 }
1321                                 else
1322                                         *tk++ = '$';
1323
1324                                 continue;
1325                         case '<':               // < or << or <> or <=
1326                                 switch (*ln)
1327                                 {
1328                                 case '<':
1329                                         *tk++ = SHL;
1330                                         ++ln;
1331                                         continue;
1332                                 case '>':
1333                                         *tk++ = NE;
1334                                         ++ln;
1335                                         continue;
1336                                 case '=':
1337                                         *tk++ = LE;
1338                                         ++ln;
1339                                         continue;
1340                                 default:
1341                                         *tk++ = '<';
1342                                         continue;
1343                                 }
1344                         case ':':               // : or ::
1345                                 if (*ln == ':')
1346                                 {
1347                                         *tk++ = DCOLON;
1348                                         ++ln;
1349                                 }
1350                                 else
1351                                         *tk++ = ':';
1352
1353                                 continue;
1354                         case '=':               // = or ==
1355                                 if (*ln == '=')
1356                                 {
1357                                         *tk++ = DEQUALS;
1358                                         ++ln;
1359                                 }
1360                                 else
1361                                         *tk++ = '=';
1362
1363                                 continue;
1364                         case '>':               // > or >> or >=
1365                                 switch (*ln)
1366                                 {
1367                                 case '>':
1368                                         *tk++ = SHR;
1369                                         ln++;
1370                                         continue;
1371                                 case '=':
1372                                         *tk++ = GE;
1373                                         ln++;
1374                                         continue;
1375                                 default:
1376                                         *tk++ = '>';
1377                                         continue;
1378                                 }
1379                         case '%':               // % or binary constant
1380                                 if (*ln < '0' || *ln > '1')
1381                                 {
1382                                         *tk++ = '%';
1383                                         continue;
1384                                 }
1385
1386                                 v = 0;
1387
1388                                 while (*ln >= '0' && *ln <= '1')
1389                                         v = (v << 1) + *ln++ - '0';
1390
1391                                 if (*ln == '.')
1392                                 {
1393                                         if ((*(ln + 1) == 'b') || (*(ln + 1) == 'B'))
1394                                         {
1395                                                 v &= 0x000000FF;
1396                                                 ln += 2;
1397                                         }
1398
1399                                         if ((*(ln + 1) == 'w') || (*(ln + 1) == 'W'))
1400                                         {
1401                                                 v &= 0x0000FFFF;
1402                                                 ln += 2;
1403                                         }
1404
1405                                         if ((*(ln + 1) == 'l') || (*(ln + 1) == 'L'))
1406                                         {
1407                                                 ln += 2;
1408                                         }
1409                                 }
1410
1411                                 *tk++ = CONST;
1412                                 *tk++ = v;
1413                                 continue;
1414                         case '@':               // @ or octal constant
1415                                 if (*ln < '0' || *ln > '7')
1416                                 {
1417                                         *tk++ = '@';
1418                                         continue;
1419                                 }
1420
1421                                 v = 0;
1422
1423                                 while (*ln >= '0' && *ln <= '7')
1424                                         v = (v << 3) + *ln++ - '0';
1425
1426                                 if (*ln == '.')
1427                                 {
1428                                         if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1429                                         {
1430                                                 v &= 0x000000FF;
1431                                                 ln += 2;
1432                                         }
1433
1434                                         if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1435                                         {
1436                                                 v &= 0x0000FFFF;
1437                                                 ln += 2;
1438                                         }
1439
1440                                         if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1441                                         {
1442                                                 ln += 2;
1443                                         }
1444                                 }
1445
1446                                 *tk++ = CONST;
1447                                 *tk++ = v;
1448                                 continue;
1449                         case '^':               // ^ or ^^ <operator-name>
1450                                 if (*ln != '^')
1451                                 {
1452                                         *tk++ = '^';
1453                                         continue;
1454                                 }
1455
1456                                 if (((int)chrtab[*++ln] & STSYM) == 0)
1457                                 {
1458                                         error("invalid symbol following ^^");
1459                                         continue;
1460                                 }
1461
1462                                 p = ln++;
1463
1464                                 while ((int)chrtab[*ln] & CTSYM)
1465                                         ++ln;
1466
1467                                 for(state=0; state>=0;)
1468                                 {
1469                                         // Get char, convert to lowercase
1470                                         j = *p++;
1471
1472                                         if (j >= 'A' && j <= 'Z')
1473                                                 j += 0x20;
1474
1475                                         j += kwbase[state];
1476
1477                                         if (kwcheck[j] != state)
1478                                         {
1479                                                 j = -1;
1480                                                 break;
1481                                         }
1482
1483                                         if (*p == EOS || p == ln)
1484                                         {
1485                                                 j = kwaccept[j];
1486                                                 break;
1487                                         }
1488
1489                                         state = kwtab[j];
1490                                 }
1491
1492                                 if (j < 0 || state < 0)
1493                                 {
1494                                         error("unknown symbol following ^^");
1495                                         continue;
1496                                 }
1497
1498                                 *tk++ = (TOKEN)j;
1499                                 continue;
1500                         default:
1501                                 interror(2);    // Bad MULTX entry in chrtab
1502                                 continue;
1503                         }
1504                 }
1505
1506                 // Handle decimal constant
1507                 if (c & DIGIT)
1508                 {
1509                         v = 0;
1510
1511                         while ((int)chrtab[*ln] & DIGIT)
1512                                 v = (v * 10) + *ln++ - '0';
1513
1514                         // See if there's a .[bwl] after the constant & deal with it if so
1515                         if (*ln == '.')
1516                         {
1517                                 if ((*(ln + 1) == 'b') || (*(ln + 1) == 'B'))
1518                                 {
1519                                         v &= 0x000000FF;
1520                                         ln += 2;
1521                                 }
1522                                 else if ((*(ln + 1) == 'w') || (*(ln + 1) == 'W'))
1523                                 {
1524                                         v &= 0x0000FFFF;
1525                                         ln += 2;
1526                                 }
1527                                 else if ((*(ln + 1) == 'l') || (*(ln + 1) == 'L'))
1528                                 {
1529                                         ln += 2;
1530                                 }
1531                         }
1532
1533                         *tk++ = CONST;
1534                         *tk++ = v;
1535 //printf("CONST: %i\n", v);
1536                         continue;
1537                 }
1538
1539                 // Handle illegal character
1540                 return error("illegal character");
1541         }
1542
1543         // Terminate line of tokens and return "success."
1544
1545 goteol:
1546         tok = etok;                                                             // Set tok to beginning of line
1547
1548         if (stuffnull)                                                  // Terminate last SYMBOL
1549                 *nullspot = EOS;
1550
1551         *tk++ = EOL;
1552
1553         return OK;
1554 }
1555
1556
1557 //
1558 // .GOTO <label>        goto directive
1559 //
1560 // The label is searched for starting from the first line of the current,
1561 // enclosing macro definition. If no enclosing macro exists, an error is
1562 // generated.
1563 //
1564 // A label is of the form:
1565 //
1566 // :<name><whitespace>
1567 //
1568 // The colon must appear in column 1.  The label is stripped prior to macro
1569 // expansion, and is NOT subject to macro expansion.  The whitespace may also
1570 // be EOL.
1571 //
1572 int d_goto(WORD unused)
1573 {
1574         // Setup for the search
1575         if (*tok != SYMBOL)
1576                 return error("missing label");
1577
1578         char * sym = string[tok[1]];
1579         tok += 2;
1580
1581         if (cur_inobj->in_type != SRC_IMACRO)
1582                 return error("goto not in macro");
1583
1584         IMACRO * imacro = cur_inobj->inobj.imacro;
1585         struct LineList * defln = imacro->im_macro->lineList;
1586
1587         // Attempt to find the label, starting with the first line.
1588         for(; defln!=NULL; defln=defln->next)
1589         {
1590                 // Must start with a colon
1591                 if (defln->line[0] == ':')
1592                 {
1593                         // Compare names (sleazo string compare)
1594                         char * s1 = sym;
1595                         char * s2 = defln->line;
1596
1597                         // Either we will match the strings to EOS on both, or we will
1598                         // match EOS on string 1 to whitespace on string 2. Otherwise, we
1599                         // have no match.
1600                         while ((*s1 == *s2) || ((*s1 == EOS) && (chrtab[*s2] & WHITE)))
1601                         {
1602                                 // If we reached the end of string 1 (sym), we're done.
1603                                 // Note that we're also checking for the end of string 2 as
1604                                 // well, since we've established they're equal above.
1605                                 if (*s1 == EOS)
1606                                 {
1607                                         // Found the label, set new macro next-line and return.
1608                                         imacro->im_nextln = defln;
1609                                         return 0;
1610                                 }
1611
1612                                 s1++;
1613                                 s2++;
1614                         }
1615                 }
1616         }
1617
1618         return error("goto label not found");
1619 }
1620
1621
1622 void DumpTokenBuffer(void)
1623 {
1624         TOKEN * t;
1625         printf("Tokens [%X]: ", sloc);
1626
1627         for(t=tokbuf; *t!=EOL; t++)
1628         {
1629                 if (*t == COLON)
1630                         printf("[COLON]");
1631                 else if (*t == CONST)
1632                 {
1633                         t++;
1634                         printf("[CONST: $%X]", (uint32_t)*t);
1635                 }
1636                 else if (*t == ACONST)
1637                         printf("[ACONST]");
1638                 else if (*t == STRING)
1639                 {
1640                         t++;
1641                         printf("[STRING:\"%s\"]", string[*t]);
1642                 }
1643                 else if (*t == SYMBOL)
1644                 {
1645                         t++;
1646                         printf("[SYMBOL:\"%s\"]", string[*t]);
1647                 }
1648                 else if (*t == EOS)
1649                         printf("[EOS]");
1650                 else if (*t == TKEOF)
1651                         printf("[TKEOF]");
1652                 else if (*t == DEQUALS)
1653                         printf("[DEQUALS]");
1654                 else if (*t == SET)
1655                         printf("[SET]");
1656                 else if (*t == REG)
1657                         printf("[REG]");
1658                 else if (*t == DCOLON)
1659                         printf("[DCOLON]");
1660                 else if (*t == GE)
1661                         printf("[GE]");
1662                 else if (*t == LE)
1663                         printf("[LE]");
1664                 else if (*t == NE)
1665                         printf("[NE]");
1666                 else if (*t == SHR)
1667                         printf("[SHR]");
1668                 else if (*t == SHL)
1669                         printf("[SHL]");
1670                 else if (*t == UNMINUS)
1671                         printf("[UNMINUS]");
1672                 else if (*t == DOTB)
1673                         printf("[DOTB]");
1674                 else if (*t == DOTW)
1675                         printf("[DOTW]");
1676                 else if (*t == DOTL)
1677                         printf("[DOTL]");
1678                 else if (*t == DOTI)
1679                         printf("[DOTI]");
1680                 else if (*t == ENDEXPR)
1681                         printf("[ENDEXPR]");
1682                 else if (*t == CR_ABSCOUNT)
1683                         printf("[CR_ABSCOUNT]");
1684                 else if (*t == CR_DEFINED)
1685                         printf("[CR_DEFINED]");
1686                 else if (*t == CR_REFERENCED)
1687                         printf("[CR_REFERENCED]");
1688                 else if (*t == CR_STREQ)
1689                         printf("[CR_STREQ]");
1690                 else if (*t == CR_MACDEF)
1691                         printf("[CR_MACDEF]");
1692                 else if (*t == CR_TIME)
1693                         printf("[CR_TIME]");
1694                 else if (*t == CR_DATE)
1695                         printf("[CR_DATE]");
1696                 else if (*t >= 0x20 && *t <= 0x2F)
1697                         printf("[%c]", (char)*t);
1698                 else if (*t >= 0x3A && *t <= 0x3F)
1699                         printf("[%c]", (char)*t);
1700                 else if (*t >= 0x80 && *t <= 0x87)
1701                         printf("[D%u]", ((uint32_t)*t) - 0x80);
1702                 else if (*t >= 0x88 && *t <= 0x8F)
1703                         printf("[A%u]", ((uint32_t)*t) - 0x88);
1704                 else
1705                         printf("[%X:%c]", (uint32_t)*t, (char)*t);
1706         }
1707
1708         printf("[EOL]\n");
1709 }
1710