2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // TOKEN.C - Token Handling
4 // Copyright (C) 199x Landon Dyer, 2011-2012 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source Utilised with the Kind Permission of Landon Dyer
15 #define DECL_KW // Declare keyword arrays
16 #define DEF_KW // Declare keyword values
17 #include "kwtab.h" // Incl generated keyword tables & defs
20 int lnsave; // 1; strcpy() text of current line
21 int curlineno; // Current line number
22 int totlines; // Total # of lines
23 int mjump_align = 0; // mjump alignment flag
24 char lntag; // Line tag
25 char * curfname; // Current filename
26 char tolowertab[128]; // Uppercase ==> lowercase
27 char hextab[128]; // Table of hex values
28 char dotxtab[128]; // Table for ".b", ".s", etc.
29 char irbuf[LNSIZ]; // Text for .rept block line
30 char lnbuf[LNSIZ]; // Text of current line
31 WORD filecount; // Unique file number counter
32 WORD cfileno; // Current file number
33 TOKEN * tok; // Ptr to current token
34 TOKEN * etok; // Ptr past last token in tokbuf[]
35 TOKEN tokeol[1] = {EOL}; // Bailout end-of-line token
36 char * string[TOKBUFSIZE*2]; // Token buffer string pointer storage
38 // File record, used to maintain a list of every include file ever visited
39 #define FILEREC struct _filerec
49 INOBJ * cur_inobj; // Ptr current input obj (IFILE/IMACRO)
50 static INOBJ * f_inobj; // Ptr list of free INOBJs
51 static IFILE * f_ifile; // Ptr list of free IFILEs
52 static IMACRO * f_imacro; // Ptr list of free IMACROs
54 static TOKEN tokbuf[TOKBUFSIZE]; // Token buffer (stack-like, all files)
57 ILLEG, ILLEG, ILLEG, ILLEG, // NUL SOH STX ETX
58 ILLEG, ILLEG, ILLEG, ILLEG, // EOT ENQ ACK BEL
59 ILLEG, WHITE, ILLEG, ILLEG, // BS HT LF VT
60 WHITE, ILLEG, ILLEG, ILLEG, // FF CR SO SI
62 ILLEG, ILLEG, ILLEG, ILLEG, // DLE DC1 DC2 DC3
63 ILLEG, ILLEG, ILLEG, ILLEG, // DC4 NAK SYN ETB
64 ILLEG, ILLEG, ILLEG, ILLEG, // CAN EM SUB ESC
65 ILLEG, ILLEG, ILLEG, ILLEG, // FS GS RS US
67 WHITE, MULTX, MULTX, SELF, // SP ! " #
68 MULTX+CTSYM, MULTX, SELF, MULTX, // $ % & '
69 SELF, SELF, SELF, SELF, // ( ) * +
70 SELF, SELF, STSYM, SELF, // , - . /
72 DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 0 1
73 DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 2 3
74 DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 4 5
75 DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 6 7
76 DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 8 9
78 MULTX, MULTX, MULTX, STSYM+CTSYM, // < = > ?
80 MULTX, STSYM+CTSYM+HDIGIT, // @ A
81 (char)((BYTE)DOT)+STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT, // B C
82 STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT, // D E
83 STSYM+CTSYM+HDIGIT, STSYM+CTSYM, // F G
84 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, // H I J K
85 (char)((BYTE)DOT)+STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, // L M N O
87 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, // P Q R S
88 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, // T U V W
89 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, SELF, // X Y Z [
90 SELF, SELF, MULTX, STSYM+CTSYM, // \ ] ^ _
92 ILLEG, STSYM+CTSYM+HDIGIT, // ` a
93 (char)((BYTE)DOT)+STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT, // b c
94 STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT, // d e
95 STSYM+CTSYM+HDIGIT, STSYM+CTSYM, // f g
96 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, // h i j k
97 (char)((BYTE)DOT)+STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, // l m n o
99 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, // p q r s
100 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, // t u v w
101 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, SELF, // x y z {
102 SELF, SELF, SELF, ILLEG // | } ~ DEL
105 // Names of registers
106 static char * regname[] = {
107 "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
108 "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
109 "pc", "ssp", "usp", "sr", "ccr"
112 static char * riscregname[] = {
113 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
114 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
115 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
116 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
120 void SetFilenameForErrorReporting(void)
124 // Check for absolute top filename (this should never happen)
127 curfname = "(*top*)";
131 FILEREC * fr = filerec;
133 // Advance to the correct record...
134 while (fr != NULL && fnum != 0)
140 // Check for file # record not found (this should never happen either)
143 curfname = "(*NOT FOUND*)";
147 curfname = fr->frec_name;
152 // Allocate an IFILE or IMACRO
154 INOBJ * a_inobj(int typ)
160 // Allocate and initialize INOBJ first
162 inobj = malloc(sizeof(INOBJ));
166 f_inobj = f_inobj->in_link;
171 case SRC_IFILE: // Alloc and init an IFILE
173 ifile = malloc(sizeof(IFILE));
177 f_ifile = f_ifile->if_link;
180 inobj->inobj.ifile = ifile;
182 case SRC_IMACRO: // Alloc and init an IMACRO
183 if (f_imacro == NULL)
184 imacro = malloc(sizeof(IMACRO));
188 f_imacro = f_imacro->im_link;
191 inobj->inobj.imacro = imacro;
193 case SRC_IREPT: // Alloc and init an IREPT
194 inobj->inobj.irept = malloc(sizeof(IREPT));
195 DEBUG printf("alloc IREPT\n");
199 // Install INOBJ on top of input stack
200 inobj->in_ifent = ifent; // Record .if context on entry
201 inobj->in_type = (WORD)typ;
202 inobj->in_otok = tok;
203 inobj->in_etok = etok;
204 inobj->in_link = cur_inobj;
212 // Perform macro substitution from 'orig' to 'dest'. Return OK or some error.
213 // A macro reference is in one of two forms:
214 // \name <non-name-character>
216 // A doubled backslash (\\) is compressed to a single backslash (\).
217 // Argument definitions have been pre-tokenized, so we have to turn them back
218 // into text. This means that numbers, in particular, become hex, regardless of
219 // their representation when the macro was invoked. This is a hack.
220 // A label may appear at the beginning of the line:
221 // :<name><whitespace>
222 // (the colon must be in the first column). These labels are stripped before
223 // macro expansion takes place.
225 int ExpandMacro(char * src, char * dest, int destsiz)
228 int questmark; // \? for testing argument existence
229 char mname[128]; // Assume max size of a formal arg name
230 char numbuf[20]; // Buffer for text of CONSTs
233 char ** symbolString;
235 DEBUG { printf("ExM: src=\"%s\"\n", src); }
237 IMACRO * imacro = cur_inobj->inobj.imacro;
238 int macnum = (int)(imacro->im_macro->sattr);
241 char * dst = dest; // Next dest slot
242 char * edst = dest + destsiz - 1; // End + 1(?) of dest buffer
244 // Check for (and skip over) any "label" on the line
250 while (*s != EOS && !(chrtab[*s] & WHITE))
254 s++; // Skip first whitespace
257 // Expand the rest of the line
260 // Copy single character
268 // Do macro expansion
276 case '\\': // \\, \ (collapse to single backslash)
282 case '?': // \? <macro> set `questmark' flag
286 case '#': // \#, number of arguments
287 sprintf(numbuf, "%d", (int)imacro->im_nargs);
289 case '!': // \! size suffix supplied on invocation
290 switch ((int)imacro->im_siz)
292 case SIZN: d = ""; break;
293 case SIZB: d = ".b"; break;
294 case SIZW: d = ".w"; break;
295 case SIZL: d = ".l"; break;
299 case '~': // ==> unique label string Mnnnn...
300 sprintf(numbuf, "M%u", curuniq);
316 return error("missing argument name");
319 // \n ==> argument number 'n', 0..9
320 if (chrtab[*s] & DIGIT)
330 // Get argument name: \name, \{name}
340 while (chrtab[*s] & CTSYM);
345 for(++s; *s != EOS && *s != '}';)
349 return error("missing '}'");
356 // Lookup the argument and copy its (string) value into the
357 // destination string
358 DEBUG printf("argument='%s'\n", mname);
360 if ((arg = lookup(mname, MACARG, macnum)) == NULL)
361 return errors("undefined argument: '%s'", mname);
364 // Convert a string of tokens (terminated with EOL) back into
365 // text. If an argument is out of range (not specified in the
366 // macro invocation) then it is ignored.
367 i = (int)arg->svalue;
369 DEBUG printf("~argnumber=%d (argBase=%u)\n", i, imacro->argBase);
372 if (i < imacro->im_nargs)
377 tk = argPtrs[imacro->argBase + i];
379 tk = imacro->argument[i].token;
380 symbolString = imacro->argument[i].string;
383 // printf("ExM: Preparing to parse argument #%u...\n", i);
390 // 0 if the argument is empty or non-existant,
391 // 1 if the argument is not empty
394 if (tk == NULL || *tk == EOL)
400 *dst++ = (char)(questmark + '0');
404 if (tk != NULL) // arg # is in range, so expand it
408 // Reverse-translation from a token number to a string.
409 // This is a hack. It might be better table-driven.
412 if ((*tk >= KW_D0) && !rdsp && !rgpu)
414 d = regname[(int)*tk++ - KW_D0];
417 else if ((*tk >= KW_R0) && (*tk <= KW_R31))
419 d = riscregname[(int)*tk++ - KW_R0];
428 // d = (char *)*tk++;
431 // This fix should be done for strings too
432 d = symbolString[*tk++];
433 DEBUG printf("ExM: SYMBOL=\"%s\"", d);
438 // d = (char *)*tk++;
441 d = symbolString[*tk++];
462 // Shamus: Changing the format specifier from %lx to %ux caused
463 // the assembler to choke on legitimate code... Need to investigate
464 // this further before changing anything else here!
466 sprintf(numbuf, "$%lx", (LONG)*tk++);
527 *dst++ = (char)*(tk - 1);
532 // If 'd' != NULL, copy string to destination
536 DEBUG printf("d='%s'\n", d);
553 DEBUG { printf("ExM: dst=\"%s\"\n", dest); }
558 DEBUG printf("*** OVERFLOW LINE ***\n%s\n", dest);
559 return fatal("line too long as a result of macro expansion");
564 // Get Next Line of Text from a Macro
568 unsigned source_addr;
570 IMACRO * imacro = cur_inobj->inobj.imacro;
571 // LONG * strp = imacro->im_nextln;
572 struct LineList * strp = imacro->im_nextln;
574 if (strp == NULL) // End-of-macro
577 // imacro->im_nextln = (LONG *)*strp;
578 imacro->im_nextln = strp->next;
579 // ExpandMacro((char *)(strp + 1), imacro->im_lnbuf, LNSIZ);
580 ExpandMacro(strp->line, imacro->im_lnbuf, LNSIZ);
584 if (!strcmp(imacro->im_macro->sname, "mjump") && !mjump_align)
586 // if we need to adjust the alignment of the jump source address to
587 // meet the rules of gpu main execution we need to skip the first nop
588 // of the macro. This is simpler than trying to insert nop's mid macro.
589 source_addr = (orgactive ? orgaddr : sloc);
594 strp = imacro->im_nextln;
599 // imacro->im_nextln = (LONG *)*strp;
600 // ExpandMacro((char *)(strp + 1), imacro->im_lnbuf, LNSIZ);
601 imacro->im_nextln = strp->next;
602 ExpandMacro(strp->line, imacro->im_lnbuf, LNSIZ);
609 return imacro->im_lnbuf;
614 // Get Next Line of Text from a Repeat Block
619 IREPT * irept = cur_inobj->inobj.irept;
620 LONG * strp = irept->ir_nextln; // initial null
622 // Do repeat at end of .rept block's string list
625 DEBUG printf("back-to-top-of-repeat-block count=%d\n", (int)irept->ir_count);
626 irept->ir_nextln = irept->ir_firstln; // copy first line
628 if (irept->ir_count-- == 0)
630 DEBUG printf("end-repeat-block\n");
634 strp = irept->ir_nextln;
637 strcpy(irbuf, (char *)(irept->ir_nextln + 1));
638 DEBUG printf("repeat line='%s'\n", irbuf);
639 irept->ir_nextln = (LONG *)*strp;
646 // Include a Source File used at the Root, and for ".include" Files
648 int include(int handle, char * fname)
656 printf("[include: %s, cfileno=%u]\n", fname, cfileno);
658 // Alloc and initialize include-descriptors
659 inobj = a_inobj(SRC_IFILE);
660 ifile = inobj->inobj.ifile;
662 ifile->ifhandle = handle; // Setup file handle
663 ifile->ifind = ifile->ifcnt = 0; // Setup buffer indices
664 ifile->ifoldlineno = curlineno; // Save old line number
665 ifile->ifoldfname = curfname; // Save old filename
666 ifile->ifno = cfileno; // Save old file number
668 // cfileno = filecount++; // Compute new file number
669 // NB: This *must* be preincrement, we're adding one to the filecount here!
670 cfileno = ++filecount; // Compute NEW file number
671 curfname = strdup(fname); // Set current filename (alloc storage)
672 curlineno = 0; // Start on line zero
674 // Add another file to the file-record
675 fr = (FILEREC *)malloc(sizeof(FILEREC));
676 fr->frec_next = NULL;
677 fr->frec_name = curfname;
680 filerec = fr; // Add first filerec
682 last_fr->frec_next = fr; // Append to list of filerecs
685 DEBUG printf("[include: curfname: %s, cfileno=%u]\n", curfname, cfileno);
692 // Initialize Tokenizer
694 void init_token(void)
697 char * htab = "0123456789abcdefABCDEF"; // Hex character table
699 lnsave = 0; // Don't save lines
700 curfname = ""; // No file, empty filename
701 filecount = (WORD)-1;
702 cfileno = (WORD)-1; // cfileno gets bumped to 0
714 // Initialize hex, "dot" and tolower tables
719 tolowertab[i] = (char)i;
722 for(i=0; htab[i]!=EOS; i++)
723 hextab[htab[i]] = (char)((i < 16) ? i : i - 6);
725 for(i='A'; i<='Z'; i++)
726 tolowertab[i] |= 0x20;
728 // These characters are legal immediately after a period
729 dotxtab['b'] = DOTB; // .b .B .s .S
733 dotxtab['w'] = DOTW; // .w .W
735 dotxtab['l'] = DOTL; // .l .L
737 dotxtab['I'] = DOTI; // .l .L
743 // Pop the Current Input Level
750 INOBJ * inobj = cur_inobj;
754 // Pop IFENT levels until we reach the conditional assembly context we
755 // were at when the input object was entered.
756 while (ifent != inobj->in_ifent)
759 tok = inobj->in_otok; // Restore tok and otok
760 etok = inobj->in_etok;
762 switch (inobj->in_type)
764 case SRC_IFILE: // Pop and release an IFILE
766 printf("[Leaving: %s]\n", curfname);
768 ifile = inobj->inobj.ifile;
769 ifile->if_link = f_ifile;
771 close(ifile->ifhandle); // Close source file
772 if (verb_flag) printf("[fpop (pre): curfname=%s]\n", curfname);
773 curfname = ifile->ifoldfname; // Set current filename
774 if (verb_flag) printf("[fpop (post): curfname=%s]\n", curfname);
775 if (verb_flag) printf("[fpop: (pre) cfileno=%d ifile->ifno=%d]\n", (int)cfileno, (int)ifile->ifno);
776 curlineno = ifile->ifoldlineno; // Set current line#
777 DEBUG printf("cfileno=%d ifile->ifno=%d\n", (int)cfileno, (int)ifile->ifno);
778 cfileno = ifile->ifno; // Restore current file number
779 if (verb_flag) printf("[fpop: (post) cfileno=%d ifile->ifno=%d]\n", (int)cfileno, (int)ifile->ifno);
781 case SRC_IMACRO: // Pop and release an IMACRO
782 imacro = inobj->inobj.imacro;
783 imacro->im_link = f_imacro;
786 case SRC_IREPT: // Pop and release an IREPT
787 DEBUG printf("dealloc IREPT\n");
788 p = inobj->inobj.irept->ir_firstln;
799 cur_inobj = inobj->in_link;
800 inobj->in_link = f_inobj;
809 // Get line from file into buf, return NULL on EOF or ptr to the start of a
816 int readamt = -1; // 0 if last read() yeilded 0 bytes
817 IFILE * fl = cur_inobj->inobj.ifile;
821 // Scan for next end-of-line; handle stupid text formats by treating
822 // \r\n the same as \n. (lone '\r' at end of buffer means we have to
826 d = &fl->ifbuf[fl->ifind];
828 for(p=d; i<j; i++, p++)
830 if (*p == '\r' || *p == '\n')
838 break; // Look for '\n' to eat
840 else if (p[1] == '\n')
854 // Handle hanging lines by ignoring them (Input file is exhausted, no
855 // \r or \n on last line)
856 if (!readamt && fl->ifcnt)
863 // Truncate and return absurdly long lines.
864 if (fl->ifcnt >= QUANTUM)
866 fl->ifbuf[fl->ifind + fl->ifcnt - 1] = '\0';
868 return &fl->ifbuf[fl->ifind];
871 // Relocate what's left of a line to the beginning of the buffer, and
872 // read some more of the file in; return NULL if the buffer's empty and
876 p = &fl->ifbuf[fl->ifind];
877 d = &fl->ifbuf[fl->ifcnt & 1];
879 for(i=0; i<fl->ifcnt; i++)
882 fl->ifind = fl->ifcnt & 1;
885 if ((readamt = read(fl->ifhandle, &fl->ifbuf[fl->ifind + fl->ifcnt], QUANTUM)) < 0)
888 if ((fl->ifcnt += readamt) == 0)
899 char * ln = NULL; // Ptr to current position in line
900 char * p; // Random character ptr
901 TOKEN * tk; // Token-deposit ptr
902 int state = 0; // State for keyword detector
903 int j = 0; // Var for keyword detector
904 char c; // Random char
905 VALUE v; // Random value
906 char * nullspot = NULL; // Spot to clobber for SYMBOL terminatn
907 int stuffnull; // 1:terminate SYMBOL '\0' at *nullspot
909 int stringNum = 0; // Pointer to string locations in tokenized line
913 if (cur_inobj == NULL) // Return EOF if input stack is empty
916 // Get another line of input from the current input source: a file,
917 // a macro, or a repeat-block
918 switch (cur_inobj->in_type)
922 // o bump source line number;
923 // o tag the listing-line with a space;
924 // o kludge lines generated by Alcyon C.
926 if ((ln = getln()) == NULL)
928 if (verb_flag) printf("tokln: Calling fpop() from SRC_IFILE...\n");
929 fpop(); // Pop input level
930 goto retry; // Try for more lines
933 curlineno++; // Bump line number
938 // AS68 compatibility, throw away all lines starting with
939 // back-quotes, tildes, or '*'
940 // On other lines, turn the first '*' into a semi-colon.
941 if (*ln == '`' || *ln == '~' || *ln == '*')
945 for(p=ln; *p!=EOS; p++)
958 // o Handle end-of-macro;
959 // o tag the listing-line with an at (@) sign.
961 if ((ln = getmln()) == NULL)
963 ExitMacro(); // Exit macro (pop args, do fpop(), etc)
964 goto retry; // Try for more lines...
970 // o Handle end-of-repeat-block;
971 // o tag the listing-line with a pound (#) sign.
973 if ((ln = getrln()) == NULL)
975 if (verb_flag) printf("tokln: Calling fpop() from SRC_IREPT...\n");
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
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
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) == '/')))
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.).
1009 // Skip whitespace, handle EOL
1010 while ((int)chrtab[*ln] & WHITE)
1013 // Handle EOL, comment with ';'
1014 if (*ln == EOS || *ln == ';'|| ((*ln == '/') && (*(ln + 1) == '/')))
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.
1024 if (stuffnull) // Terminate old symbol from previous pass
1027 v = 0; // Assume no DOT attrib follows symbol
1029 p = nullspot = ln++; // Nullspot -> start of this symbol
1031 // Find end of symbol (and compute its length)
1032 for(j=1; (int)chrtab[*ln]&CTSYM; j++)
1035 // Handle "DOT" special forms (like ".b") that follow a normal
1036 // symbol or keyword:
1039 *ln++ = EOS; // Terminate symbol
1040 stuffnull = 0; // And never try it again
1042 // Character following the `.' must have a DOT attribute, and
1043 // the chararacter after THAT one must not have a start-symbol
1044 // attribute (to prevent symbols that look like, for example,
1045 // "zingo.barf", which might be a good idea anyway....)
1046 if ((((int)chrtab[*ln] & DOT) == 0) || ((int)dotxtab[*ln] <= 0))
1047 return error("[bwsl] must follow `.' in symbol");
1049 v = (VALUE)dotxtab[*ln++];
1051 if ((int)chrtab[*ln] & CTSYM)
1052 return error("misuse of `.', not allowed in symbols");
1055 // If the symbol is small, check to see if it's really the name of
1059 for(state=0; state>=0;)
1061 j = (int)tolowertab[*p++];
1064 if (kwcheck[j] != state)
1070 if (*p == EOS || p == ln)
1084 //make j = -1 if time, date etc with no preceeding ^^
1085 //defined, referenced, streq, macdef, date and time
1088 case 112: // defined
1089 case 113: // referenced
1098 if (j < 0 || state < 0)
1102 //problem here: nullspot is a char * but TOKEN is a uint32_t. On a 64-bit system,
1103 //this will cause all kinds of mischief.
1105 *tk++ = (TOKEN)nullspot;
1107 string[stringNum] = nullspot;
1118 if (v) // Record attribute token (if any)
1121 if (stuffnull) // Arrange for string termination on next pass
1127 // Handle identity tokens
1134 // Handle multiple-character tokens
1139 case '!': // ! or !=
1149 case '\'': // 'string'
1150 case '\"': // "string"
1154 // More char * stuffing (8 bytes) into the space of 4 (TOKEN).
1155 // Need to figure out how to fix this crap.
1159 string[stringNum] = ln;
1164 for(p=ln; *ln!=EOS && *ln!=c1;)
1173 return(error("unterminated string"));
1202 warn("bad backslash code in string");
1212 return error("unterminated string");
1216 case '$': // $, hex constant
1217 if ((int)chrtab[*ln] & HDIGIT)
1221 while ((int)hextab[*ln] >= 0)
1222 v = (v << 4) + (int)hextab[*ln++];
1226 if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1232 if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1238 if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1251 case '<': // < or << or <> or <=
1270 case ':': // : or ::
1280 case '=': // = or ==
1290 case '>': // > or >> or >=
1305 case '%': // % or binary constant
1306 if (*ln < '0' || *ln > '1')
1314 while (*ln >= '0' && *ln <= '1')
1315 v = (v << 1) + *ln++ - '0';
1319 if ((*(ln + 1) == 'b') || (*(ln + 1) == 'B'))
1325 if ((*(ln + 1) == 'w') || (*(ln + 1) == 'W'))
1331 if ((*(ln + 1) == 'l') || (*(ln + 1) == 'L'))
1340 case '@': // @ or octal constant
1341 if (*ln < '0' || *ln > '7')
1349 while (*ln >= '0' && *ln <= '7')
1350 v = (v << 3) + *ln++ - '0';
1354 if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1360 if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1366 if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1375 case '^': // ^ or ^^ <operator-name>
1382 if (((int)chrtab[*++ln] & STSYM) == 0)
1384 error("invalid symbol following ^^");
1390 while ((int)chrtab[*ln] & CTSYM)
1393 for(state=0; state>=0;)
1395 // Get char, convert to lowercase
1398 if (j >= 'A' && j <= 'Z')
1403 if (kwcheck[j] != state)
1409 if (*p == EOS || p == ln)
1418 if (j < 0 || state < 0)
1420 error("unknown symbol following ^^");
1427 interror(2); // Bad MULTX entry in chrtab
1432 // Handle decimal constant
1437 while ((int)chrtab[*ln] & DIGIT)
1438 v = (v * 10) + *ln++ - '0';
1440 // See if there's a .[bwl] after the constant, & deal with it
1443 if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1449 if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1455 if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1466 // Handle illegal character
1467 return error("illegal character");
1470 // Terminate line of tokens and return "success."
1473 tok = etok; // Set tok to beginning of line
1475 if (stuffnull) // Terminate last SYMBOL
1485 // .GOTO <label> goto directive
1487 // The label is searched for starting from the first line of the current,
1488 // enclosing macro definition. If no enclosing macro exists, an error is
1491 // A label is of the form:
1493 // :<name><whitespace>
1495 // The colon must appear in column 1. The label is stripped prior to macro
1496 // expansion, and is NOT subject to macro expansion. The whitespace may also
1499 //int d_goto(WORD siz) {
1501 int d_goto(WORD unused)
1503 // char * sym; // Label to search for
1504 // LONG * defln; // Macro definition strings
1505 char * s1; // Temps for string comparison
1507 // IMACRO * imacro; // Macro invocation block
1509 // Setup for the search
1511 return error("missing label");
1513 // sym = (char *)tok[1];
1514 char * sym = string[tok[1]];
1517 if (cur_inobj->in_type != SRC_IMACRO)
1518 return error("goto not in macro");
1520 IMACRO * imacro = cur_inobj->inobj.imacro;
1521 // defln = (LONG *)imacro->im_macro->svalue;
1522 struct LineList * defln = imacro->im_macro->lineList;
1524 // Find the label, starting with the first line.
1525 // for(; defln!=NULL; defln=(LONG *)*defln)
1526 for(; defln!=NULL; defln=defln->next)
1528 // if (*(char *)(defln + 1) == ':')
1529 if (defln->line[0] == ':')
1531 // Compare names (sleazo string compare)
1532 // This string compare is not right. Doesn't check for lengths.
1533 #warning "!!! Bad string comparison !!!"
1535 // s2 = (char *)(defln + 1) + 1;
1549 // Found the label, set new macro next-line and return.
1550 if ((*s2 == EOS) || ((int)chrtab[*s2] & WHITE))
1552 imacro->im_nextln = defln;
1558 return error("goto label not found");
1562 void DumpTokenBuffer(void)
1565 printf("Tokens [%X]: ", sloc);
1567 for(t=tokbuf; *t!=EOL; t++)
1571 else if (*t == CONST)
1574 printf("[CONST: $%X]", (uint32_t)*t);
1576 else if (*t == ACONST)
1578 else if (*t == STRING)
1579 // printf("[STRING]");
1582 printf("[STRING:\"%s\"]", string[*t]);
1584 else if (*t == SYMBOL)
1587 printf("[SYMBOL:\"%s\"]", string[*t]);
1591 else if (*t == TKEOF)
1593 else if (*t == DEQUALS)
1594 printf("[DEQUALS]");
1599 else if (*t == DCOLON)
1611 else if (*t == UNMINUS)
1612 printf("[UNMINUS]");
1613 else if (*t == DOTB)
1615 else if (*t == DOTW)
1617 else if (*t == DOTL)
1619 else if (*t == DOTI)
1621 else if (*t == ENDEXPR)
1622 printf("[ENDEXPR]");
1623 else if (*t == CR_DEFINED)
1624 printf("[CR_DEFINED]");
1625 else if (*t == CR_REFERENCED)
1626 printf("[CR_REFERENCED]");
1627 else if (*t == CR_STREQ)
1628 printf("[CR_STREQ]");
1629 else if (*t == CR_MACDEF)
1630 printf("[CR_MACDEF]");
1631 else if (*t == CR_TIME)
1632 printf("[CR_TIME]");
1633 else if (*t == CR_DATE)
1634 printf("[CR_DATE]");
1635 else if (*t >= 0x20 && *t <= 0x2F)
1636 printf("[%c]", (char)*t);
1637 else if (*t >= 0x3A && *t <= 0x3F)
1638 printf("[%c]", (char)*t);
1639 else if (*t >= 0x80 && *t <= 0x87)
1640 printf("[D%u]", ((uint32_t)*t) - 0x80);
1641 else if (*t >= 0x88 && *t <= 0x8F)
1642 printf("[A%u]", ((uint32_t)*t) - 0x88);
1644 printf("[%X:%c]", (uint32_t)*t, (char)*t);
1645 // printf("[%X]", (uint32_t)*t);