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