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
19 int lnsave; // 1; strcpy() text of current line
20 int curlineno; // Current line number
21 int totlines; // Total # of lines
22 int mjump_align = 0; // mjump alignment flag
23 char lntag; // Line tag
24 char * curfname; // Current filename
25 char tolowertab[128]; // Uppercase ==> lowercase
26 char hextab[128]; // Table of hex values
27 char dotxtab[128]; // Table for ".b", ".s", etc.
28 char irbuf[LNSIZ]; // Text for .rept block line
29 char lnbuf[LNSIZ]; // Text of current line
30 WORD filecount; // Unique file number counter
31 WORD cfileno; // Current file number
32 TOKEN * tok; // Ptr to current token
33 TOKEN * etok; // Ptr past last token in tokbuf[]
34 TOKEN tokeol[1] = {EOL}; // Bailout end-of-line token
35 char * string[TOKBUFSIZE]; // Token buffer string pointer storage
37 // File record, used to maintain a list of every include file ever visited
38 #define FILEREC struct _filerec
48 INOBJ * cur_inobj; // Ptr current input obj (IFILE/IMACRO)
49 static INOBJ * f_inobj; // Ptr list of free INOBJs
50 static IFILE * f_ifile; // Ptr list of free IFILEs
51 static IMACRO * f_imacro; // Ptr list of free IMACROs
53 static TOKEN tokbuf[TOKBUFSIZE]; // Token buffer (stack-like, all files)
56 ILLEG, ILLEG, ILLEG, ILLEG, // NUL SOH STX ETX
57 ILLEG, ILLEG, ILLEG, ILLEG, // EOT ENQ ACK BEL
58 ILLEG, WHITE, ILLEG, ILLEG, // BS HT LF VT
59 WHITE, ILLEG, ILLEG, ILLEG, // FF CR SO SI
61 ILLEG, ILLEG, ILLEG, ILLEG, // DLE DC1 DC2 DC3
62 ILLEG, ILLEG, ILLEG, ILLEG, // DC4 NAK SYN ETB
63 ILLEG, ILLEG, ILLEG, ILLEG, // CAN EM SUB ESC
64 ILLEG, ILLEG, ILLEG, ILLEG, // FS GS RS US
66 WHITE, MULTX, MULTX, SELF, // SP ! " #
67 MULTX+CTSYM, MULTX, SELF, MULTX, // $ % & '
68 SELF, SELF, SELF, SELF, // ( ) * +
69 SELF, SELF, STSYM, SELF, // , - . /
71 DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 0 1
72 DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 2 3
73 DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 4 5
74 DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 6 7
75 DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 8 9
77 MULTX, MULTX, MULTX, STSYM+CTSYM, // < = > ?
79 MULTX, STSYM+CTSYM+HDIGIT, // @ A
80 (char)((BYTE)DOT)+STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT, // B C
81 STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT, // D E
82 STSYM+CTSYM+HDIGIT, STSYM+CTSYM, // F G
83 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, // H I J K
84 (char)((BYTE)DOT)+STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, // L M N O
86 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, // P Q R S
87 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, // T U V W
88 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, SELF, // X Y Z [
89 SELF, SELF, MULTX, STSYM+CTSYM, // \ ] ^ _
91 ILLEG, STSYM+CTSYM+HDIGIT, // ` a
92 (char)((BYTE)DOT)+STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT, // b c
93 STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT, // d e
94 STSYM+CTSYM+HDIGIT, STSYM+CTSYM, // f g
95 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, // h i j k
96 (char)((BYTE)DOT)+STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, // l m n o
98 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, // p q r s
99 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, // t u v w
100 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, SELF, // x y z {
101 SELF, SELF, SELF, ILLEG // | } ~ DEL
104 // Names of registers
105 static char * regname[] = {
106 "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
107 "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
108 "pc", "ssp", "usp", "sr", "ccr"
111 static char * riscregname[] = {
112 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
113 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
114 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
115 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
120 // Make `fnum' the Current `curfname'
122 void setfnum(WORD fnum)
126 for(fr=filerec; fr!=NULL && fnum--; fr=fr->frec_next);
129 curfname = "(*top*)";
131 curfname = fr->frec_name;
136 // Allocate an IFILE or IMACRO
138 INOBJ * a_inobj(int typ)
144 // Allocate and initialize INOBJ first
146 // inobj = (INOBJ *)amem((LONG)sizeof(INOBJ));
147 inobj = (INOBJ *)malloc(sizeof(INOBJ));
151 f_inobj = f_inobj->in_link;
156 case SRC_IFILE: // Alloc and init an IFILE
158 // ifile = (IFILE *)amem((LONG)sizeof(IFILE));
159 ifile = (IFILE *)malloc(sizeof(IFILE));
163 f_ifile = f_ifile->if_link;
166 inobj->inobj.ifile = ifile;
168 case SRC_IMACRO: // Alloc and init an IMACRO
169 if (f_imacro == NULL)
170 // imacro = (IMACRO *)amem((LONG)sizeof(IMACRO));
171 imacro = (IMACRO *)malloc(sizeof(IMACRO));
175 f_imacro = f_imacro->im_link;
178 inobj->inobj.imacro = imacro;
180 case SRC_IREPT: // Alloc and init an IREPT
181 // inobj->inobj.irept = (IREPT *)amem((LONG)sizeof(IREPT));
182 inobj->inobj.irept = (IREPT *)malloc(sizeof(IREPT));
183 DEBUG printf("alloc IREPT\n");
187 // Install INOBJ on top of input stack
188 inobj->in_ifent = ifent; // Record .if context on entry
189 inobj->in_type = (WORD)typ;
190 inobj->in_otok = tok;
191 inobj->in_etok = etok;
192 inobj->in_link = cur_inobj;
200 // Perform macro substitution from 'orig' to 'dest'. Return OK or some error.
201 // A macro reference is in one of two forms:
202 // \name <non-name-character>
204 // A doubled backslash (\\) is compressed to a single backslash (\).
205 // Argument definitions have been pre-tokenized, so we have to turn them back
206 // into text. This means that numbers, in particular, become hex, regardless of
207 // their representation when the macro was invoked. This is a hack.
208 // A label may appear at the beginning of the line:
209 // :<name><whitespace>
210 // (the colon must be in the first column). These labels are stripped before
211 // macro expansion takes place.
213 int mexpand(char * src, char * dest, int destsiz)
217 char * dst; // Next dest slot
218 char * edst; // End+1 of dest buffer
220 int questmark; // \? for testing argument existence
222 char mname[128]; // Assume max size of a formal arg name
226 char numbuf[20]; // Buffer for text of CONSTs
228 imacro = cur_inobj->inobj.imacro;
229 macnum = (int)(imacro->im_macro->sattr);
233 edst = dest + destsiz;
235 // Check for (and skip over) any "label" on the line
240 while (*s != EOS && !(chrtab[*s] & WHITE))
244 s++; // Skip first whitespace
247 // Expand the rest of the line
250 // Copy single character
258 // Do macro expansion
266 case '\\': // \\, \ (collapse to single backslash)
272 case '?': // \? <macro> set `questmark' flag
276 case '#': // \#, number of arguments
277 sprintf(numbuf, "%d", (int)imacro->im_nargs);
279 case '!': // \! size suffix supplied on invocation
280 switch ((int)imacro->im_siz)
282 case SIZN: d = ""; break;
283 case SIZB: d = ".b"; break;
284 case SIZW: d = ".w"; break;
285 case SIZL: d = ".l"; break;
289 case '~': // ==> unique label string Mnnnn...
290 sprintf(numbuf, "M%ud", curuniq);
306 return error("missing argument name");
309 // \n ==> argument number 'n', 0..9
310 if (chrtab[*s] & DIGIT)
320 // Get argument name: \name, \{name}
330 while (chrtab[*s] & CTSYM);
335 for(++s; *s != EOS && *s != '}';)
339 return error("missing '}'");
346 // Lookup the argument and copy its (string) value into the
347 // destination string
348 DEBUG printf("mname='%s'\n", mname);
350 if ((arg = lookup(mname, MACARG, macnum)) == NULL)
351 return errors("undefined argument: '%s'", mname);
354 // Convert a string of tokens (terminated with EOL) back into
355 // text. If an argument is out of range (not specified in the
356 // macro invocation) then it is ignored.
357 i = (int)arg->svalue;
359 DEBUG printf("~argnumber=%d\n", i);
363 if (i < imacro->im_nargs)
367 // 0 if the argument is empty or non-existant,
368 // 1 if the argument is not empty
371 if (tk == NULL || *tk == EOL)
377 *dst++ = (char)(questmark + '0');
381 if (tk != NULL) // arg# is in range, so expand it
385 // Reverse-translation from a token number to a string.
386 // This is a hack. It might be better table-driven.
389 if ((*tk >= KW_D0) && !rdsp && !rgpu)
391 d = regname[(int)*tk++ - KW_D0];
394 else if ((*tk >= KW_R0) && (*tk <= KW_R31))
396 d = riscregname[(int)*tk++ - KW_R0];
428 // Shamus: Changing the format specifier from %lx to %ux caused
429 // the assembler to choke on legitimate code... Need to investigate
430 // this further before changing anything else here!
432 sprintf(numbuf, "$%lx", (LONG)*tk++);
493 *dst++ = (char)*(tk - 1);
498 // If 'd' != NULL, copy string to destination
502 DEBUG printf("d='%s'\n", d);
523 return fatal("line too long as a result of macro expansion");
528 // Get Next Line of Text from a Macro
532 unsigned source_addr;
534 IMACRO * imacro = cur_inobj->inobj.imacro;
535 LONG * strp = imacro->im_nextln;
537 if (strp == NULL) // End-of-macro
540 imacro->im_nextln = (LONG *)*strp;
541 mexpand((char *)(strp + 1), imacro->im_lnbuf, LNSIZ);
543 if (!strcmp(imacro->im_macro->sname, "mjump") && !mjump_align)
545 // if we need to adjust the alignment of the jump source address to
546 // meet the rules of gpu main execution we need to skip the first nop
547 // of the macro. This is simpler than trying to insert nop's mid macro.
548 source_addr = (orgactive) ? orgaddr : sloc;
553 strp = imacro->im_nextln;
558 imacro->im_nextln = (LONG *)*strp;
559 mexpand((char *)(strp + 1), imacro->im_lnbuf, LNSIZ);
565 return imacro->im_lnbuf;
570 // Get Next Line of Text from a Repeat Block
575 IREPT * irept = cur_inobj->inobj.irept;
576 LONG * strp = irept->ir_nextln; // initial null
578 // Do repeat at end of .rept block's string list
581 DEBUG printf("back-to-top-of-repeat-block count=%d\n", (int)irept->ir_count);
582 irept->ir_nextln = irept->ir_firstln; // copy first line
584 if (irept->ir_count-- == 0)
586 DEBUG printf("end-repeat-block\n");
590 strp = irept->ir_nextln; //strp
593 strcpy(irbuf, (char *)(irept->ir_nextln + 1));
594 DEBUG printf("repeat line='%s'\n", irbuf);
595 irept->ir_nextln = (LONG *)*strp;
602 // Include a Source File used at the Root, and for ".include" Files
604 int include(int handle, char * fname)
612 printf("[Including: %s]\n", fname);
614 // Alloc and initialize include-descriptors
615 inobj = a_inobj(SRC_IFILE);
616 ifile = inobj->inobj.ifile;
618 ifile->ifhandle = handle; // Setup file handle
619 ifile->ifind = ifile->ifcnt = 0; // Setup buffer indices
620 ifile->ifoldlineno = curlineno; // Save old line number
621 ifile->ifoldfname = curfname; // Save old filename
622 ifile->ifno = cfileno; // Save old file number
623 cfileno = filecount++; // Compute new file number
624 curfname = strdup(fname); // Set current filename (alloc storage)
625 curlineno = 0; // Start on line zero
627 // Add another file to the file-record
628 // fr = (FILEREC *)amem((LONG)sizeof(FILEREC));
629 fr = (FILEREC *)malloc(sizeof(FILEREC));
630 fr->frec_next = NULL;
631 fr->frec_name = curfname;
634 filerec = fr; // Add first filerec
636 last_fr->frec_next = fr; // Append to list of filerecs
645 // Initialize Tokenizer
647 void init_token(void)
650 char * htab = "0123456789abcdefABCDEF"; // Hex character table
652 lnsave = 0; // Don't save lines
653 curfname = ""; // No file, empty filename
654 filecount = (WORD)-1;
655 cfileno = (WORD)-1; // cfileno gets bumped to 0
667 // Initialize hex, "dot" and tolower tables
672 tolowertab[i] = (char)i;
675 for(i=0; htab[i]!=EOS; i++)
676 hextab[htab[i]] = (char)((i < 16) ? i : i - 6);
678 for(i='A'; i<='Z'; i++)
679 tolowertab[i] |= 0x20;
681 // These characters are legal immediately after a period
682 dotxtab['b'] = DOTB; // .b .B .s .S
686 dotxtab['w'] = DOTW; // .w .W
688 dotxtab['l'] = DOTL; // .l .L
690 dotxtab['I'] = DOTI; // .l .L
696 // Pop the Current Input Level
709 // Pop IFENT levels until we reach the conditional assembly context we
710 // were at when the input object was entered.
711 while (ifent != inobj->in_ifent)
714 tok = inobj->in_otok; // Restore tok and otok
715 etok = inobj->in_etok;
717 switch (inobj->in_type)
719 case SRC_IFILE: // Pop and release an IFILE
721 printf("[Leaving: %s]\n", curfname);
723 ifile = inobj->inobj.ifile;
724 ifile->if_link = f_ifile;
726 close(ifile->ifhandle); // Close source file
727 curfname = ifile->ifoldfname; // Set current filename
728 curlineno = ifile->ifoldlineno; // Set current line#
729 DEBUG printf("cfileno=%d ifile->ifno=%d\n", (int)cfileno, (int)ifile->ifno);
730 cfileno = ifile->ifno; // Restore current file number
732 case SRC_IMACRO: // Pop and release an IMACRO
733 imacro = inobj->inobj.imacro;
734 imacro->im_link = f_imacro;
737 case SRC_IREPT: // Pop and release an IREPT
738 DEBUG printf("dealloc IREPT\n");
739 p = inobj->inobj.irept->ir_firstln;
750 cur_inobj = inobj->in_link;
751 inobj->in_link = f_inobj;
760 // Get line from file into buf, return NULL on EOF or ptr to the start of a
767 int readamt = -1; // 0 if last read() yeilded 0 bytes
768 IFILE * fl = cur_inobj->inobj.ifile;
772 // Scan for next end-of-line; handle stupid text formats by treating
773 // \r\n the same as \n. (lone '\r' at end of buffer means we have to
777 d = &fl->ifbuf[fl->ifind];
779 for(p=d; i<j; i++, p++)
781 if (*p == '\r' || *p == '\n')
789 break; // Look for '\n' to eat
791 else if (p[1] == '\n')
805 // Handle hanging lines by ignoring them (Input file is exhausted, no
806 // \r or \n on last line)
807 if (!readamt && fl->ifcnt)
814 // Truncate and return absurdly long lines.
815 if (fl->ifcnt >= QUANTUM)
817 fl->ifbuf[fl->ifind + fl->ifcnt - 1] = '\0';
819 return &fl->ifbuf[fl->ifind];
822 // Relocate what's left of a line to the beginning of the buffer, and
823 // read some more of the file in; return NULL if the buffer's empty and
827 p = &fl->ifbuf[fl->ifind];
828 d = &fl->ifbuf[fl->ifcnt & 1];
830 for(i=0; i<fl->ifcnt; i++)
833 fl->ifind = fl->ifcnt & 1;
836 if ((readamt = read(fl->ifhandle, &fl->ifbuf[fl->ifind + fl->ifcnt], QUANTUM)) < 0)
839 if ((fl->ifcnt += readamt) == 0)
850 char * ln = NULL; // Ptr to current position in line
851 char * p; // Random character ptr
852 TOKEN * tk; // Token-deposit ptr
853 int state = 0; // State for keyword detector
854 int j = 0; // Var for keyword detector
855 char c; // Random char
856 VALUE v; // Random value
857 char * nullspot = NULL; // Spot to clobber for SYMBOL terminatn
858 int stuffnull; // 1:terminate SYMBOL '\0' at *nullspot
860 int stringNum = 0; // Pointer to string locations in tokenized line
864 if (cur_inobj == NULL) // Return EOF if input stack is empty
867 // Get another line of input from the current input source: a file,
868 // a macro, or a repeat-block
869 switch (cur_inobj->in_type)
873 // o bump source line number;
874 // o tag the listing-line with a space;
875 // o kludge lines generated by Alcyon C.
877 if ((ln = getln()) == NULL)
879 fpop(); // Pop input level
880 goto retry; // Try for more lines
883 curlineno++; // Bump line number
888 // AS68 compatibility, throw away all lines starting with
889 // back-quotes, tildes, or '*'
890 // On other lines, turn the first '*' into a semi-colon.
891 if (*ln == '`' || *ln == '~' || *ln == '*')
895 for(p=ln; *p!=EOS; ++p)
908 // o Handle end-of-macro;
909 // o tag the listing-line with an at (@) sign.
911 if ((ln = getmln()) == NULL)
913 exitmac(); // Exit macro (pop args, do fpop(), etc)
914 goto retry; // Try for more lines...
920 // o Handle end-of-repeat-block;
921 // o tag the listing-line with a pound (#) sign.
923 if ((ln = getrln()) == NULL)
933 // Save text of the line. We only do this during listings and within
934 // macro-type blocks, since it is expensive to unconditionally copy every
939 // General house-keeping
940 tok = tokeol; // Set "tok" to EOL in case of error
941 tk = etok; // Reset token ptr
942 stuffnull = 0; // Don't stuff nulls
943 totlines++; // Bump total #lines assembled
945 // See if the entire line is a comment. This is a win if the programmer
946 // puts in lots of comments
947 if (*ln == '*' || *ln == ';' || ((*ln == '/') && (*(ln + 1) == '/')))
950 // Main tokenization loop;
951 // o skip whitespace;
952 // o handle end-of-line;
954 // o handle single-character tokens (operators, etc.);
955 // o handle multiple-character tokens (constants, strings, etc.).
958 // Skip whitespace, handle EOL
959 while ((int)chrtab[*ln] & WHITE)
962 // Handle EOL, comment with ';'
963 if (*ln == EOS || *ln == ';'|| ((*ln == '/') && (*(ln + 1) == '/')))
966 // Handle start of symbol. Symbols are null-terminated in place. The
967 // termination is always one symbol behind, since there may be no place
968 // for a null in the case that an operator immediately follows the name.
973 if (stuffnull) // Terminate old symbol
976 v = 0; // Assume no DOT attrib follows symbol
978 p = nullspot = ln++; // Nullspot -> start of this symbol
980 // Find end of symbol (and compute its length)
981 for(j=1; (int)chrtab[*ln]&CTSYM; j++)
984 // Handle "DOT" special forms (like ".b") that follow a normal
985 // symbol or keyword:
988 *ln++ = EOS; // Terminate symbol
989 stuffnull = 0; // And never try it again
991 // Character following the `.' must have a DOT attribute, and
992 // the chararacter after THAT one must not have a start-symbol
993 // attribute (to prevent symbols that look like, for example,
994 // "zingo.barf", which might be a good idea anyway....)
995 if ((((int)chrtab[*ln] & DOT) == 0) || ((int)dotxtab[*ln] <= 0))
996 return error("[bwsl] must follow `.' in symbol");
998 v = (VALUE)dotxtab[*ln++];
1000 if ((int)chrtab[*ln] & CTSYM)
1001 return error("misuse of `.', not allowed in symbols");
1004 // If the symbol is small, check to see if it's really the name of
1008 for(state=0; state>=0;)
1010 j = (int)tolowertab[*p++];
1013 if (kwcheck[j] != state)
1019 if (*p == EOS || p == ln)
1033 //make j = -1 if time, date etc with no preceeding ^^
1034 //defined, referenced, streq, macdef, date and time
1037 case 112: // defined
1038 case 113: // referenced
1047 if (j < 0 || state < 0)
1051 //problem here: nullspot is a char * but TOKEN is a uint32_t. On a 64-bit system,
1052 //this will cause all kinds of mischief.
1053 *tk++ = (TOKEN)nullspot;
1061 if (v) // Record attribute token (if any)
1064 if (stuffnull) // Arrange for string termination
1070 // Handle identity tokens
1077 // Handle multiple-character tokens
1082 case '!': // ! or !=
1092 case '\'': // 'string'
1093 case '\"': // "string"
1097 // More char * stuffing (8 bytes) into the space of 4 (TOKEN).
1098 // Need to figure out how to fix this crap.
1101 for(p=ln; *ln!=EOS && *ln!=c1;)
1110 return(error("unterminated string"));
1139 warn("bad backslash code in string");
1149 return error("unterminated string");
1153 case '$': // $, hex constant
1154 if ((int)chrtab[*ln] & HDIGIT)
1158 while ((int)hextab[*ln] >= 0)
1159 v = (v << 4) + (int)hextab[*ln++];
1163 if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1169 if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1175 if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1188 case '<': // < or << or <> or <=
1207 case ':': // : or ::
1217 case '=': // = or ==
1227 case '>': // > or >> or >=
1242 case '%': // % or binary constant
1243 if (*ln < '0' || *ln > '1')
1251 while (*ln >= '0' && *ln <= '1')
1252 v = (v << 1) + *ln++ - '0';
1256 if ((*(ln + 1) == 'b') || (*(ln + 1) == 'B'))
1262 if ((*(ln + 1) == 'w') || (*(ln + 1) == 'W'))
1268 if ((*(ln + 1) == 'l') || (*(ln + 1) == 'L'))
1277 case '@': // @ or octal constant
1278 if (*ln < '0' || *ln > '7')
1286 while (*ln >= '0' && *ln <= '7')
1287 v = (v << 3) + *ln++ - '0';
1291 if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1297 if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1303 if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1312 case '^': // ^ or ^^ <operator-name>
1319 if (((int)chrtab[*++ln] & STSYM) == 0)
1321 error("invalid symbol following ^^");
1327 while ((int)chrtab[*ln] & CTSYM)
1330 for(state=0; state>=0;)
1332 // Get char, convert to lowercase
1335 if (j >= 'A' && j <= 'Z')
1340 if (kwcheck[j] != state)
1346 if (*p == EOS || p == ln)
1355 if (j < 0 || state < 0)
1357 error("unknown symbol following ^^");
1364 interror(2); // Bad MULTX entry in chrtab
1369 // Handle decimal constant
1374 while ((int)chrtab[*ln] & DIGIT)
1375 v = (v * 10) + *ln++ - '0';
1377 // See if there's a .[bwl] after the constant, & deal with it
1380 if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1386 if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1392 if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1403 // Handle illegal character
1404 return error("illegal character");
1407 // Terminate line of tokens and return "success."
1410 tok = etok; // Set tok to beginning of line
1412 if (stuffnull) // Terminate last SYMBOL
1422 // .GOTO <label> goto directive
1424 // The label is searched for starting from the first line of the current,
1425 // enclosing macro definition. If no enclosing macro exists, an error is
1428 // A label is of the form:
1430 // :<name><whitespace>
1432 // The colon must appear in column 1. The label is stripped prior to macro
1433 // expansion, and is NOT subject to macro expansion. The whitespace may also
1436 //int d_goto(WORD siz) {
1439 char * sym; // Label to search for
1440 LONG * defln; // Macro definition strings
1441 char * s1; // Temps for string comparison
1443 IMACRO * imacro; // Macro invocation block
1445 // Setup for the search
1447 return error("missing label");
1449 sym = (char *)tok[1];
1452 if (cur_inobj->in_type != SRC_IMACRO)
1453 return error("goto not in macro");
1455 imacro = cur_inobj->inobj.imacro;
1456 defln = (LONG *)imacro->im_macro->svalue;
1458 // Find the label, starting with the first line.
1459 for(; defln!=NULL; defln=(LONG *)*defln)
1461 if (*(char *)(defln + 1) == ':')
1463 // Compare names (sleazo string compare)
1465 s2 = (char *)(defln + 1) + 1;
1478 // Found the label, set new macro next-line and return.
1479 if ((*s2 == EOS) || ((int)chrtab[*s2] & WHITE))
1481 imacro->im_nextln = defln;
1487 return error("goto label not found");
1490 void DumpTokenBuffer(void)
1495 for(t=tokbuf; *t!=EOL; t++)
1499 else if (*t == CONST)
1502 printf("[CONST: $%X]", (uint32_t)*t);
1504 else if (*t == ACONST)
1506 else if (*t == STRING)
1508 else if (*t == SYMBOL)
1511 printf("[SYMBOL:\"%s\"]", (char *)*t);
1515 else if (*t == TKEOF)
1517 else if (*t == DEQUALS)
1518 printf("[DEQUALS]");
1523 else if (*t == DCOLON)
1535 else if (*t == UNMINUS)
1536 printf("[UNMINUS]");
1537 else if (*t == DOTB)
1539 else if (*t == DOTW)
1541 else if (*t == DOTL)
1543 else if (*t == DOTI)
1545 else if (*t == ENDEXPR)
1546 printf("[ENDEXPR]");
1547 else if (*t == CR_DEFINED)
1548 printf("[CR_DEFINED]");
1549 else if (*t == CR_REFERENCED)
1550 printf("[CR_REFERENCED]");
1551 else if (*t == CR_STREQ)
1552 printf("[CR_STREQ]");
1553 else if (*t == CR_MACDEF)
1554 printf("[CR_MACDEF]");
1555 else if (*t == CR_TIME)
1556 printf("[CR_TIME]");
1557 else if (*t == CR_DATE)
1558 printf("[CR_DATE]");
1559 else if (*t >= 0x20 && *t <= 0x2F)
1560 printf("[%c]", (char)*t);
1561 else if (*t >= 0x80 && *t <= 0x87)
1562 printf("[D%u]", ((uint32_t)*t) - 0x80);
1563 else if (*t >= 0x88 && *t <= 0x8F)
1564 printf("[A%u]", ((uint32_t)*t) - 0x88);
1566 // printf("[%X:%c]", (uint32_t)*t, (char)*t);
1567 printf("[%X]", (uint32_t)*t);