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