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