]> Shamusworld >> Repos - rmac/blob - token.c
Fix for bug #77 (ds with negative numbers).
[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 uint16_t curlineno;                     // Current line number (64K max currently)
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 the assembler
521 //         to choke on legitimate code... Need to investigate this further
522 //         before changing anything else here!
523                                                         case CONST:
524                                                                 sprintf(numbuf, "$%lx", (long unsigned int)*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         IREPT * irept = cur_inobj->inobj.irept;
652         LONG * strp = irept->ir_nextln;                 // initial null
653
654         // Do repeat at end of .rept block's string list
655         if (strp == NULL)
656         {
657                 DEBUG printf("back-to-top-of-repeat-block count=%d\n", (int)irept->ir_count);
658                 irept->ir_nextln = irept->ir_firstln;   // copy first line
659
660                 if (irept->ir_count-- == 0)
661                 {
662                         DEBUG printf("end-repeat-block\n");
663                         return NULL;
664                 }
665
666                 strp = irept->ir_nextln;
667         }
668
669         strcpy(irbuf, (char *)(irept->ir_nextln + 1));
670         DEBUG printf("repeat line='%s'\n", irbuf);
671         irept->ir_nextln = (LONG *)*strp;
672
673         return irbuf;
674 }
675
676
677 //
678 // Include a source file used at the root, and for ".include" files
679 //
680 int include(int handle, char * fname)
681 {
682         // Debug mode
683         if (debug)
684                 printf("[include: %s, cfileno=%u]\n", fname, cfileno);
685
686         // Alloc and initialize include-descriptors
687         INOBJ * inobj = a_inobj(SRC_IFILE);
688         IFILE * ifile = inobj->inobj.ifile;
689
690         ifile->ifhandle = handle;                               // Setup file handle
691         ifile->ifind = ifile->ifcnt = 0;                // Setup buffer indices
692         ifile->ifoldlineno = curlineno;                 // Save old line number
693         ifile->ifoldfname = curfname;                   // Save old filename
694         ifile->ifno = cfileno;                                  // Save old file number
695
696         // NB: This *must* be preincrement, we're adding one to the filecount here!
697         cfileno = ++filecount;                                  // Compute NEW file number
698         curfname = strdup(fname);                               // Set current filename (alloc storage)
699         curlineno = 0;                                                  // Start on line zero
700
701         // Add another file to the file-record
702         FILEREC * fr = (FILEREC *)malloc(sizeof(FILEREC));
703         fr->frec_next = NULL;
704         fr->frec_name = curfname;
705
706         if (last_fr == NULL)
707                 filerec = fr;                                           // Add first filerec
708         else
709                 last_fr->frec_next = fr;                        // Append to list of filerecs
710
711         last_fr = fr;
712         DEBUG printf("[include: curfname: %s, cfileno=%u]\n", curfname, cfileno);
713
714         return OK;
715 }
716
717
718 //
719 // Pop the current input level
720 //
721 int fpop(void)
722 {
723         IFILE * ifile;
724         IMACRO * imacro;
725         LONG * p, * p1;
726         INOBJ * inobj = cur_inobj;
727
728         if (inobj != NULL)
729         {
730                 // Pop IFENT levels until we reach the conditional assembly context we
731                 // were at when the input object was entered.
732                 int numUnmatched = 0;
733
734                 while (ifent != inobj->in_ifent)
735                 {
736                         if (d_endif() != 0)             // Something bad happened during endif parsing?
737                                 return -1;                      // If yes, bail instead of getting stuck in a loop
738
739                         numUnmatched++;
740                 }
741
742                 // Give a warning to the user that we had to wipe their bum for them
743                 if (numUnmatched > 0)
744                         warni("missing %d .endif(s)", numUnmatched);
745
746                 tok = inobj->in_otok;           // Restore tok and otok
747                 etok = inobj->in_etok;
748
749                 switch (inobj->in_type)
750                 {
751                 case SRC_IFILE:                         // Pop and release an IFILE
752                         if (debug)
753                                 printf("[Leaving: %s]\n", curfname);
754
755                         ifile = inobj->inobj.ifile;
756                         ifile->if_link = f_ifile;
757                         f_ifile = ifile;
758                         close(ifile->ifhandle);                 // Close source file
759 if (debug)      printf("[fpop (pre):  curfname=%s]\n", curfname);
760                         curfname = ifile->ifoldfname;   // Set current filename
761 if (debug)      printf("[fpop (post): curfname=%s]\n", curfname);
762 if (debug)      printf("[fpop: (pre)  cfileno=%d ifile->ifno=%d]\n", (int)cfileno, (int)ifile->ifno);
763                         curlineno = ifile->ifoldlineno; // Set current line#
764                         DEBUG printf("cfileno=%d ifile->ifno=%d\n", (int)cfileno, (int)ifile->ifno);
765                         cfileno = ifile->ifno;                  // Restore current file number
766 if (debug)      printf("[fpop: (post) cfileno=%d ifile->ifno=%d]\n", (int)cfileno, (int)ifile->ifno);
767                         break;
768                 case SRC_IMACRO:                                        // Pop and release an IMACRO
769                         imacro = inobj->inobj.imacro;
770                         imacro->im_link = f_imacro;
771                         f_imacro = imacro;
772                         break;
773                 case SRC_IREPT:                                         // Pop and release an IREPT
774                         DEBUG printf("dealloc IREPT\n");
775                         p = inobj->inobj.irept->ir_firstln;
776
777                         while (p != NULL)
778                         {
779                                 p1 = (LONG *)*p;
780                                 p = p1;
781                         }
782
783                         break;
784                 }
785
786                 cur_inobj = inobj->in_link;
787                 inobj->in_link = f_inobj;
788                 f_inobj = inobj;
789         }
790
791         return 0;
792 }
793
794
795 //
796 // Get line from file into buf, return NULL on EOF or ptr to the start of a
797 // null-term line
798 //
799 char * GetNextLine(void)
800 {
801         int i, j;
802         char * p, * d;
803         int readamt = -1;                                               // 0 if last read() yeilded 0 bytes
804         IFILE * fl = cur_inobj->inobj.ifile;
805
806         for(;;)
807         {
808                 // Scan for next end-of-line; handle stupid text formats by treating
809                 // \r\n the same as \n. (lone '\r' at end of buffer means we have to
810                 // check for '\n').
811                 d = &fl->ifbuf[fl->ifind];
812
813                 for(p=d, i=0, j=fl->ifcnt; i<j; i++, p++)
814                 {
815                         if (*p == '\r' || *p == '\n')
816                         {
817                                 i++;
818
819                                 if (*p == '\r')
820                                 {
821                                         if (i >= j)
822                                                 break;  // Need to read more, then look for '\n' to eat
823                                         else if (p[1] == '\n')
824                                                 i++;
825                                 }
826
827                                 // Cover up the newline with end-of-string sentinel
828                                 *p = '\0';
829
830                                 fl->ifind += i;
831                                 fl->ifcnt -= i;
832                                 return d;
833                         }
834                 }
835
836                 // Handle hanging lines by ignoring them (Input file is exhausted, no
837                 // \r or \n on last line)
838                 // Shamus: This is retarded. Never ignore any input!
839                 if (!readamt && fl->ifcnt)
840                 {
841 #if 0
842                         fl->ifcnt = 0;
843                         *p = '\0';
844                         return NULL;
845 #else
846                         // Really should check to see if we're at the end of the buffer!
847                         // :-P
848                         fl->ifbuf[fl->ifind + fl->ifcnt] = '\0';
849                         fl->ifcnt = 0;
850                         return &fl->ifbuf[fl->ifind];
851 #endif
852                 }
853
854                 // Truncate and return absurdly long lines.
855                 if (fl->ifcnt >= QUANTUM)
856                 {
857                         fl->ifbuf[fl->ifind + fl->ifcnt - 1] = '\0';
858                         fl->ifcnt = 0;
859                         return &fl->ifbuf[fl->ifind];
860                 }
861
862                 // Relocate what's left of a line to the beginning of the buffer, and
863                 // read some more of the file in; return NULL if the buffer's empty and
864                 // on EOF.
865                 if (fl->ifind != 0)
866                 {
867                         p = &fl->ifbuf[fl->ifind];
868                         d = &fl->ifbuf[fl->ifcnt & 1];
869
870                         for(i=0; i<fl->ifcnt; i++)
871                                 *d++ = *p++;
872
873                         fl->ifind = fl->ifcnt & 1;
874                 }
875
876                 readamt = read(fl->ifhandle, &fl->ifbuf[fl->ifind + fl->ifcnt], QUANTUM);
877
878                 if (readamt < 0)
879                         return NULL;
880
881                 if ((fl->ifcnt += readamt) == 0)
882                         return NULL;
883         }
884 }
885
886
887 //
888 // Tokenize a line
889 //
890 int TokenizeLine(void)
891 {
892         char * ln = NULL;                       // Ptr to current position in line
893         char * p;                                       // Random character ptr
894         TOKEN * tk;                                     // Token-deposit ptr
895         int state = 0;                          // State for keyword detector
896         int j = 0;                                      // Var for keyword detector
897         char c;                                         // Random char
898         VALUE v;                                        // Random value
899         char * nullspot = NULL;         // Spot to clobber for SYMBOL termination
900         int stuffnull;                          // 1:terminate SYMBOL '\0' at *nullspot
901         char c1;
902         int stringNum = 0;                      // Pointer to string locations in tokenized line
903
904 retry:
905
906         if (cur_inobj == NULL)                                  // Return EOF if input stack is empty
907                 return TKEOF;
908
909         // Get another line of input from the current input source: a file, a
910         // macro, or a repeat-block
911         switch (cur_inobj->in_type)
912         {
913         // Include-file:
914         // o  handle EOF;
915         // o  bump source line number;
916         // o  tag the listing-line with a space;
917         // o  kludge lines generated by Alcyon C.
918         case SRC_IFILE:
919                 if ((ln = GetNextLine()) == NULL)
920                 {
921 if (debug) printf("TokenizeLine: Calling fpop() from SRC_IFILE...\n");
922                         if (fpop() == 0)                                // Pop input level
923                                 goto retry;                                     // Try for more lines
924                         else
925                         {
926                                 ifent->if_prev = (IFENT *) - 1; //Signal Assemble() that we have reached EOF with unbalanced if/endifs
927                                 return TKEOF;
928                         }
929                 }
930
931                 curlineno++;                                            // Bump line number
932                 lntag = SPACE;
933
934                 if (as68_flag)
935                 {
936                         // AS68 compatibility, throw away all lines starting with
937                         // back-quotes, tildes, or '*'
938                         // On other lines, turn the first '*' into a semi-colon.
939                         if (*ln == '`' || *ln == '~' || *ln == '*')
940                                 *ln = ';';
941                         else
942                         {
943                                 for(p=ln; *p!=EOS; p++)
944                                 {
945                                         if (*p == '*')
946                                         {
947                                                 *p = ';';
948                                                 break;
949                                         }
950                                 }
951                         }
952                 }
953
954                 break;
955         // Macro-block:
956         // o  Handle end-of-macro;
957         // o  tag the listing-line with an at (@) sign.
958         case SRC_IMACRO:
959                 if ((ln = GetNextMacroLine()) == NULL)
960                 {
961                         if (ExitMacro() == 0)                   // Exit macro (pop args, do fpop(), etc)
962                                 goto retry;                                     // Try for more lines...
963                         else
964                                 return TKEOF;                           // Oops, we got a non zero return code, signal EOF
965                 }
966
967                 lntag = '@';
968                 break;
969         // Repeat-block:
970         // o  Handle end-of-repeat-block;
971         // o  tag the listing-line with a pound (#) sign.
972         case SRC_IREPT:
973                 if ((ln = GetNextRepeatLine()) == NULL)
974                 {
975 if (debug) printf("TokenizeLine: Calling fpop() from SRC_IREPT...\n");
976                         fpop();
977                         goto retry;
978                 }
979
980                 lntag = '#';
981                 break;
982         }
983
984         // Save text of the line.  We only do this during listings and within
985         // macro-type blocks, since it is expensive to unconditionally copy every
986         // line.
987         if (lnsave)
988                 strcpy(lnbuf, ln);
989
990         // General house-keeping
991         tok = tokeol;                   // Set "tok" to EOL in case of error
992         tk = etok;                              // Reset token ptr
993         stuffnull = 0;                  // Don't stuff nulls
994         totlines++;                             // Bump total #lines assembled
995
996         // See if the entire line is a comment. This is a win if the programmer
997         // puts in lots of comments
998         if (*ln == '*' || *ln == ';' || ((*ln == '/') && (*(ln + 1) == '/')))
999                 goto goteol;
1000
1001         // Main tokenization loop;
1002         // o  skip whitespace;
1003         // o  handle end-of-line;
1004         // o  handle symbols;
1005         // o  handle single-character tokens (operators, etc.);
1006         // o  handle multiple-character tokens (constants, strings, etc.).
1007         for(; *ln!=EOS;)
1008         {
1009                 // Skip whitespace, handle EOL
1010                 while ((int)chrtab[*ln] & WHITE)
1011                         ln++;
1012
1013                 // Handle EOL, comment with ';'
1014                 if (*ln == EOS || *ln == ';'|| ((*ln == '/') && (*(ln + 1) == '/')))
1015                         break;
1016
1017                 // Handle start of symbol. Symbols are null-terminated in place. The
1018                 // termination is always one symbol behind, since there may be no place
1019                 // for a null in the case that an operator immediately follows the name.
1020                 c = chrtab[*ln];
1021
1022                 if (c & STSYM)
1023                 {
1024                         if (stuffnull)                  // Terminate old symbol from previous pass
1025                                 *nullspot = EOS;
1026
1027                         v = 0;                                  // Assume no DOT attrib follows symbol
1028                         stuffnull = 1;
1029
1030                         // In some cases, we need to check for a DOTx at the *beginning*
1031                         // of a symbol, as the "start" of the line we're currently looking
1032                         // at could be somewhere in the middle of that line!
1033                         if (*ln == '.')
1034                         {
1035                                 // Make sure that it's *only* a .[bwsl] following, and not the
1036                                 // start of a local symbol:
1037                                 if ((chrtab[*(ln + 1)] & DOT)
1038                                         && (dotxtab[*(ln + 1)] != 0)
1039                                         && !(chrtab[*(ln + 2)] & CTSYM))
1040                                 {
1041                                         // We found a legitimate DOTx construct, so add it to the
1042                                         // token stream:
1043                                         ln++;
1044                                         stuffnull = 0;
1045                                         *tk++ = (TOKEN)dotxtab[*ln++];
1046                                         continue;
1047                                 }
1048                         }
1049
1050                         p = nullspot = ln++;    // Nullspot -> start of this symbol
1051
1052                         // Find end of symbol (and compute its length)
1053                         for(j=1; (int)chrtab[*ln]&CTSYM; j++)
1054                                 ln++;
1055
1056                         // Handle "DOT" special forms (like ".b") that follow a normal
1057                         // symbol or keyword:
1058                         if (*ln == '.')
1059                         {
1060                                 *ln++ = EOS;            // Terminate symbol
1061                                 stuffnull = 0;          // And never try it again
1062
1063                                 // Character following the `.' must have a DOT attribute, and
1064                                 // the chararacter after THAT one must not have a start-symbol
1065                                 // attribute (to prevent symbols that look like, for example,
1066                                 // "zingo.barf", which might be a good idea anyway....)
1067                                 if (((chrtab[*ln] & DOT) == 0) || (dotxtab[*ln] == 0))
1068                                         return error("[bwsl] must follow '.' in symbol");
1069
1070                                 v = (VALUE)dotxtab[*ln++];
1071
1072                                 if (chrtab[*ln] & CTSYM)
1073                                         return error("misuse of '.', not allowed in symbols");
1074                         }
1075
1076                         // If the symbol is small, check to see if it's really the name of
1077                         // a register.
1078                         if (j <= KWSIZE)
1079                         {
1080                                 for(state=0; state>=0;)
1081                                 {
1082                                         j = (int)tolowertab[*p++];
1083                                         j += kwbase[state];
1084
1085                                         if (kwcheck[j] != state)
1086                                         {
1087                                                 j = -1;
1088                                                 break;
1089                                         }
1090
1091                                         if (*p == EOS || p == ln)
1092                                         {
1093                                                 j = kwaccept[j];
1094                                                 break;
1095                                         }
1096
1097                                         state = kwtab[j];
1098                                 }
1099                         }
1100                         else
1101                         {
1102                                 j = -1;
1103                         }
1104
1105                         // Make j = -1 if user tries to use a RISC register while in 68K mode
1106                         if (!(rgpu || rdsp) && ((TOKEN)j >= KW_R0 && (TOKEN)j <= KW_R31))
1107                         {
1108                                 j = -1;
1109                         }
1110
1111                         // Make j = -1 if time, date etc with no preceeding ^^
1112                         // defined, referenced, streq, macdef, date and time
1113                         switch ((TOKEN)j)
1114                         {
1115                         case 112:   // defined
1116                         case 113:   // referenced
1117                         case 118:   // streq
1118                         case 119:   // macdef
1119                         case 120:   // time
1120                         case 121:   // date
1121                                 j = -1;
1122                         }
1123
1124                         // If not tokenized keyword OR token was not found
1125                         if ((j < 0) || (state < 0))
1126                         {
1127                                 *tk++ = SYMBOL;
1128 //#warning
1129 //problem here: nullspot is a char * but TOKEN is a uint32_t. On a 64-bit
1130 //system, this will cause all kinds of mischief.
1131 #if 0
1132                                 *tk++ = (TOKEN)nullspot;
1133 #else
1134                                 string[stringNum] = nullspot;
1135                                 *tk++ = stringNum;
1136                                 stringNum++;
1137 #endif
1138                         }
1139                         else
1140                         {
1141                                 *tk++ = (TOKEN)j;
1142                                 stuffnull = 0;
1143                         }
1144
1145                         if (v)                                                  // Record attribute token (if any)
1146                                 *tk++ = (TOKEN)v;
1147
1148                         if (stuffnull)                                  // Arrange for string termination on next pass
1149                                 nullspot = ln;
1150
1151                         continue;
1152                 }
1153
1154                 // Handle identity tokens
1155                 if (c & SELF)
1156                 {
1157                         *tk++ = *ln++;
1158                         continue;
1159                 }
1160
1161                 // Handle multiple-character tokens
1162                 if (c & MULTX)
1163                 {
1164
1165                         switch (*ln++)
1166                         {
1167                         case '!':               // ! or !=
1168                                 if (*ln == '=')
1169                                 {
1170                                         *tk++ = NE;
1171                                         ++ln;
1172                                 }
1173                                 else
1174                                         *tk++ = '!';
1175
1176                                 continue;
1177                         case '\'':              // 'string'
1178                                 if (m6502)
1179                                 {
1180                                         // Hardcoded for now, maybe this will change in the future
1181                                         *tk++ = STRINGA8;
1182                                         goto dostring;
1183                                 }
1184                                 // Fall through
1185                         case '\"':              // "string"
1186                                 *tk++ = STRING;
1187 dostring:
1188                                 c1 = ln[-1];
1189                                 string[stringNum] = ln;
1190                                 *tk++ = stringNum;
1191                                 stringNum++;
1192
1193                                 for(p=ln; *ln!=EOS && *ln!=c1;)
1194                                 {
1195                                         c = *ln++;
1196
1197                                         if (c == '\\')
1198                                         {
1199                                                 switch (*ln++)
1200                                                 {
1201                                                 case EOS:
1202                                                         return(error("unterminated string"));
1203                                                 case 'e':
1204                                                         c = '\033';
1205                                                         break;
1206                                                 case 'n':
1207                                                         c = '\n';
1208                                                         break;
1209                                                 case 'b':
1210                                                         c = '\b';
1211                                                         break;
1212                                                 case 't':
1213                                                         c = '\t';
1214                                                         break;
1215                                                 case 'r':
1216                                                         c = '\r';
1217                                                         break;
1218                                                 case 'f':
1219                                                         c = '\f';
1220                                                         break;
1221                                                 case '\"':
1222                                                         c = '\"';
1223                                                         break;
1224                                                 case '\'':
1225                                                         c = '\'';
1226                                                         break;
1227                                                 case '\\':
1228                                                         c = '\\';
1229                                                         break;
1230                                                 default:
1231                                                         warn("bad backslash code in string");
1232                                                         ln--;
1233                                                         break;
1234                                                 }
1235                                         }
1236
1237                                         *p++ = c;
1238                                 }
1239
1240                                 if (*ln++ != c1)
1241                                         return error("unterminated string");
1242
1243                                 *p++ = EOS;
1244                                 continue;
1245                         case '$':               // $, hex constant
1246                                 if (chrtab[*ln] & HDIGIT)
1247                                 {
1248                                         v = 0;
1249
1250                                         // Parse the hex value
1251                                         while (hextab[*ln] >= 0)
1252                                                 v = (v << 4) + (int)hextab[*ln++];
1253
1254                                         // ggn: Okay, some comments here are in order I think....
1255                                         // The original madmac sources didn't parse the size at
1256                                         // this point (i.e. .b/.w/.l). It was probably done at
1257                                         // another point, although it's unclear to me exactly
1258                                         // where. So why change this? My understanding (at least
1259                                         // from what SCPCD said on IRC) is that .w addressing
1260                                         // formats produce wrong code on jaguar (or doesn't execute
1261                                         // properly? something like that). So the code was changed
1262                                         // to mask off the upper bits depending on length (note: I
1263                                         // don't think .b is valid at all! I only know of .w/.l, so
1264                                         // this should probably be wiped). Then the code that
1265                                         // parses the constant and checks to see if it's between
1266                                         // $ffff0000 and $8000 never got triggered, so yay job
1267                                         // done! ...now say we want to assemble a st .prg. One of
1268                                         // the most widely spread optimisations is move.X expr.w,Y
1269                                         // (or vice versa, or both, anyway...) to access hardware
1270                                         // registers (which are mapped to $fxxxxx). This botchy
1271                                         // thing would create "hilarious" code while trying to
1272                                         // access hardware registers. So I made a condition to see
1273                                         // if st mode or jaguar is active and apply the both or
1274                                         // not. One last note: this is hardcoded to get optimised
1275                                         // for now on ST mode, i.e. it can't generate code like
1276                                         // move.w $00001234,d0 - it'll always get optimised to
1277                                         // move.w $1234.w,d0. It's probably ok, but maybe a warning
1278                                         // should be emitted? Or maybe finding a way to make it not
1279                                         // auto-optimise? I think it's ok for now...
1280                                         if (*ln == '.')
1281                                         {
1282                                                 if (obj_format == BSD)
1283                                                 {
1284                                                         if ((*(ln + 1) & 0xDF) == 'B')
1285                                                         {
1286                                                                 v &= 0x000000FF;
1287                                                                 ln += 2;
1288                                                         }
1289                                                         else if ((*(ln + 1) & 0xDF) == 'W')
1290                                                         {
1291                                                                 v &= 0x0000FFFF;
1292                                                                 ln += 2;
1293                                                         }
1294                                                         else if ((*(ln + 1) & 0xDF) == 'L')
1295                                                         {
1296                                                                 ln += 2;
1297                                                         }
1298                                                 }
1299                                         }
1300
1301                                         *tk++ = CONST;
1302                                         *tk++ = v;
1303
1304                                         if (obj_format == ALCYON)
1305                                         {
1306                                                 if ((*(ln + 1) == 'w') || (*(ln + 1) == 'W'))
1307                                                 {
1308                                                         *tk++ = DOTW;
1309                                                         ln += 2;
1310                                                 }
1311                                                 else if ((*(ln + 1) == 'l') || (*(ln + 1) == 'L'))
1312                                                 {
1313                                                         *tk++ = DOTL;
1314                                                         ln += 2;
1315                                                 }
1316                                         }
1317                                 }
1318                                 else
1319                                         *tk++ = '$';
1320
1321                                 continue;
1322                         case '<':               // < or << or <> or <=
1323                                 switch (*ln)
1324                                 {
1325                                 case '<':
1326                                         *tk++ = SHL;
1327                                         ++ln;
1328                                         continue;
1329                                 case '>':
1330                                         *tk++ = NE;
1331                                         ++ln;
1332                                         continue;
1333                                 case '=':
1334                                         *tk++ = LE;
1335                                         ++ln;
1336                                         continue;
1337                                 default:
1338                                         *tk++ = '<';
1339                                         continue;
1340                                 }
1341                         case ':':               // : or ::
1342                                 if (*ln == ':')
1343                                 {
1344                                         *tk++ = DCOLON;
1345                                         ++ln;
1346                                 }
1347                                 else
1348                                         *tk++ = ':';
1349
1350                                 continue;
1351                         case '=':               // = or ==
1352                                 if (*ln == '=')
1353                                 {
1354                                         *tk++ = DEQUALS;
1355                                         ++ln;
1356                                 }
1357                                 else
1358                                         *tk++ = '=';
1359
1360                                 continue;
1361                         case '>':               // > or >> or >=
1362                                 switch (*ln)
1363                                 {
1364                                 case '>':
1365                                         *tk++ = SHR;
1366                                         ln++;
1367                                         continue;
1368                                 case '=':
1369                                         *tk++ = GE;
1370                                         ln++;
1371                                         continue;
1372                                 default:
1373                                         *tk++ = '>';
1374                                         continue;
1375                                 }
1376                         case '%':               // % or binary constant
1377                                 if (*ln < '0' || *ln > '1')
1378                                 {
1379                                         *tk++ = '%';
1380                                         continue;
1381                                 }
1382
1383                                 v = 0;
1384
1385                                 while (*ln >= '0' && *ln <= '1')
1386                                         v = (v << 1) + *ln++ - '0';
1387
1388                                 if (*ln == '.')
1389                                 {
1390                                         if ((*(ln + 1) == 'b') || (*(ln + 1) == 'B'))
1391                                         {
1392                                                 v &= 0x000000FF;
1393                                                 ln += 2;
1394                                         }
1395
1396                                         if ((*(ln + 1) == 'w') || (*(ln + 1) == 'W'))
1397                                         {
1398                                                 v &= 0x0000FFFF;
1399                                                 ln += 2;
1400                                         }
1401
1402                                         if ((*(ln + 1) == 'l') || (*(ln + 1) == 'L'))
1403                                         {
1404                                                 ln += 2;
1405                                         }
1406                                 }
1407
1408                                 *tk++ = CONST;
1409                                 *tk++ = v;
1410                                 continue;
1411                         case '@':               // @ or octal constant
1412                                 if (*ln < '0' || *ln > '7')
1413                                 {
1414                                         *tk++ = '@';
1415                                         continue;
1416                                 }
1417
1418                                 v = 0;
1419
1420                                 while (*ln >= '0' && *ln <= '7')
1421                                         v = (v << 3) + *ln++ - '0';
1422
1423                                 if (*ln == '.')
1424                                 {
1425                                         if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1426                                         {
1427                                                 v &= 0x000000FF;
1428                                                 ln += 2;
1429                                         }
1430
1431                                         if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1432                                         {
1433                                                 v &= 0x0000FFFF;
1434                                                 ln += 2;
1435                                         }
1436
1437                                         if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1438                                         {
1439                                                 ln += 2;
1440                                         }
1441                                 }
1442
1443                                 *tk++ = CONST;
1444                                 *tk++ = v;
1445                                 continue;
1446                         case '^':               // ^ or ^^ <operator-name>
1447                                 if (*ln != '^')
1448                                 {
1449                                         *tk++ = '^';
1450                                         continue;
1451                                 }
1452
1453                                 if (((int)chrtab[*++ln] & STSYM) == 0)
1454                                 {
1455                                         error("invalid symbol following ^^");
1456                                         continue;
1457                                 }
1458
1459                                 p = ln++;
1460
1461                                 while ((int)chrtab[*ln] & CTSYM)
1462                                         ++ln;
1463
1464                                 for(state=0; state>=0;)
1465                                 {
1466                                         // Get char, convert to lowercase
1467                                         j = *p++;
1468
1469                                         if (j >= 'A' && j <= 'Z')
1470                                                 j += 0x20;
1471
1472                                         j += kwbase[state];
1473
1474                                         if (kwcheck[j] != state)
1475                                         {
1476                                                 j = -1;
1477                                                 break;
1478                                         }
1479
1480                                         if (*p == EOS || p == ln)
1481                                         {
1482                                                 j = kwaccept[j];
1483                                                 break;
1484                                         }
1485
1486                                         state = kwtab[j];
1487                                 }
1488
1489                                 if (j < 0 || state < 0)
1490                                 {
1491                                         error("unknown symbol following ^^");
1492                                         continue;
1493                                 }
1494
1495                                 *tk++ = (TOKEN)j;
1496                                 continue;
1497                         default:
1498                                 interror(2);    // Bad MULTX entry in chrtab
1499                                 continue;
1500                         }
1501                 }
1502
1503                 // Handle decimal constant
1504                 if (c & DIGIT)
1505                 {
1506                         v = 0;
1507
1508                         while ((int)chrtab[*ln] & DIGIT)
1509                                 v = (v * 10) + *ln++ - '0';
1510
1511                         // See if there's a .[bwl] after the constant & deal with it if so
1512                         if (*ln == '.')
1513                         {
1514                                 if ((*(ln + 1) == 'b') || (*(ln + 1) == 'B'))
1515                                 {
1516                                         v &= 0x000000FF;
1517                                         ln += 2;
1518                                 }
1519                                 else if ((*(ln + 1) == 'w') || (*(ln + 1) == 'W'))
1520                                 {
1521                                         v &= 0x0000FFFF;
1522                                         ln += 2;
1523                                 }
1524                                 else if ((*(ln + 1) == 'l') || (*(ln + 1) == 'L'))
1525                                 {
1526                                         ln += 2;
1527                                 }
1528                         }
1529
1530                         *tk++ = CONST;
1531                         *tk++ = v;
1532 //printf("CONST: %i\n", v);
1533                         continue;
1534                 }
1535
1536                 // Handle illegal character
1537                 return error("illegal character");
1538         }
1539
1540         // Terminate line of tokens and return "success."
1541
1542 goteol:
1543         tok = etok;                                                             // Set tok to beginning of line
1544
1545         if (stuffnull)                                                  // Terminate last SYMBOL
1546                 *nullspot = EOS;
1547
1548         *tk++ = EOL;
1549
1550         return OK;
1551 }
1552
1553
1554 //
1555 // .GOTO <label>        goto directive
1556 //
1557 // The label is searched for starting from the first line of the current,
1558 // enclosing macro definition. If no enclosing macro exists, an error is
1559 // generated.
1560 //
1561 // A label is of the form:
1562 //
1563 // :<name><whitespace>
1564 //
1565 // The colon must appear in column 1.  The label is stripped prior to macro
1566 // expansion, and is NOT subject to macro expansion.  The whitespace may also
1567 // be EOL.
1568 //
1569 int d_goto(WORD unused)
1570 {
1571         // Setup for the search
1572         if (*tok != SYMBOL)
1573                 return error("missing label");
1574
1575         char * sym = string[tok[1]];
1576         tok += 2;
1577
1578         if (cur_inobj->in_type != SRC_IMACRO)
1579                 return error("goto not in macro");
1580
1581         IMACRO * imacro = cur_inobj->inobj.imacro;
1582         struct LineList * defln = imacro->im_macro->lineList;
1583
1584         // Attempt to find the label, starting with the first line.
1585         for(; defln!=NULL; defln=defln->next)
1586         {
1587                 // Must start with a colon
1588                 if (defln->line[0] == ':')
1589                 {
1590                         // Compare names (sleazo string compare)
1591                         char * s1 = sym;
1592                         char * s2 = defln->line;
1593
1594                         // Either we will match the strings to EOS on both, or we will
1595                         // match EOS on string 1 to whitespace on string 2. Otherwise, we
1596                         // have no match.
1597                         while ((*s1 == *s2) || ((*s1 == EOS) && (chrtab[*s2] & WHITE)))
1598                         {
1599                                 // If we reached the end of string 1 (sym), we're done.
1600                                 // Note that we're also checking for the end of string 2 as
1601                                 // well, since we've established they're equal above.
1602                                 if (*s1 == EOS)
1603                                 {
1604                                         // Found the label, set new macro next-line and return.
1605                                         imacro->im_nextln = defln;
1606                                         return 0;
1607                                 }
1608
1609                                 s1++;
1610                                 s2++;
1611                         }
1612                 }
1613         }
1614
1615         return error("goto label not found");
1616 }
1617
1618
1619 void DumpTokenBuffer(void)
1620 {
1621         TOKEN * t;
1622         printf("Tokens [%X]: ", sloc);
1623
1624         for(t=tokbuf; *t!=EOL; t++)
1625         {
1626                 if (*t == COLON)
1627                         printf("[COLON]");
1628                 else if (*t == CONST)
1629                 {
1630                         t++;
1631                         printf("[CONST: $%X]", (uint32_t)*t);
1632                 }
1633                 else if (*t == ACONST)
1634                         printf("[ACONST]");
1635                 else if (*t == STRING)
1636                 {
1637                         t++;
1638                         printf("[STRING:\"%s\"]", string[*t]);
1639                 }
1640                 else if (*t == SYMBOL)
1641                 {
1642                         t++;
1643                         printf("[SYMBOL:\"%s\"]", string[*t]);
1644                 }
1645                 else if (*t == EOS)
1646                         printf("[EOS]");
1647                 else if (*t == TKEOF)
1648                         printf("[TKEOF]");
1649                 else if (*t == DEQUALS)
1650                         printf("[DEQUALS]");
1651                 else if (*t == SET)
1652                         printf("[SET]");
1653                 else if (*t == REG)
1654                         printf("[REG]");
1655                 else if (*t == DCOLON)
1656                         printf("[DCOLON]");
1657                 else if (*t == GE)
1658                         printf("[GE]");
1659                 else if (*t == LE)
1660                         printf("[LE]");
1661                 else if (*t == NE)
1662                         printf("[NE]");
1663                 else if (*t == SHR)
1664                         printf("[SHR]");
1665                 else if (*t == SHL)
1666                         printf("[SHL]");
1667                 else if (*t == UNMINUS)
1668                         printf("[UNMINUS]");
1669                 else if (*t == DOTB)
1670                         printf("[DOTB]");
1671                 else if (*t == DOTW)
1672                         printf("[DOTW]");
1673                 else if (*t == DOTL)
1674                         printf("[DOTL]");
1675                 else if (*t == DOTI)
1676                         printf("[DOTI]");
1677                 else if (*t == ENDEXPR)
1678                         printf("[ENDEXPR]");
1679                 else if (*t == CR_ABSCOUNT)
1680                         printf("[CR_ABSCOUNT]");
1681                 else if (*t == CR_DEFINED)
1682                         printf("[CR_DEFINED]");
1683                 else if (*t == CR_REFERENCED)
1684                         printf("[CR_REFERENCED]");
1685                 else if (*t == CR_STREQ)
1686                         printf("[CR_STREQ]");
1687                 else if (*t == CR_MACDEF)
1688                         printf("[CR_MACDEF]");
1689                 else if (*t == CR_TIME)
1690                         printf("[CR_TIME]");
1691                 else if (*t == CR_DATE)
1692                         printf("[CR_DATE]");
1693                 else if (*t >= 0x20 && *t <= 0x2F)
1694                         printf("[%c]", (char)*t);
1695                 else if (*t >= 0x3A && *t <= 0x3F)
1696                         printf("[%c]", (char)*t);
1697                 else if (*t >= 0x80 && *t <= 0x87)
1698                         printf("[D%u]", ((uint32_t)*t) - 0x80);
1699                 else if (*t >= 0x88 && *t <= 0x8F)
1700                         printf("[A%u]", ((uint32_t)*t) - 0x88);
1701                 else
1702                         printf("[%X:%c]", (uint32_t)*t, (char)*t);
1703         }
1704
1705         printf("[EOL]\n");
1706 }
1707