1 /*****************************************************************************/
5 /* The scanner for the ca65 macroassembler */
9 /* (C) 1998-2007 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 enum Token Tok = TOK_NONE; /* Current token */
74 int WS; /* Flag: Whitespace before token */
75 long IVal; /* Integer token attribute */
76 char SVal[MAX_STR_LEN+1]; /* String token attribute */
78 FilePos CurPos = { 0, 0, 0 }; /* Name and position in current file */
82 /* Struct to handle include files. */
83 typedef struct InputFile InputFile;
85 FILE* F; /* Input file descriptor */
86 FilePos Pos; /* Position in file */
87 enum Token Tok; /* Last token */
88 int C; /* Last character */
89 char Line[256]; /* The current input line */
90 InputFile* Next; /* Linked list of input files */
93 /* Struct to handle textual input data */
94 typedef struct InputData InputData;
96 char* Text; /* Pointer to the text data */
97 const char* Pos; /* Pointer to current position */
98 int Malloced; /* Memory was malloced */
99 enum Token Tok; /* Last token */
100 int C; /* Last character */
101 InputData* Next; /* Linked list of input data */
104 /* Input source: Either file or data */
105 typedef struct CharSource CharSource;
107 /* Set of input functions */
108 typedef struct CharSourceFunctions CharSourceFunctions;
109 struct CharSourceFunctions {
110 void (*MarkStart) (CharSource*); /* Mark the start pos of a token */
111 void (*NextChar) (CharSource*); /* Read next char from input */
112 void (*Done) (CharSource*); /* Close input source */
115 /* Input source: Either file or data */
117 CharSource* Next; /* Linked list of char sources */
118 enum Token Tok; /* Last token */
119 int C; /* Last character */
120 const CharSourceFunctions* Func; /* Pointer to function table */
122 InputFile File; /* File data */
123 InputData Data; /* Textual data */
127 /* Current input variables */
128 static CharSource* Source = 0; /* Current char source */
129 static unsigned FCount = 0; /* Count of input files */
130 static int C = 0; /* Current input character */
132 /* Force end of assembly */
135 /* List of dot keywords with the corresponding tokens */
137 const char* Key; /* MUST be first field */
142 { ".ADDR", TOK_ADDR },
143 { ".ALIGN", TOK_ALIGN },
144 { ".AND", TOK_BOOLAND },
145 { ".ASCIIZ", TOK_ASCIIZ },
146 { ".ASSERT", TOK_ASSERT },
147 { ".AUTOIMPORT", TOK_AUTOIMPORT },
148 { ".BANKBYTE", TOK_BANKBYTE },
149 { ".BITAND", TOK_AND },
150 { ".BITNOT", TOK_NOT },
151 { ".BITOR", TOK_OR },
152 { ".BITXOR", TOK_XOR },
153 { ".BLANK", TOK_BLANK },
155 { ".BYT", TOK_BYTE },
156 { ".BYTE", TOK_BYTE },
157 { ".CASE", TOK_CASE },
158 { ".CHARMAP", TOK_CHARMAP },
159 { ".CODE", TOK_CODE },
160 { ".CONCAT", TOK_CONCAT },
161 { ".CONDES", TOK_CONDES },
162 { ".CONST", TOK_CONST },
163 { ".CONSTRUCTOR", TOK_CONSTRUCTOR },
165 { ".DATA", TOK_DATA },
167 { ".DBYT", TOK_DBYT },
168 { ".DEBUGINFO", TOK_DEBUGINFO },
169 { ".DEF", TOK_DEFINED },
170 { ".DEFINE", TOK_DEFINE },
171 { ".DEFINED", TOK_DEFINED },
172 { ".DESTRUCTOR", TOK_DESTRUCTOR },
173 { ".DWORD", TOK_DWORD },
174 { ".ELSE", TOK_ELSE },
175 { ".ELSEIF", TOK_ELSEIF },
177 { ".ENDENUM", TOK_ENDENUM },
178 { ".ENDIF", TOK_ENDIF },
179 { ".ENDMAC", TOK_ENDMACRO },
180 { ".ENDMACRO", TOK_ENDMACRO },
181 { ".ENDPROC", TOK_ENDPROC },
182 { ".ENDREP", TOK_ENDREP },
183 { ".ENDREPEAT", TOK_ENDREP },
184 { ".ENDSCOPE", TOK_ENDSCOPE },
185 { ".ENDSTRUCT", TOK_ENDSTRUCT },
186 { ".ENDUNION", TOK_ENDUNION },
187 { ".ENUM", TOK_ENUM },
188 { ".ERROR", TOK_ERROR },
189 { ".EXITMAC", TOK_EXITMACRO },
190 { ".EXITMACRO", TOK_EXITMACRO },
191 { ".EXPORT", TOK_EXPORT },
192 { ".EXPORTZP", TOK_EXPORTZP },
193 { ".FARADDR", TOK_FARADDR },
194 { ".FEATURE", TOK_FEATURE },
195 { ".FILEOPT", TOK_FILEOPT },
196 { ".FOPT", TOK_FILEOPT },
197 { ".FORCEIMPORT", TOK_FORCEIMPORT },
198 { ".FORCEWORD", TOK_FORCEWORD },
199 { ".GLOBAL", TOK_GLOBAL },
200 { ".GLOBALZP", TOK_GLOBALZP },
201 { ".HIBYTE", TOK_HIBYTE },
202 { ".HIWORD", TOK_HIWORD },
205 { ".IDENT", TOK_MAKEIDENT },
207 { ".IFBLANK", TOK_IFBLANK },
208 { ".IFCONST", TOK_IFCONST },
209 { ".IFDEF", TOK_IFDEF },
210 { ".IFNBLANK", TOK_IFNBLANK },
211 { ".IFNCONST", TOK_IFNCONST },
212 { ".IFNDEF", TOK_IFNDEF },
213 { ".IFNREF", TOK_IFNREF },
214 { ".IFP02", TOK_IFP02 },
215 { ".IFP816", TOK_IFP816 },
216 { ".IFPC02", TOK_IFPC02 },
217 { ".IFPSC02", TOK_IFPSC02 },
218 { ".IFREF", TOK_IFREF },
219 { ".IMPORT", TOK_IMPORT },
220 { ".IMPORTZP", TOK_IMPORTZP },
221 { ".INCBIN", TOK_INCBIN },
222 { ".INCLUDE", TOK_INCLUDE },
223 { ".INTERRUPTOR", TOK_INTERRUPTOR },
224 { ".LEFT", TOK_LEFT },
225 { ".LINECONT", TOK_LINECONT },
226 { ".LIST", TOK_LIST },
227 { ".LISTBYTES", TOK_LISTBYTES },
228 { ".LOBYTE", TOK_LOBYTE },
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 },
238 { ".NOT", TOK_BOOLNOT },
239 { ".NULL", TOK_NULL },
240 { ".OR", TOK_BOOLOR },
244 { ".P816", TOK_P816 },
245 { ".PAGELEN", TOK_PAGELENGTH },
246 { ".PAGELENGTH", TOK_PAGELENGTH },
247 { ".PARAMCOUNT", TOK_PARAMCOUNT },
248 { ".PC02", TOK_PC02 },
249 { ".POPSEG", TOK_POPSEG },
250 { ".PROC", TOK_PROC },
251 { ".PSC02", TOK_PSC02 },
252 { ".PUSHSEG", TOK_PUSHSEG },
253 { ".REF", TOK_REFERENCED },
254 { ".REFERENCED", TOK_REFERENCED },
255 { ".RELOC", TOK_RELOC },
256 { ".REPEAT", TOK_REPEAT },
258 { ".RIGHT", TOK_RIGHT },
259 { ".RODATA", TOK_RODATA },
260 { ".SCOPE", TOK_SCOPE },
261 { ".SEGMENT", TOK_SEGMENT },
263 { ".SETCPU", TOK_SETCPU },
266 { ".SIZEOF", TOK_SIZEOF },
267 { ".SMART", TOK_SMART },
268 { ".SPRINTF", TOK_SPRINTF },
269 { ".STRAT", TOK_STRAT },
270 { ".STRING", TOK_STRING },
271 { ".STRLEN", TOK_STRLEN },
272 { ".STRUCT", TOK_STRUCT },
273 { ".SUNPLUS", TOK_SUNPLUS },
275 { ".TCOUNT", TOK_TCOUNT },
276 { ".TIME", TOK_TIME },
277 { ".UNION", TOK_UNION },
278 { ".VERSION", TOK_VERSION },
279 { ".WARNING", TOK_WARNING },
280 { ".WORD", TOK_WORD },
281 { ".XMATCH", TOK_XMATCH },
282 { ".XOR", TOK_BOOLXOR },
283 { ".ZEROPAGE", TOK_ZEROPAGE },
288 /*****************************************************************************/
289 /* CharSource functions */
290 /*****************************************************************************/
294 static void UseCharSource (CharSource* S)
295 /* Initialize a new input source and start to use it. */
297 /* Remember the current input char and token */
301 /* Use the new input source */
305 /* Read the first character from the new file */
306 S->Func->NextChar (S);
308 /* Setup the next token so it will be skipped on the next call to
316 static void DoneCharSource (void)
317 /* Close the top level character source */
321 /* First, call the type specific function */
322 Source->Func->Done (Source);
324 /* Restore the old token */
328 /* Remember the last stacked input source */
331 /* Delete the top level one ... */
334 /* ... and use the one before */
340 /*****************************************************************************/
341 /* InputFile functions */
342 /*****************************************************************************/
346 static void IFMarkStart (CharSource* S)
347 /* Mark the start of the next token */
349 CurPos = S->V.File.Pos;
354 static void IFNextChar (CharSource* S)
355 /* Read the next character from the input file */
357 /* Check for end of line, read the next line if needed */
358 while (S->V.File.Line [S->V.File.Pos.Col] == '\0') {
360 unsigned Len, Removed;
362 /* End of current line reached, read next line */
363 if (fgets (S->V.File.Line, sizeof (S->V.File.Line), S->V.File.F) == 0) {
364 /* End of file. Add an empty line to the listing. This is a
365 * small hack needed to keep the PC output in sync.
367 NewListingLine ("", S->V.File.Pos.Name, FCount);
372 /* For better handling of files with unusual line endings (DOS
373 * files that are accidently translated on Unix for example),
374 * first remove all whitespace at the end, then add a single
377 Len = strlen (S->V.File.Line);
379 while (Len > 0 && IsSpace (S->V.File.Line[Len-1])) {
384 S->V.File.Line[Len+0] = '\n';
385 S->V.File.Line[Len+1] = '\0';
389 S->V.File.Pos.Line++;
390 S->V.File.Pos.Col = 0;
392 /* Remember the new line for the listing */
393 NewListingLine (S->V.File.Line, S->V.File.Pos.Name, FCount);
397 /* Return the next character from the file */
398 C = S->V.File.Line [S->V.File.Pos.Col++];
403 void IFDone (CharSource* S)
404 /* Close the current input file */
406 /* We're at the end of an include file. Check if we have any
407 * open .IFs, or any open token lists in this file. This
408 * enforcement is artificial, using conditionals that start
409 * in one file and end in another are uncommon, and don't
410 * allowing these things will help finding errors.
414 /* Close the input file and decrement the file count. We will ignore
415 * errors here, since we were just reading from the file.
417 (void) fclose (S->V.File.F);
423 /* Set of input file handling functions */
424 static const CharSourceFunctions IFFunc = {
432 void NewInputFile (const char* Name)
433 /* Open a new input file */
437 /* First try to open the file */
438 FILE* F = fopen (Name, "r");
441 /* Error (fatal error if this is the main file) */
443 Fatal ("Cannot open input file `%s': %s", Name, strerror (errno));
446 /* We are on include level. Search for the file in the include
449 PathName = FindInclude (Name);
450 if (PathName == 0 || (F = fopen (PathName, "r")) == 0) {
451 /* Not found or cannot open, print an error and bail out */
452 Error ("Cannot open include file `%s': %s", Name, strerror (errno));
455 /* Use the path name from now on */
459 /* check again if we do now have an open file */
465 /* Stat the file and remember the values. There a race condition here,
466 * since we cannot use fileno() (non standard identifier in standard
467 * header file), and therefore not fstat. When using stat with the
468 * file name, there's a risk that the file was deleted and recreated
469 * while it was open. Since mtime and size are only used to check
470 * if a file has changed in the debugger, we will ignore this problem
474 if (stat (Name, &Buf) != 0) {
475 Fatal ("Cannot stat input file `%s': %s", Name, strerror (errno));
478 /* Add the file to the input file table and remember the index */
479 FileIdx = AddFile (Name, Buf.st_size, Buf.st_mtime);
481 /* Create a new input source variable and initialize it */
482 S = xmalloc (sizeof (*S));
485 S->V.File.Pos.Line = 0;
486 S->V.File.Pos.Col = 0;
487 S->V.File.Pos.Name = FileIdx;
488 S->V.File.Line[0] = '\0';
490 /* Count active input files */
493 /* Use this input source */
497 /* Free an allocated name buffer */
503 /*****************************************************************************/
504 /* InputData functions */
505 /*****************************************************************************/
509 static void IDMarkStart (CharSource* S attribute ((unused)))
510 /* Mark the start of the next token */
512 /* Nothing to do here */
517 static void IDNextChar (CharSource* S)
518 /* Read the next character from the input text */
520 C = *S->V.Data.Pos++;
522 /* End of input data */
530 void IDDone (CharSource* S)
531 /* Close the current input data */
533 /* Cleanup the current stuff */
534 if (S->V.Data.Malloced) {
535 xfree (S->V.Data.Text);
541 /* Set of input data handling functions */
542 static const CharSourceFunctions IDFunc = {
550 void NewInputData (char* Text, int Malloced)
551 /* Add a chunk of input data to the input stream */
555 /* Create a new input source variable and initialize it */
556 S = xmalloc (sizeof (*S));
558 S->V.Data.Text = Text;
559 S->V.Data.Pos = Text;
560 S->V.Data.Malloced = Malloced;
562 /* Use this input source */
568 /*****************************************************************************/
569 /* Character classification functions */
570 /*****************************************************************************/
575 /* Return true if the character is a valid character for an identifier */
577 return IsAlNum (C) ||
579 (C == '@' && AtInIdents) ||
580 (C == '$' && DollarInIdents);
585 int IsIdStart (int C)
586 /* Return true if the character may start an identifier */
588 return IsAlpha (C) || C == '_';
593 /*****************************************************************************/
595 /*****************************************************************************/
599 static unsigned DigitVal (unsigned char C)
600 /* Convert a digit into it's numerical representation */
605 return toupper (C) - 'A' + 10;
611 static void NextChar (void)
612 /* Read the next character from the input file */
614 Source->Func->NextChar (Source);
619 void LocaseSVal (void)
620 /* Make SVal lower case */
624 SVal [I] = tolower (SVal [I]);
631 void UpcaseSVal (void)
632 /* Make SVal upper case */
636 SVal [I] = toupper (SVal [I]);
643 static int CmpDotKeyword (const void* K1, const void* K2)
644 /* Compare function for the dot keyword search */
646 return strcmp (((struct DotKeyword*)K1)->Key, ((struct DotKeyword*)K2)->Key);
651 static unsigned char FindDotKeyword (void)
652 /* Find the dot keyword in SVal. Return the corresponding token if found,
653 * return TOK_NONE if not found.
656 static const struct DotKeyword K = { SVal, 0 };
657 struct DotKeyword* R;
659 /* If we aren't in ignore case mode, we have to uppercase the keyword */
664 /* Search for the keyword */
665 R = bsearch (&K, DotKeywords, sizeof (DotKeywords) / sizeof (DotKeywords [0]),
666 sizeof (DotKeywords [0]), CmpDotKeyword);
676 static void ReadIdent (unsigned Index)
677 /* Read an identifier from the current input position into Ident. Filling SVal
678 * starts at Index with the current character in C. It is assumed that any
679 * characters already filled in are ok, and the character in C is checked.
682 /* Read the identifier */
684 if (Index < MAX_STR_LEN) {
688 } while (IsIdChar (C));
691 /* If we should ignore case, convert the identifier to upper case */
699 static unsigned ReadStringConst (int StringTerm)
700 /* Read a string constant into SVal. Check for maximum string length and all
701 * other stuff. The length of the string is returned.
706 /* Skip the leading string terminator */
709 /* Read the string */
712 if (C == StringTerm) {
715 if (C == '\n' || C == EOF) {
716 Error ("Newline in string constant");
720 /* Check for string length, print an error message once */
721 if (I == MAX_STR_LEN) {
722 Error ("Maximum string size exceeded");
723 } else if (I < MAX_STR_LEN) {
728 /* Skip the character */
732 /* Skip the trailing terminator */
735 /* Terminate the string */
736 if (I >= MAX_STR_LEN) {
741 /* Return the length of the string */
747 static int Sweet16Reg (const char* Ident)
748 /* Check if the given identifier is a sweet16 register. Return -1 if this is
749 * not the case, return the register number otherwise.
755 if (Ident[0] != 'r' && Ident[0] != 'R') {
758 if (!IsDigit (Ident[1])) {
762 if (sscanf (Ident+1, "%u%c", &RegNum, &Check) != 1 || RegNum > 15) {
763 /* Invalid register */
767 /* The register number is valid */
773 void NextRawTok (void)
774 /* Read the next raw token from the input stream */
776 /* If we've a forced end of assembly, don't read further */
783 /* Check if we have tokens from another input source */
784 if (InputFromStack ()) {
789 /* Skip whitespace, remember if we had some */
790 if ((WS = IsBlank (C)) != 0) {
793 } while (IsBlank (C));
796 /* Mark the file position of the next token */
797 Source->Func->MarkStart (Source);
799 /* Hex number or PC symbol? */
803 /* Hex digit must follow or DollarIsPC must be enabled */
809 Error ("Hexadecimal digit expected");
813 /* Read the number */
815 while (IsXDigit (C)) {
816 if (IVal & 0xF0000000) {
817 Error ("Overflow in hexadecimal number");
820 IVal = (IVal << 4) + DigitVal (C);
824 /* This is an integer constant */
833 /* 0 or 1 must follow */
835 Error ("Binary digit expected");
838 /* Read the number */
840 while (IsBDigit (C)) {
841 if (IVal & 0x80000000) {
842 Error ("Overflow in binary number");
845 IVal = (IVal << 1) + DigitVal (C);
849 /* This is an integer constant */
864 /* Ignore leading zeros */
869 /* Read the number into Buf counting the digits */
871 while (IsXDigit (C)) {
873 /* Buf is big enough to allow any decimal and hex number to
874 * overflow, so ignore excess digits here, they will be detected
875 * when we convert the value.
877 if (Digits < sizeof (Buf)) {
884 /* Allow zilog/intel style hex numbers with a 'h' suffix */
885 if (C == 'h' || C == 'H') {
888 Max = 0xFFFFFFFFUL / 16;
891 Max = 0xFFFFFFFFUL / 10;
894 /* Convert the number using the given base */
896 for (I = 0; I < Digits; ++I) {
898 Error ("Number out of range");
902 DVal = DigitVal (Buf[I]);
904 Error ("Invalid digits in number");
908 IVal = (IVal * Base) + DVal;
911 /* This is an integer constant */
916 /* Control command? */
919 /* Remember and skip the dot */
922 /* Check if it's just a dot */
923 if (!IsIdStart (C)) {
930 /* Read the remainder of the identifier */
934 /* Dot keyword, search for it */
935 Tok = FindDotKeyword ();
936 if (Tok == TOK_NONE) {
939 if (!LeadingDotInIdents) {
940 /* Invalid pseudo instruction */
941 Error ("`%s' is not a recognized control command", SVal);
945 /* An identifier with a dot. Check if it's a define style
948 if (IsDefine (SVal)) {
949 /* This is a define style macro - expand it */
954 /* Just an identifier with a dot */
962 /* Indirect op for sweet16 cpu. Must check this before checking for local
963 * symbols, because these may also use the '@' symbol.
965 if (CPU == CPU_SWEET16 && C == '@') {
972 if (C == LocalStart) {
974 /* Read the identifier */
977 /* Start character alone is not enough */
978 if (SVal [1] == '\0') {
979 Error ("Invalid cheap local symbol");
983 /* A local identifier */
984 Tok = TOK_LOCAL_IDENT;
989 /* Identifier or keyword? */
992 /* Read the identifier */
995 /* Check for special names. Bail out if we have identified the type of
996 * the token. Go on if the token is an identifier.
998 if (SVal[1] == '\0') {
999 switch (toupper (SVal [0])) {
1004 Tok = TOK_OVERRIDE_ABS;
1013 Tok = TOK_OVERRIDE_FAR;
1033 Tok = TOK_OVERRIDE_ZP;
1042 } else if (CPU == CPU_SWEET16 && (IVal = Sweet16Reg (SVal)) >= 0) {
1044 /* A sweet16 register number in sweet16 mode */
1050 /* Check for define style macro */
1051 if (IsDefine (SVal)) {
1052 /* Macro - expand it */
1062 /* Ok, let's do the switch */
1117 Tok = TOK_NAMESPACE;
1156 while (C != '\n' && C != EOF) {
1201 } else if (C == '<') {
1204 } else if (C == '>') {
1227 } else if (C == '>') {
1241 /* Hack: If we allow ' as terminating character for strings, read
1242 * the following stuff as a string, and check for a one character
1245 if (LooseStringTerm) {
1246 if (ReadStringConst ('\'') == 1) {
1253 /* Always a character constant */
1255 if (C == EOF || IsControl (C)) {
1256 Error ("Illegal character constant");
1263 if (!MissingCharTerm) {
1264 Error ("Illegal character constant");
1273 ReadStringConst ('\"');
1278 /* Line continuation? */
1282 /* Handle as white space */
1297 /* In case of the main file, do not close it, but return EOF. */
1298 if (Source && Source->Next) {
1307 /* If we go here, we could not identify the current character. Skip it
1310 Error ("Invalid input character: 0x%02X", C & 0xFF);
1317 int TokHasSVal (enum Token Tok)
1318 /* Return true if the given token has an attached SVal */
1320 return (Tok == TOK_IDENT || TOK_LOCAL_IDENT || Tok == TOK_STRCON);
1325 int TokHasIVal (enum Token Tok)
1326 /* Return true if the given token has an attached IVal */
1328 return (Tok == TOK_INTCON || Tok == TOK_CHARCON || Tok == TOK_REG);
1333 int GetSubKey (const char** Keys, unsigned Count)
1334 /* Search for a subkey in a table of keywords. The current token must be an
1335 * identifier and all keys must be in upper case. The identifier will be
1336 * uppercased in the process. The function returns the index of the keyword,
1337 * or -1 if the keyword was not found.
1342 /* Must have an identifier */
1343 PRECONDITION (Tok == TOK_IDENT);
1345 /* If we aren't in ignore case mode, we have to uppercase the identifier */
1350 /* Do a linear search (a binary search is not worth the effort) */
1351 for (I = 0; I < Count; ++I) {
1352 if (strcmp (SVal, Keys [I]) == 0) {
1364 unsigned char ParseAddrSize (void)
1365 /* Check if the next token is a keyword that denotes an address size specifier.
1366 * If so, return the corresponding address size constant, otherwise output an
1367 * error message and return ADDR_SIZE_DEFAULT.
1370 static const char* Keys[] = {
1371 "DIRECT", "ZEROPAGE", "ZP",
1372 "ABSOLUTE", "ABS", "NEAR",
1377 /* Check for an identifier */
1378 if (Tok != TOK_IDENT) {
1379 Error ("Address size specifier expected");
1380 return ADDR_SIZE_DEFAULT;
1383 /* Search for the attribute */
1384 switch (GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]))) {
1387 case 2: return ADDR_SIZE_ZP;
1390 case 5: return ADDR_SIZE_ABS;
1391 case 6: return ADDR_SIZE_FAR;
1393 case 8: return ADDR_SIZE_LONG;
1395 Error ("Address size specifier expected");
1396 return ADDR_SIZE_DEFAULT;
1402 void InitScanner (const char* InFile)
1403 /* Initialize the scanner, open the given input file */
1405 /* Open the input file */
1406 NewInputFile (InFile);
1411 void DoneScanner (void)
1412 /* Release scanner resources */