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*2]; // 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"
119 // Removing this, provided it doesn't cause unwanted side-effects :-P
122 // Make `fnum' the Current `curfname'
123 // NOTE: This is currently only called from error() in error.c
125 void setfnum(WORD fnum)
128 // NOTE: fnum is ZERO based, this can cause problems if you're not careful!
129 FILEREC * fr = filerec;
131 DEBUG printf("[setfnum: fnum=%u]\n", fnum);
133 // Advance to the correct record...
134 while (fr != NULL && fnum != 0)
141 curfname = "(*top*)";
143 curfname = fr->frec_name;
145 DEBUG printf("[setfnum: curfname=%s]\n", curfname);
147 // Check for absolute top filename (this should never happen)
150 curfname = "(*top*)";
154 FILEREC * fr = filerec;
156 // Advance to the correct record...
157 while (fr != NULL && fnum != 0)
163 // Check for file # record not found (this should never happen either)
166 curfname = "(*NOT FOUND*)";
170 curfname = fr->frec_name;
177 // Allocate an IFILE or IMACRO
179 INOBJ * a_inobj(int typ)
185 // Allocate and initialize INOBJ first
187 inobj = malloc(sizeof(INOBJ));
191 f_inobj = f_inobj->in_link;
196 case SRC_IFILE: // Alloc and init an IFILE
198 ifile = malloc(sizeof(IFILE));
202 f_ifile = f_ifile->if_link;
205 inobj->inobj.ifile = ifile;
207 case SRC_IMACRO: // Alloc and init an IMACRO
208 if (f_imacro == NULL)
209 imacro = malloc(sizeof(IMACRO));
213 f_imacro = f_imacro->im_link;
216 inobj->inobj.imacro = imacro;
218 case SRC_IREPT: // Alloc and init an IREPT
219 inobj->inobj.irept = malloc(sizeof(IREPT));
220 DEBUG printf("alloc IREPT\n");
224 // Install INOBJ on top of input stack
225 inobj->in_ifent = ifent; // Record .if context on entry
226 inobj->in_type = (WORD)typ;
227 inobj->in_otok = tok;
228 inobj->in_etok = etok;
229 inobj->in_link = cur_inobj;
237 // Perform macro substitution from 'orig' to 'dest'. Return OK or some error.
238 // A macro reference is in one of two forms:
239 // \name <non-name-character>
241 // A doubled backslash (\\) is compressed to a single backslash (\).
242 // Argument definitions have been pre-tokenized, so we have to turn them back
243 // into text. This means that numbers, in particular, become hex, regardless of
244 // their representation when the macro was invoked. This is a hack.
245 // A label may appear at the beginning of the line:
246 // :<name><whitespace>
247 // (the colon must be in the first column). These labels are stripped before
248 // macro expansion takes place.
250 int ExpandMacro(char * src, char * dest, int destsiz)
253 int questmark; // \? for testing argument existence
254 char mname[128]; // Assume max size of a formal arg name
255 char numbuf[20]; // Buffer for text of CONSTs
258 char ** symbolString;
260 DEBUG { printf("ExM: src=\"%s\"\n", src); }
262 IMACRO * imacro = cur_inobj->inobj.imacro;
263 int macnum = (int)(imacro->im_macro->sattr);
266 char * dst = dest; // Next dest slot
267 char * edst = dest + destsiz - 1; // End + 1(?) of dest buffer
269 // Check for (and skip over) any "label" on the line
275 while (*s != EOS && !(chrtab[*s] & WHITE))
279 s++; // Skip first whitespace
282 // Expand the rest of the line
285 // Copy single character
293 // Do macro expansion
301 case '\\': // \\, \ (collapse to single backslash)
307 case '?': // \? <macro> set `questmark' flag
311 case '#': // \#, number of arguments
312 sprintf(numbuf, "%d", (int)imacro->im_nargs);
314 case '!': // \! size suffix supplied on invocation
315 switch ((int)imacro->im_siz)
317 case SIZN: d = ""; break;
318 case SIZB: d = ".b"; break;
319 case SIZW: d = ".w"; break;
320 case SIZL: d = ".l"; break;
324 case '~': // ==> unique label string Mnnnn...
325 sprintf(numbuf, "M%u", curuniq);
341 return error("missing argument name");
344 // \n ==> argument number 'n', 0..9
345 if (chrtab[*s] & DIGIT)
355 // Get argument name: \name, \{name}
365 while (chrtab[*s] & CTSYM);
370 for(++s; *s != EOS && *s != '}';)
374 return error("missing '}'");
381 // Lookup the argument and copy its (string) value into the
382 // destination string
383 DEBUG printf("argument='%s'\n", mname);
385 if ((arg = lookup(mname, MACARG, macnum)) == NULL)
386 return errors("undefined argument: '%s'", mname);
389 // Convert a string of tokens (terminated with EOL) back into
390 // text. If an argument is out of range (not specified in the
391 // macro invocation) then it is ignored.
392 i = (int)arg->svalue;
394 DEBUG printf("~argnumber=%d (argBase=%u)\n", i, imacro->argBase);
397 if (i < imacro->im_nargs)
402 tk = argPtrs[imacro->argBase + i];
404 tk = imacro->argument[i].token;
405 symbolString = imacro->argument[i].string;
408 // printf("ExM: Preparing to parse argument #%u...\n", i);
415 // 0 if the argument is empty or non-existant,
416 // 1 if the argument is not empty
419 if (tk == NULL || *tk == EOL)
425 *dst++ = (char)(questmark + '0');
429 if (tk != NULL) // arg # is in range, so expand it
433 // Reverse-translation from a token number to a string.
434 // This is a hack. It might be better table-driven.
437 if ((*tk >= KW_D0) && !rdsp && !rgpu)
439 d = regname[(int)*tk++ - KW_D0];
442 else if ((*tk >= KW_R0) && (*tk <= KW_R31))
444 d = riscregname[(int)*tk++ - KW_R0];
453 // d = (char *)*tk++;
456 // This fix should be done for strings too
457 d = symbolString[*tk++];
458 DEBUG printf("ExM: SYMBOL=\"%s\"", d);
463 // d = (char *)*tk++;
466 d = symbolString[*tk++];
487 // Shamus: Changing the format specifier from %lx to %ux caused
488 // the assembler to choke on legitimate code... Need to investigate
489 // this further before changing anything else here!
491 sprintf(numbuf, "$%lx", (LONG)*tk++);
552 *dst++ = (char)*(tk - 1);
557 // If 'd' != NULL, copy string to destination
561 DEBUG printf("d='%s'\n", d);
578 DEBUG { printf("ExM: dst=\"%s\"\n", dest); }
583 DEBUG printf("*** OVERFLOW LINE ***\n%s\n", dest);
584 return fatal("line too long as a result of macro expansion");
589 // Get Next Line of Text from a Macro
593 unsigned source_addr;
595 IMACRO * imacro = cur_inobj->inobj.imacro;
596 // LONG * strp = imacro->im_nextln;
597 struct LineList * strp = imacro->im_nextln;
599 if (strp == NULL) // End-of-macro
602 // imacro->im_nextln = (LONG *)*strp;
603 imacro->im_nextln = strp->next;
604 // ExpandMacro((char *)(strp + 1), imacro->im_lnbuf, LNSIZ);
605 ExpandMacro(strp->line, imacro->im_lnbuf, LNSIZ);
607 if (!strcmp(imacro->im_macro->sname, "mjump") && !mjump_align)
609 // if we need to adjust the alignment of the jump source address to
610 // meet the rules of gpu main execution we need to skip the first nop
611 // of the macro. This is simpler than trying to insert nop's mid macro.
612 source_addr = (orgactive ? orgaddr : sloc);
617 strp = imacro->im_nextln;
622 // imacro->im_nextln = (LONG *)*strp;
623 // ExpandMacro((char *)(strp + 1), imacro->im_lnbuf, LNSIZ);
624 imacro->im_nextln = strp->next;
625 ExpandMacro(strp->line, imacro->im_lnbuf, LNSIZ);
631 return imacro->im_lnbuf;
636 // Get Next Line of Text from a Repeat Block
641 IREPT * irept = cur_inobj->inobj.irept;
642 LONG * strp = irept->ir_nextln; // initial null
644 // Do repeat at end of .rept block's string list
647 DEBUG printf("back-to-top-of-repeat-block count=%d\n", (int)irept->ir_count);
648 irept->ir_nextln = irept->ir_firstln; // copy first line
650 if (irept->ir_count-- == 0)
652 DEBUG printf("end-repeat-block\n");
656 strp = irept->ir_nextln; //strp
659 strcpy(irbuf, (char *)(irept->ir_nextln + 1));
660 DEBUG printf("repeat line='%s'\n", irbuf);
661 irept->ir_nextln = (LONG *)*strp;
668 // Include a Source File used at the Root, and for ".include" Files
670 int include(int handle, char * fname)
678 printf("[include: %s, cfileno=%u]\n", fname, cfileno);
680 // Alloc and initialize include-descriptors
681 inobj = a_inobj(SRC_IFILE);
682 ifile = inobj->inobj.ifile;
684 ifile->ifhandle = handle; // Setup file handle
685 ifile->ifind = ifile->ifcnt = 0; // Setup buffer indices
686 ifile->ifoldlineno = curlineno; // Save old line number
687 ifile->ifoldfname = curfname; // Save old filename
688 ifile->ifno = cfileno; // Save old file number
689 // cfileno = filecount++; // Compute new file number
690 cfileno = ++filecount; // Compute new file number
691 curfname = strdup(fname); // Set current filename (alloc storage)
692 curlineno = 0; // Start on line zero
694 // Add another file to the file-record
695 // fr = (FILEREC *)amem((LONG)sizeof(FILEREC));
696 fr = (FILEREC *)malloc(sizeof(FILEREC));
697 fr->frec_next = NULL;
698 fr->frec_name = curfname;
701 filerec = fr; // Add first filerec
703 last_fr->frec_next = fr; // Append to list of filerecs
708 printf("[include: curfname: %s, cfileno=%u]\n", curfname, cfileno);
715 // Initialize Tokenizer
717 void init_token(void)
720 char * htab = "0123456789abcdefABCDEF"; // Hex character table
722 lnsave = 0; // Don't save lines
723 curfname = ""; // No file, empty filename
724 filecount = (WORD)-1;
725 cfileno = (WORD)-1; // cfileno gets bumped to 0
737 // Initialize hex, "dot" and tolower tables
742 tolowertab[i] = (char)i;
745 for(i=0; htab[i]!=EOS; i++)
746 hextab[htab[i]] = (char)((i < 16) ? i : i - 6);
748 for(i='A'; i<='Z'; i++)
749 tolowertab[i] |= 0x20;
751 // These characters are legal immediately after a period
752 dotxtab['b'] = DOTB; // .b .B .s .S
756 dotxtab['w'] = DOTW; // .w .W
758 dotxtab['l'] = DOTL; // .l .L
760 dotxtab['I'] = DOTI; // .l .L
766 // Pop the Current Input Level
773 INOBJ * inobj = cur_inobj;
777 // Pop IFENT levels until we reach the conditional assembly context we
778 // were at when the input object was entered.
779 while (ifent != inobj->in_ifent)
782 tok = inobj->in_otok; // Restore tok and otok
783 etok = inobj->in_etok;
785 switch (inobj->in_type)
787 case SRC_IFILE: // Pop and release an IFILE
789 printf("[Leaving: %s]\n", curfname);
791 ifile = inobj->inobj.ifile;
792 ifile->if_link = f_ifile;
794 close(ifile->ifhandle); // Close source file
795 if (verb_flag) printf("[fpop (pre): curfname=%s]\n", curfname);
796 curfname = ifile->ifoldfname; // Set current filename
797 if (verb_flag) printf("[fpop (post): curfname=%s]\n", curfname);
798 curlineno = ifile->ifoldlineno; // Set current line#
799 DEBUG printf("cfileno=%d ifile->ifno=%d\n", (int)cfileno, (int)ifile->ifno);
800 if (verb_flag) printf("[fpop: cfileno=%d ifile->ifno=%d]\n", (int)cfileno, (int)ifile->ifno);
801 cfileno = ifile->ifno; // Restore current file number
803 case SRC_IMACRO: // Pop and release an IMACRO
804 imacro = inobj->inobj.imacro;
805 imacro->im_link = f_imacro;
808 case SRC_IREPT: // Pop and release an IREPT
809 DEBUG printf("dealloc IREPT\n");
810 p = inobj->inobj.irept->ir_firstln;
821 cur_inobj = inobj->in_link;
822 inobj->in_link = f_inobj;
831 // Get line from file into buf, return NULL on EOF or ptr to the start of a
838 int readamt = -1; // 0 if last read() yeilded 0 bytes
839 IFILE * fl = cur_inobj->inobj.ifile;
843 // Scan for next end-of-line; handle stupid text formats by treating
844 // \r\n the same as \n. (lone '\r' at end of buffer means we have to
848 d = &fl->ifbuf[fl->ifind];
850 for(p=d; i<j; i++, p++)
852 if (*p == '\r' || *p == '\n')
860 break; // Look for '\n' to eat
862 else if (p[1] == '\n')
876 // Handle hanging lines by ignoring them (Input file is exhausted, no
877 // \r or \n on last line)
878 if (!readamt && fl->ifcnt)
885 // Truncate and return absurdly long lines.
886 if (fl->ifcnt >= QUANTUM)
888 fl->ifbuf[fl->ifind + fl->ifcnt - 1] = '\0';
890 return &fl->ifbuf[fl->ifind];
893 // Relocate what's left of a line to the beginning of the buffer, and
894 // read some more of the file in; return NULL if the buffer's empty and
898 p = &fl->ifbuf[fl->ifind];
899 d = &fl->ifbuf[fl->ifcnt & 1];
901 for(i=0; i<fl->ifcnt; i++)
904 fl->ifind = fl->ifcnt & 1;
907 if ((readamt = read(fl->ifhandle, &fl->ifbuf[fl->ifind + fl->ifcnt], QUANTUM)) < 0)
910 if ((fl->ifcnt += readamt) == 0)
921 char * ln = NULL; // Ptr to current position in line
922 char * p; // Random character ptr
923 TOKEN * tk; // Token-deposit ptr
924 int state = 0; // State for keyword detector
925 int j = 0; // Var for keyword detector
926 char c; // Random char
927 VALUE v; // Random value
928 char * nullspot = NULL; // Spot to clobber for SYMBOL terminatn
929 int stuffnull; // 1:terminate SYMBOL '\0' at *nullspot
931 int stringNum = 0; // Pointer to string locations in tokenized line
935 if (cur_inobj == NULL) // Return EOF if input stack is empty
938 // Get another line of input from the current input source: a file,
939 // a macro, or a repeat-block
940 switch (cur_inobj->in_type)
944 // o bump source line number;
945 // o tag the listing-line with a space;
946 // o kludge lines generated by Alcyon C.
948 if ((ln = getln()) == NULL)
950 fpop(); // Pop input level
951 goto retry; // Try for more lines
954 curlineno++; // Bump line number
959 // AS68 compatibility, throw away all lines starting with
960 // back-quotes, tildes, or '*'
961 // On other lines, turn the first '*' into a semi-colon.
962 if (*ln == '`' || *ln == '~' || *ln == '*')
966 for(p=ln; *p!=EOS; p++)
979 // o Handle end-of-macro;
980 // o tag the listing-line with an at (@) sign.
982 if ((ln = getmln()) == NULL)
984 ExitMacro(); // Exit macro (pop args, do fpop(), etc)
985 goto retry; // Try for more lines...
991 // o Handle end-of-repeat-block;
992 // o tag the listing-line with a pound (#) sign.
994 if ((ln = getrln()) == NULL)
1004 // Save text of the line. We only do this during listings and within
1005 // macro-type blocks, since it is expensive to unconditionally copy every
1010 // General house-keeping
1011 tok = tokeol; // Set "tok" to EOL in case of error
1012 tk = etok; // Reset token ptr
1013 stuffnull = 0; // Don't stuff nulls
1014 totlines++; // Bump total #lines assembled
1016 // See if the entire line is a comment. This is a win if the programmer
1017 // puts in lots of comments
1018 if (*ln == '*' || *ln == ';' || ((*ln == '/') && (*(ln + 1) == '/')))
1021 // Main tokenization loop;
1022 // o skip whitespace;
1023 // o handle end-of-line;
1024 // o handle symbols;
1025 // o handle single-character tokens (operators, etc.);
1026 // o handle multiple-character tokens (constants, strings, etc.).
1029 // Skip whitespace, handle EOL
1030 while ((int)chrtab[*ln] & WHITE)
1033 // Handle EOL, comment with ';'
1034 if (*ln == EOS || *ln == ';'|| ((*ln == '/') && (*(ln + 1) == '/')))
1037 // Handle start of symbol. Symbols are null-terminated in place. The
1038 // termination is always one symbol behind, since there may be no place
1039 // for a null in the case that an operator immediately follows the name.
1044 if (stuffnull) // Terminate old symbol from previous pass
1047 v = 0; // Assume no DOT attrib follows symbol
1049 p = nullspot = ln++; // Nullspot -> start of this symbol
1051 // Find end of symbol (and compute its length)
1052 for(j=1; (int)chrtab[*ln]&CTSYM; j++)
1055 // Handle "DOT" special forms (like ".b") that follow a normal
1056 // symbol or keyword:
1059 *ln++ = EOS; // Terminate symbol
1060 stuffnull = 0; // And never try it again
1062 // Character following the `.' must have a DOT attribute, and
1063 // the chararacter after THAT one must not have a start-symbol
1064 // attribute (to prevent symbols that look like, for example,
1065 // "zingo.barf", which might be a good idea anyway....)
1066 if ((((int)chrtab[*ln] & DOT) == 0) || ((int)dotxtab[*ln] <= 0))
1067 return error("[bwsl] must follow `.' in symbol");
1069 v = (VALUE)dotxtab[*ln++];
1071 if ((int)chrtab[*ln] & CTSYM)
1072 return error("misuse of `.', not allowed in symbols");
1075 // If the symbol is small, check to see if it's really the name of
1079 for(state=0; state>=0;)
1081 j = (int)tolowertab[*p++];
1084 if (kwcheck[j] != state)
1090 if (*p == EOS || p == ln)
1104 //make j = -1 if time, date etc with no preceeding ^^
1105 //defined, referenced, streq, macdef, date and time
1108 case 112: // defined
1109 case 113: // referenced
1118 if (j < 0 || state < 0)
1122 //problem here: nullspot is a char * but TOKEN is a uint32_t. On a 64-bit system,
1123 //this will cause all kinds of mischief.
1125 *tk++ = (TOKEN)nullspot;
1127 string[stringNum] = nullspot;
1138 if (v) // Record attribute token (if any)
1141 if (stuffnull) // Arrange for string termination on next pass
1147 // Handle identity tokens
1154 // Handle multiple-character tokens
1159 case '!': // ! or !=
1169 case '\'': // 'string'
1170 case '\"': // "string"
1174 // More char * stuffing (8 bytes) into the space of 4 (TOKEN).
1175 // Need to figure out how to fix this crap.
1179 string[stringNum] = ln;
1184 for(p=ln; *ln!=EOS && *ln!=c1;)
1193 return(error("unterminated string"));
1222 warn("bad backslash code in string");
1232 return error("unterminated string");
1236 case '$': // $, hex constant
1237 if ((int)chrtab[*ln] & HDIGIT)
1241 while ((int)hextab[*ln] >= 0)
1242 v = (v << 4) + (int)hextab[*ln++];
1246 if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1252 if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1258 if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1271 case '<': // < or << or <> or <=
1290 case ':': // : or ::
1300 case '=': // = or ==
1310 case '>': // > or >> or >=
1325 case '%': // % or binary constant
1326 if (*ln < '0' || *ln > '1')
1334 while (*ln >= '0' && *ln <= '1')
1335 v = (v << 1) + *ln++ - '0';
1339 if ((*(ln + 1) == 'b') || (*(ln + 1) == 'B'))
1345 if ((*(ln + 1) == 'w') || (*(ln + 1) == 'W'))
1351 if ((*(ln + 1) == 'l') || (*(ln + 1) == 'L'))
1360 case '@': // @ or octal constant
1361 if (*ln < '0' || *ln > '7')
1369 while (*ln >= '0' && *ln <= '7')
1370 v = (v << 3) + *ln++ - '0';
1374 if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1380 if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1386 if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1395 case '^': // ^ or ^^ <operator-name>
1402 if (((int)chrtab[*++ln] & STSYM) == 0)
1404 error("invalid symbol following ^^");
1410 while ((int)chrtab[*ln] & CTSYM)
1413 for(state=0; state>=0;)
1415 // Get char, convert to lowercase
1418 if (j >= 'A' && j <= 'Z')
1423 if (kwcheck[j] != state)
1429 if (*p == EOS || p == ln)
1438 if (j < 0 || state < 0)
1440 error("unknown symbol following ^^");
1447 interror(2); // Bad MULTX entry in chrtab
1452 // Handle decimal constant
1457 while ((int)chrtab[*ln] & DIGIT)
1458 v = (v * 10) + *ln++ - '0';
1460 // See if there's a .[bwl] after the constant, & deal with it
1463 if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1469 if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1475 if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1486 // Handle illegal character
1487 return error("illegal character");
1490 // Terminate line of tokens and return "success."
1493 tok = etok; // Set tok to beginning of line
1495 if (stuffnull) // Terminate last SYMBOL
1505 // .GOTO <label> goto directive
1507 // The label is searched for starting from the first line of the current,
1508 // enclosing macro definition. If no enclosing macro exists, an error is
1511 // A label is of the form:
1513 // :<name><whitespace>
1515 // The colon must appear in column 1. The label is stripped prior to macro
1516 // expansion, and is NOT subject to macro expansion. The whitespace may also
1519 //int d_goto(WORD siz) {
1521 int d_goto(WORD unused)
1523 // char * sym; // Label to search for
1524 // LONG * defln; // Macro definition strings
1525 char * s1; // Temps for string comparison
1527 // IMACRO * imacro; // Macro invocation block
1529 // Setup for the search
1531 return error("missing label");
1533 // sym = (char *)tok[1];
1534 char * sym = string[tok[1]];
1537 if (cur_inobj->in_type != SRC_IMACRO)
1538 return error("goto not in macro");
1540 IMACRO * imacro = cur_inobj->inobj.imacro;
1541 // defln = (LONG *)imacro->im_macro->svalue;
1542 struct LineList * defln = imacro->im_macro->lineList;
1544 // Find the label, starting with the first line.
1545 // for(; defln!=NULL; defln=(LONG *)*defln)
1546 for(; defln!=NULL; defln=defln->next)
1548 // if (*(char *)(defln + 1) == ':')
1549 if (defln->line[0] == ':')
1551 // Compare names (sleazo string compare)
1552 // This string compare is not right. Doesn't check for lengths.
1553 #warning "!!! Bad string comparison !!!"
1555 // s2 = (char *)(defln + 1) + 1;
1569 // Found the label, set new macro next-line and return.
1570 if ((*s2 == EOS) || ((int)chrtab[*s2] & WHITE))
1572 imacro->im_nextln = defln;
1578 return error("goto label not found");
1581 void DumpTokenBuffer(void)
1584 printf("Tokens [%X]: ", sloc);
1586 for(t=tokbuf; *t!=EOL; t++)
1590 else if (*t == CONST)
1593 printf("[CONST: $%X]", (uint32_t)*t);
1595 else if (*t == ACONST)
1597 else if (*t == STRING)
1598 // printf("[STRING]");
1601 printf("[STRING:\"%s\"]", string[*t]);
1603 else if (*t == SYMBOL)
1606 printf("[SYMBOL:\"%s\"]", string[*t]);
1610 else if (*t == TKEOF)
1612 else if (*t == DEQUALS)
1613 printf("[DEQUALS]");
1618 else if (*t == DCOLON)
1630 else if (*t == UNMINUS)
1631 printf("[UNMINUS]");
1632 else if (*t == DOTB)
1634 else if (*t == DOTW)
1636 else if (*t == DOTL)
1638 else if (*t == DOTI)
1640 else if (*t == ENDEXPR)
1641 printf("[ENDEXPR]");
1642 else if (*t == CR_DEFINED)
1643 printf("[CR_DEFINED]");
1644 else if (*t == CR_REFERENCED)
1645 printf("[CR_REFERENCED]");
1646 else if (*t == CR_STREQ)
1647 printf("[CR_STREQ]");
1648 else if (*t == CR_MACDEF)
1649 printf("[CR_MACDEF]");
1650 else if (*t == CR_TIME)
1651 printf("[CR_TIME]");
1652 else if (*t == CR_DATE)
1653 printf("[CR_DATE]");
1654 else if (*t >= 0x20 && *t <= 0x2F)
1655 printf("[%c]", (char)*t);
1656 else if (*t >= 0x3A && *t <= 0x3F)
1657 printf("[%c]", (char)*t);
1658 else if (*t >= 0x80 && *t <= 0x87)
1659 printf("[D%u]", ((uint32_t)*t) - 0x80);
1660 else if (*t >= 0x88 && *t <= 0x8F)
1661 printf("[A%u]", ((uint32_t)*t) - 0x88);
1663 printf("[%X:%c]", (uint32_t)*t, (char)*t);
1664 // printf("[%X]", (uint32_t)*t);