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