1 /*****************************************************************************/
5 /* The scanner for the ca65 macroassembler */
9 /* (C) 1998-2011, Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
41 #include <sys/types.h> /* EMX needs this */
67 /*****************************************************************************/
69 /*****************************************************************************/
73 /* Current input token incl. attributes */
74 Token CurTok = STATIC_TOKEN_INITIALIZER;
76 /* Struct to handle include files. */
77 typedef struct InputFile InputFile;
79 FILE* F; /* Input file descriptor */
80 FilePos Pos; /* Position in file */
81 token_t Tok; /* Last token */
82 int C; /* Last character */
83 char Line[256]; /* The current input line */
84 int IncSearchPath; /* True if we've added a search path */
85 int BinSearchPath; /* True if we've added a search path */
86 InputFile* Next; /* Linked list of input files */
89 /* Struct to handle textual input data */
90 typedef struct InputData InputData;
92 char* Text; /* Pointer to the text data */
93 const char* Pos; /* Pointer to current position */
94 int Malloced; /* Memory was malloced */
95 token_t Tok; /* Last token */
96 int C; /* Last character */
97 InputData* Next; /* Linked list of input data */
100 /* Input source: Either file or data */
101 typedef struct CharSource CharSource;
103 /* Set of input functions */
104 typedef struct CharSourceFunctions CharSourceFunctions;
105 struct CharSourceFunctions {
106 void (*MarkStart) (CharSource*); /* Mark the start pos of a token */
107 void (*NextChar) (CharSource*); /* Read next char from input */
108 void (*Done) (CharSource*); /* Close input source */
111 /* Input source: Either file or data */
113 CharSource* Next; /* Linked list of char sources */
114 token_t Tok; /* Last token */
115 int C; /* Last character */
116 const CharSourceFunctions* Func; /* Pointer to function table */
118 InputFile File; /* File data */
119 InputData Data; /* Textual data */
123 /* Current input variables */
124 static CharSource* Source = 0; /* Current char source */
125 static unsigned FCount = 0; /* Count of input files */
126 static int C = 0; /* Current input character */
128 /* Force end of assembly */
131 /* List of dot keywords with the corresponding tokens */
133 const char* Key; /* MUST be first field */
138 { ".ADDR", TOK_ADDR },
139 { ".ALIGN", TOK_ALIGN },
140 { ".AND", TOK_BOOLAND },
141 { ".ASCIIZ", TOK_ASCIIZ },
142 { ".ASSERT", TOK_ASSERT },
143 { ".AUTOIMPORT", TOK_AUTOIMPORT },
144 { ".BANKBYTE", TOK_BANKBYTE },
145 { ".BANKBYTES", TOK_BANKBYTES },
146 { ".BITAND", TOK_AND },
147 { ".BITNOT", TOK_NOT },
148 { ".BITOR", TOK_OR },
149 { ".BITXOR", TOK_XOR },
150 { ".BLANK", TOK_BLANK },
152 { ".BYT", TOK_BYTE },
153 { ".BYTE", TOK_BYTE },
154 { ".CASE", TOK_CASE },
155 { ".CHARMAP", TOK_CHARMAP },
156 { ".CODE", TOK_CODE },
157 { ".CONCAT", TOK_CONCAT },
158 { ".CONDES", TOK_CONDES },
159 { ".CONST", TOK_CONST },
160 { ".CONSTRUCTOR", TOK_CONSTRUCTOR },
162 { ".DATA", TOK_DATA },
164 { ".DBYT", TOK_DBYT },
165 { ".DEBUGINFO", TOK_DEBUGINFO },
166 { ".DEF", TOK_DEFINED },
167 { ".DEFINE", TOK_DEFINE },
168 { ".DEFINED", TOK_DEFINED },
169 { ".DESTRUCTOR", TOK_DESTRUCTOR },
170 { ".DWORD", TOK_DWORD },
171 { ".ELSE", TOK_ELSE },
172 { ".ELSEIF", TOK_ELSEIF },
174 { ".ENDENUM", TOK_ENDENUM },
175 { ".ENDIF", TOK_ENDIF },
176 { ".ENDMAC", TOK_ENDMACRO },
177 { ".ENDMACRO", TOK_ENDMACRO },
178 { ".ENDPROC", TOK_ENDPROC },
179 { ".ENDREP", TOK_ENDREP },
180 { ".ENDREPEAT", TOK_ENDREP },
181 { ".ENDSCOPE", TOK_ENDSCOPE },
182 { ".ENDSTRUCT", TOK_ENDSTRUCT },
183 { ".ENDUNION", TOK_ENDUNION },
184 { ".ENUM", TOK_ENUM },
185 { ".ERROR", TOK_ERROR },
186 { ".EXITMAC", TOK_EXITMACRO },
187 { ".EXITMACRO", TOK_EXITMACRO },
188 { ".EXPORT", TOK_EXPORT },
189 { ".EXPORTZP", TOK_EXPORTZP },
190 { ".FARADDR", TOK_FARADDR },
191 { ".FATAL", TOK_FATAL },
192 { ".FEATURE", TOK_FEATURE },
193 { ".FILEOPT", TOK_FILEOPT },
194 { ".FOPT", TOK_FILEOPT },
195 { ".FORCEIMPORT", TOK_FORCEIMPORT },
196 { ".FORCEWORD", TOK_FORCEWORD },
197 { ".GLOBAL", TOK_GLOBAL },
198 { ".GLOBALZP", TOK_GLOBALZP },
199 { ".HIBYTE", TOK_HIBYTE },
200 { ".HIBYTES", TOK_HIBYTES },
201 { ".HIWORD", TOK_HIWORD },
204 { ".IDENT", TOK_MAKEIDENT },
206 { ".IFBLANK", TOK_IFBLANK },
207 { ".IFCONST", TOK_IFCONST },
208 { ".IFDEF", TOK_IFDEF },
209 { ".IFNBLANK", TOK_IFNBLANK },
210 { ".IFNCONST", TOK_IFNCONST },
211 { ".IFNDEF", TOK_IFNDEF },
212 { ".IFNREF", TOK_IFNREF },
213 { ".IFP02", TOK_IFP02 },
214 { ".IFP816", TOK_IFP816 },
215 { ".IFPC02", TOK_IFPC02 },
216 { ".IFPSC02", TOK_IFPSC02 },
217 { ".IFREF", TOK_IFREF },
218 { ".IMPORT", TOK_IMPORT },
219 { ".IMPORTZP", TOK_IMPORTZP },
220 { ".INCBIN", TOK_INCBIN },
221 { ".INCLUDE", TOK_INCLUDE },
222 { ".INTERRUPTOR", TOK_INTERRUPTOR },
223 { ".LEFT", TOK_LEFT },
224 { ".LINECONT", TOK_LINECONT },
225 { ".LIST", TOK_LIST },
226 { ".LISTBYTES", TOK_LISTBYTES },
227 { ".LOBYTE", TOK_LOBYTE },
228 { ".LOBYTES", TOK_LOBYTES },
229 { ".LOCAL", TOK_LOCAL },
230 { ".LOCALCHAR", TOK_LOCALCHAR },
231 { ".LOWORD", TOK_LOWORD },
232 { ".MAC", TOK_MACRO },
233 { ".MACPACK", TOK_MACPACK },
234 { ".MACRO", TOK_MACRO },
235 { ".MATCH", TOK_MATCH },
240 { ".NOT", TOK_BOOLNOT },
241 { ".NULL", TOK_NULL },
242 { ".OR", TOK_BOOLOR },
246 { ".P816", TOK_P816 },
247 { ".PAGELEN", TOK_PAGELENGTH },
248 { ".PAGELENGTH", TOK_PAGELENGTH },
249 { ".PARAMCOUNT", TOK_PARAMCOUNT },
250 { ".PC02", TOK_PC02 },
251 { ".POPCPU", TOK_POPCPU },
252 { ".POPSEG", TOK_POPSEG },
253 { ".PROC", TOK_PROC },
254 { ".PSC02", TOK_PSC02 },
255 { ".PUSHCPU", TOK_PUSHCPU },
256 { ".PUSHSEG", TOK_PUSHSEG },
257 { ".REF", TOK_REFERENCED },
258 { ".REFERENCED", TOK_REFERENCED },
259 { ".RELOC", TOK_RELOC },
260 { ".REPEAT", TOK_REPEAT },
262 { ".RIGHT", TOK_RIGHT },
263 { ".RODATA", TOK_RODATA },
264 { ".SCOPE", TOK_SCOPE },
265 { ".SEGMENT", TOK_SEGMENT },
267 { ".SETCPU", TOK_SETCPU },
270 { ".SIZEOF", TOK_SIZEOF },
271 { ".SMART", TOK_SMART },
272 { ".SPRINTF", TOK_SPRINTF },
273 { ".STRAT", TOK_STRAT },
274 { ".STRING", TOK_STRING },
275 { ".STRLEN", TOK_STRLEN },
276 { ".STRUCT", TOK_STRUCT },
277 { ".SUNPLUS", TOK_SUNPLUS },
279 { ".TCOUNT", TOK_TCOUNT },
280 { ".TIME", TOK_TIME },
281 { ".UNION", TOK_UNION },
282 { ".VERSION", TOK_VERSION },
283 { ".WARNING", TOK_WARNING },
284 { ".WORD", TOK_WORD },
285 { ".XMATCH", TOK_XMATCH },
286 { ".XOR", TOK_BOOLXOR },
287 { ".ZEROPAGE", TOK_ZEROPAGE },
292 /*****************************************************************************/
293 /* CharSource functions */
294 /*****************************************************************************/
298 static void UseCharSource (CharSource* S)
299 /* Initialize a new input source and start to use it. */
301 /* Remember the current input char and token */
305 /* Use the new input source */
309 /* Read the first character from the new file */
310 S->Func->NextChar (S);
312 /* Setup the next token so it will be skipped on the next call to
315 CurTok.Tok = TOK_SEP;
320 static void DoneCharSource (void)
321 /* Close the top level character source */
325 /* First, call the type specific function */
326 Source->Func->Done (Source);
328 /* Restore the old token */
329 CurTok.Tok = Source->Tok;
332 /* Remember the last stacked input source */
335 /* Delete the top level one ... */
338 /* ... and use the one before */
344 /*****************************************************************************/
345 /* InputFile functions */
346 /*****************************************************************************/
350 static void IFMarkStart (CharSource* S)
351 /* Mark the start of the next token */
353 CurTok.Pos = S->V.File.Pos;
358 static void IFNextChar (CharSource* S)
359 /* Read the next character from the input file */
361 /* Check for end of line, read the next line if needed */
362 while (S->V.File.Line [S->V.File.Pos.Col] == '\0') {
364 unsigned Len, Removed;
366 /* End of current line reached, read next line */
367 if (fgets (S->V.File.Line, sizeof (S->V.File.Line), S->V.File.F) == 0) {
368 /* End of file. Add an empty line to the listing. This is a
369 * small hack needed to keep the PC output in sync.
371 NewListingLine ("", S->V.File.Pos.Name, FCount);
376 /* For better handling of files with unusual line endings (DOS
377 * files that are accidently translated on Unix for example),
378 * first remove all whitespace at the end, then add a single
381 Len = strlen (S->V.File.Line);
383 while (Len > 0 && IsSpace (S->V.File.Line[Len-1])) {
388 S->V.File.Line[Len+0] = '\n';
389 S->V.File.Line[Len+1] = '\0';
393 S->V.File.Pos.Line++;
394 S->V.File.Pos.Col = 0;
396 /* Remember the new line for the listing */
397 NewListingLine (S->V.File.Line, S->V.File.Pos.Name, FCount);
401 /* Return the next character from the file */
402 C = S->V.File.Line [S->V.File.Pos.Col++];
407 void IFDone (CharSource* S)
408 /* Close the current input file */
410 /* We're at the end of an include file. Check if we have any
411 * open .IFs, or any open token lists in this file. This
412 * enforcement is artificial, using conditionals that start
413 * in one file and end in another are uncommon, and don't
414 * allowing these things will help finding errors.
418 /* If we've added search paths for this file, remove them */
419 if (S->V.File.IncSearchPath) {
420 PopSearchPath (IncSearchPath);
422 if (S->V.File.BinSearchPath) {
423 PopSearchPath (BinSearchPath);
426 /* Close the input file and decrement the file count. We will ignore
427 * errors here, since we were just reading from the file.
429 (void) fclose (S->V.File.F);
435 /* Set of input file handling functions */
436 static const CharSourceFunctions IFFunc = {
444 int NewInputFile (const char* Name)
445 /* Open a new input file. Returns true if the file could be successfully opened
446 * and false otherwise.
449 int RetCode = 0; /* Return code. Assume an error. */
453 StrBuf NameBuf; /* No need to initialize */
454 StrBuf Path = AUTO_STRBUF_INITIALIZER;
459 /* If this is the main file, just try to open it. If it's an include file,
460 * search for it using the include path list.
464 F = fopen (Name, "r");
466 Fatal ("Cannot open input file `%s': %s", Name, strerror (errno));
469 /* We are on include level. Search for the file in the include
472 PathName = SearchFile (IncSearchPath, Name);
473 if (PathName == 0 || (F = fopen (PathName, "r")) == 0) {
474 /* Not found or cannot open, print an error and bail out */
475 Error ("Cannot open include file `%s': %s", Name, strerror (errno));
479 /* Use the path name from now on */
483 /* Stat the file and remember the values. There a race condition here,
484 * since we cannot use fileno() (non standard identifier in standard
485 * header file), and therefore not fstat. When using stat with the
486 * file name, there's a risk that the file was deleted and recreated
487 * while it was open. Since mtime and size are only used to check
488 * if a file has changed in the debugger, we will ignore this problem
491 if (stat (Name, &Buf) != 0) {
492 Fatal ("Cannot stat input file `%s': %s", Name, strerror (errno));
495 /* Add the file to the input file table and remember the index */
496 FileIdx = AddFile (SB_InitFromString (&NameBuf, Name),
497 (FCount == 0)? FT_MAIN : FT_INCLUDE,
498 Buf.st_size, Buf.st_mtime);
500 /* Create a new input source variable and initialize it */
501 S = xmalloc (sizeof (*S));
504 S->V.File.Pos.Line = 0;
505 S->V.File.Pos.Col = 0;
506 S->V.File.Pos.Name = FileIdx;
507 S->V.File.Line[0] = '\0';
509 /* Push the path for this file onto the include search lists */
510 SB_CopyBuf (&Path, Name, FindName (Name) - Name);
511 SB_Terminate (&Path);
512 S->V.File.IncSearchPath = PushSearchPath (IncSearchPath, SB_GetConstBuf (&Path));
513 S->V.File.BinSearchPath = PushSearchPath (BinSearchPath, SB_GetConstBuf (&Path));
516 /* Count active input files */
519 /* Use this input source */
522 /* File successfully opened */
526 /* Free an allocated name buffer */
529 /* Return the success code */
535 /*****************************************************************************/
536 /* InputData functions */
537 /*****************************************************************************/
541 static void IDMarkStart (CharSource* S attribute ((unused)))
542 /* Mark the start of the next token */
544 /* Nothing to do here */
549 static void IDNextChar (CharSource* S)
550 /* Read the next character from the input text */
552 C = *S->V.Data.Pos++;
554 /* End of input data */
562 void IDDone (CharSource* S)
563 /* Close the current input data */
565 /* Cleanup the current stuff */
566 if (S->V.Data.Malloced) {
567 xfree (S->V.Data.Text);
573 /* Set of input data handling functions */
574 static const CharSourceFunctions IDFunc = {
582 void NewInputData (char* Text, int Malloced)
583 /* Add a chunk of input data to the input stream */
587 /* Create a new input source variable and initialize it */
588 S = xmalloc (sizeof (*S));
590 S->V.Data.Text = Text;
591 S->V.Data.Pos = Text;
592 S->V.Data.Malloced = Malloced;
594 /* Use this input source */
600 /*****************************************************************************/
601 /* Character classification functions */
602 /*****************************************************************************/
607 /* Return true if the character is a valid character for an identifier */
609 return IsAlNum (C) ||
611 (C == '@' && AtInIdents) ||
612 (C == '$' && DollarInIdents);
617 int IsIdStart (int C)
618 /* Return true if the character may start an identifier */
620 return IsAlpha (C) || C == '_';
625 /*****************************************************************************/
627 /*****************************************************************************/
631 static unsigned DigitVal (unsigned char C)
632 /* Convert a digit into it's numerical representation */
637 return toupper (C) - 'A' + 10;
643 static void NextChar (void)
644 /* Read the next character from the input file */
646 Source->Func->NextChar (Source);
651 void LocaseSVal (void)
652 /* Make SVal lower case */
654 SB_ToLower (&CurTok.SVal);
659 void UpcaseSVal (void)
660 /* Make SVal upper case */
662 SB_ToUpper (&CurTok.SVal);
667 static int CmpDotKeyword (const void* K1, const void* K2)
668 /* Compare function for the dot keyword search */
670 return strcmp (((struct DotKeyword*)K1)->Key, ((struct DotKeyword*)K2)->Key);
675 static token_t FindDotKeyword (void)
676 /* Find the dot keyword in SVal. Return the corresponding token if found,
677 * return TOK_NONE if not found.
681 struct DotKeyword* R;
684 K.Key = SB_GetConstBuf (&CurTok.SVal);
687 /* If we aren't in ignore case mode, we have to uppercase the keyword */
692 /* Search for the keyword */
693 R = bsearch (&K, DotKeywords, sizeof (DotKeywords) / sizeof (DotKeywords [0]),
694 sizeof (DotKeywords [0]), CmpDotKeyword);
704 static void ReadIdent (void)
705 /* Read an identifier from the current input position into Ident. Filling SVal
706 * starts at the current position with the next character in C. It is assumed
707 * that any characters already filled in are ok, and the character in C is
711 /* Read the identifier */
713 SB_AppendChar (&CurTok.SVal, C);
715 } while (IsIdChar (C));
716 SB_Terminate (&CurTok.SVal);
718 /* If we should ignore case, convert the identifier to upper case */
726 static void ReadStringConst (int StringTerm)
727 /* Read a string constant into SVal. */
729 /* Skip the leading string terminator */
732 /* Read the string */
734 if (C == StringTerm) {
737 if (C == '\n' || C == EOF) {
738 Error ("Newline in string constant");
742 /* Append the char to the string */
743 SB_AppendChar (&CurTok.SVal, C);
745 /* Skip the character */
749 /* Skip the trailing terminator */
752 /* Terminate the string */
753 SB_Terminate (&CurTok.SVal);
758 static int Sweet16Reg (const StrBuf* Id)
759 /* Check if the given identifier is a sweet16 register. Return -1 if this is
760 * not the case, return the register number otherwise.
766 if (SB_GetLen (Id) < 2) {
769 if (toupper (SB_AtUnchecked (Id, 0)) != 'R') {
772 if (!IsDigit (SB_AtUnchecked (Id, 1))) {
776 if (sscanf (SB_GetConstBuf (Id)+1, "%u%c", &RegNum, &Check) != 1 || RegNum > 15) {
777 /* Invalid register */
781 /* The register number is valid */
787 void NextRawTok (void)
788 /* Read the next raw token from the input stream */
790 /* If we've a forced end of assembly, don't read further */
792 CurTok.Tok = TOK_EOF;
797 /* Check if we have tokens from another input source */
798 if (InputFromStack ()) {
803 /* Skip whitespace, remember if we had some */
804 if ((CurTok.WS = IsBlank (C)) != 0) {
807 } while (IsBlank (C));
810 /* Mark the file position of the next token */
811 Source->Func->MarkStart (Source);
813 /* Clear the string attribute */
814 SB_Clear (&CurTok.SVal);
816 /* Generate line info for the current token */
817 GenLineInfo (LI_SLOT_ASM, &CurTok.Pos);
819 /* Hex number or PC symbol? */
823 /* Hex digit must follow or DollarIsPC must be enabled */
829 Error ("Hexadecimal digit expected");
833 /* Read the number */
835 while (IsXDigit (C)) {
836 if (CurTok.IVal & 0xF0000000) {
837 Error ("Overflow in hexadecimal number");
840 CurTok.IVal = (CurTok.IVal << 4) + DigitVal (C);
844 /* This is an integer constant */
845 CurTok.Tok = TOK_INTCON;
853 /* 0 or 1 must follow */
855 Error ("Binary digit expected");
858 /* Read the number */
860 while (IsBDigit (C)) {
861 if (CurTok.IVal & 0x80000000) {
862 Error ("Overflow in binary number");
865 CurTok.IVal = (CurTok.IVal << 1) + DigitVal (C);
869 /* This is an integer constant */
870 CurTok.Tok = TOK_INTCON;
884 /* Ignore leading zeros */
889 /* Read the number into Buf counting the digits */
891 while (IsXDigit (C)) {
893 /* Buf is big enough to allow any decimal and hex number to
894 * overflow, so ignore excess digits here, they will be detected
895 * when we convert the value.
897 if (Digits < sizeof (Buf)) {
904 /* Allow zilog/intel style hex numbers with a 'h' suffix */
905 if (C == 'h' || C == 'H') {
908 Max = 0xFFFFFFFFUL / 16;
911 Max = 0xFFFFFFFFUL / 10;
914 /* Convert the number using the given base */
916 for (I = 0; I < Digits; ++I) {
917 if (CurTok.IVal > Max) {
918 Error ("Number out of range");
922 DVal = DigitVal (Buf[I]);
924 Error ("Invalid digits in number");
928 CurTok.IVal = (CurTok.IVal * Base) + DVal;
931 /* This is an integer constant */
932 CurTok.Tok = TOK_INTCON;
936 /* Control command? */
939 /* Remember and skip the dot */
942 /* Check if it's just a dot */
943 if (!IsIdStart (C)) {
946 CurTok.Tok = TOK_DOT;
950 /* Read the remainder of the identifier */
951 SB_AppendChar (&CurTok.SVal, '.');
954 /* Dot keyword, search for it */
955 CurTok.Tok = FindDotKeyword ();
956 if (CurTok.Tok == TOK_NONE) {
959 if (!LeadingDotInIdents) {
960 /* Invalid pseudo instruction */
961 Error ("`%m%p' is not a recognized control command", &CurTok.SVal);
965 /* An identifier with a dot. Check if it's a define style
968 if (IsDefine (&CurTok.SVal)) {
969 /* This is a define style macro - expand it */
974 /* Just an identifier with a dot */
975 CurTok.Tok = TOK_IDENT;
982 /* Indirect op for sweet16 cpu. Must check this before checking for local
983 * symbols, because these may also use the '@' symbol.
985 if (CPU == CPU_SWEET16 && C == '@') {
992 if (C == LocalStart) {
994 /* Read the identifier. */
997 /* Start character alone is not enough */
998 if (SB_GetLen (&CurTok.SVal) == 1) {
999 Error ("Invalid cheap local symbol");
1003 /* A local identifier */
1004 CurTok.Tok = TOK_LOCAL_IDENT;
1009 /* Identifier or keyword? */
1010 if (IsIdStart (C)) {
1012 /* Read the identifier */
1015 /* Check for special names. Bail out if we have identified the type of
1016 * the token. Go on if the token is an identifier.
1018 if (SB_GetLen (&CurTok.SVal) == 1) {
1019 switch (toupper (SB_AtUnchecked (&CurTok.SVal, 0))) {
1024 CurTok.Tok = TOK_OVERRIDE_ABS;
1033 CurTok.Tok = TOK_OVERRIDE_FAR;
1039 if (CPU == CPU_65816) {
1056 CurTok.Tok = TOK_OVERRIDE_ZP;
1065 } else if (CPU == CPU_SWEET16 &&
1066 (CurTok.IVal = Sweet16Reg (&CurTok.SVal)) >= 0) {
1068 /* A sweet16 register number in sweet16 mode */
1069 CurTok.Tok = TOK_REG;
1074 /* Check for define style macro */
1075 if (IsDefine (&CurTok.SVal)) {
1076 /* Macro - expand it */
1081 CurTok.Tok = TOK_IDENT;
1086 /* Ok, let's do the switch */
1092 CurTok.Tok = TOK_PLUS;
1097 CurTok.Tok = TOK_MINUS;
1103 CurTok.Tok = TOK_DIV;
1104 } else if (CComments) {
1105 /* Remember the position, then skip the '*' */
1106 FilePos Pos = CurTok.Pos;
1111 PError (&Pos, "Unterminated comment");
1125 CurTok.Tok = TOK_MUL;
1130 CurTok.Tok = TOK_XOR;
1137 CurTok.Tok = TOK_BOOLAND;
1139 CurTok.Tok = TOK_AND;
1147 CurTok.Tok = TOK_BOOLOR;
1149 CurTok.Tok = TOK_OR;
1159 CurTok.Tok = TOK_NAMESPACE;
1168 CurTok.Tok = TOK_ULABEL;
1177 CurTok.Tok = TOK_ULABEL;
1182 CurTok.Tok = TOK_ASSIGN;
1186 CurTok.Tok = TOK_COLON;
1193 CurTok.Tok = TOK_COMMA;
1198 while (C != '\n' && C != EOF) {
1205 CurTok.Tok = TOK_HASH;
1210 CurTok.Tok = TOK_LPAREN;
1215 CurTok.Tok = TOK_RPAREN;
1220 CurTok.Tok = TOK_LBRACK;
1225 CurTok.Tok = TOK_RBRACK;
1230 CurTok.Tok = TOK_LCURLY;
1235 CurTok.Tok = TOK_RCURLY;
1242 CurTok.Tok = TOK_LE;
1243 } else if (C == '<') {
1245 CurTok.Tok = TOK_SHL;
1246 } else if (C == '>') {
1248 CurTok.Tok = TOK_NE;
1250 CurTok.Tok = TOK_LT;
1256 CurTok.Tok = TOK_EQ;
1261 CurTok.Tok = TOK_BOOLNOT;
1268 CurTok.Tok = TOK_GE;
1269 } else if (C == '>') {
1271 CurTok.Tok = TOK_SHR;
1273 CurTok.Tok = TOK_GT;
1279 CurTok.Tok = TOK_NOT;
1283 /* Hack: If we allow ' as terminating character for strings, read
1284 * the following stuff as a string, and check for a one character
1287 if (LooseStringTerm) {
1288 ReadStringConst ('\'');
1289 if (SB_GetLen (&CurTok.SVal) == 1) {
1290 CurTok.IVal = SB_AtUnchecked (&CurTok.SVal, 0);
1291 CurTok.Tok = TOK_CHARCON;
1293 CurTok.Tok = TOK_STRCON;
1296 /* Always a character constant */
1298 if (C == EOF || IsControl (C)) {
1299 Error ("Illegal character constant");
1303 CurTok.Tok = TOK_CHARCON;
1306 if (!MissingCharTerm) {
1307 Error ("Illegal character constant");
1316 ReadStringConst ('\"');
1317 CurTok.Tok = TOK_STRCON;
1321 /* Line continuation? */
1325 /* Handle as white space */
1335 CurTok.Tok = TOK_SEP;
1340 /* In case of the main file, do not close it, but return EOF. */
1341 if (Source && Source->Next) {
1345 CurTok.Tok = TOK_EOF;
1350 /* If we go here, we could not identify the current character. Skip it
1353 Error ("Invalid input character: 0x%02X", C & 0xFF);
1360 int GetSubKey (const char** Keys, unsigned Count)
1361 /* Search for a subkey in a table of keywords. The current token must be an
1362 * identifier and all keys must be in upper case. The identifier will be
1363 * uppercased in the process. The function returns the index of the keyword,
1364 * or -1 if the keyword was not found.
1369 /* Must have an identifier */
1370 PRECONDITION (CurTok.Tok == TOK_IDENT);
1372 /* If we aren't in ignore case mode, we have to uppercase the identifier */
1377 /* Do a linear search (a binary search is not worth the effort) */
1378 for (I = 0; I < Count; ++I) {
1379 if (SB_CompareStr (&CurTok.SVal, Keys [I]) == 0) {
1391 unsigned char ParseAddrSize (void)
1392 /* Check if the next token is a keyword that denotes an address size specifier.
1393 * If so, return the corresponding address size constant, otherwise output an
1394 * error message and return ADDR_SIZE_DEFAULT.
1397 unsigned char AddrSize;
1399 /* Check for an identifier */
1400 if (CurTok.Tok != TOK_IDENT) {
1401 Error ("Address size specifier expected");
1402 return ADDR_SIZE_DEFAULT;
1405 /* Convert the attribute */
1406 AddrSize = AddrSizeFromStr (SB_GetConstBuf (&CurTok.SVal));
1407 if (AddrSize == ADDR_SIZE_INVALID) {
1408 Error ("Address size specifier expected");
1409 AddrSize = ADDR_SIZE_DEFAULT;
1418 void InitScanner (const char* InFile)
1419 /* Initialize the scanner, open the given input file */
1421 /* Open the input file */
1422 NewInputFile (InFile);
1427 void DoneScanner (void)
1428 /* Release scanner resources */