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