1 /*****************************************************************************/
5 /* Configuration file scanner for the da65 disassembler */
9 /* (C) 2000-2003 Ullrich von Bassewitz */
10 /* Römerstrasse 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 /*****************************************************************************/
52 /*****************************************************************************/
54 /*****************************************************************************/
58 /* Current token and attributes */
60 char InfoSVal [CFG_MAX_IDENT_LEN+1];
64 unsigned InfoErrorLine;
65 unsigned InfoErrorCol;
67 /* Input sources for the configuration */
68 static const char* InfoFile = 0;
70 /* Other input stuff */
72 static unsigned InputLine = 1;
73 static unsigned InputCol = 0;
74 static FILE* InputFile = 0;
78 /*****************************************************************************/
80 /*****************************************************************************/
84 void InfoWarning (const char* Format, ...)
85 /* Print a warning message adding file name and line number of the config file */
90 va_start (ap, Format);
91 xvsprintf (Buf, sizeof (Buf), Format, ap);
94 Warning ("%s(%u): %s", InfoFile, InfoErrorLine, Buf);
99 void InfoError (const char* Format, ...)
100 /* Print an error message adding file name and line number of the config file */
105 va_start (ap, Format);
106 xvsprintf (Buf, sizeof (Buf), Format, ap);
109 Error ("%s(%u): %s", InfoFile, InfoErrorLine, Buf);
114 /*****************************************************************************/
116 /*****************************************************************************/
120 static void NextChar (void)
121 /* Read the next character from the input file */
123 /* Read from the file */
124 C = getc (InputFile);
140 static unsigned DigitVal (int C)
141 /* Return the value for a numeric digit */
146 return toupper (C) - 'A' + 10;
152 void InfoNextTok (void)
153 /* Read the next token from the input stream */
159 /* Skip whitespace */
160 while (IsSpace (C)) {
164 /* Remember the current position */
165 InfoErrorLine = InputLine;
166 InfoErrorCol = InputCol;
169 if (C == '_' || IsAlpha (C)) {
171 /* Read the identifier */
173 while (C == '_' || IsAlNum (C)) {
174 if (I < CFG_MAX_IDENT_LEN) {
180 InfoTok = INFOTOK_IDENT;
188 InfoError ("Hex digit expected");
191 while (IsXDigit (C)) {
192 InfoIVal = InfoIVal * 16 + DigitVal (C);
195 InfoTok = INFOTOK_INTCON;
199 /* Decimal number? */
202 while (IsDigit (C)) {
203 InfoIVal = InfoIVal * 10 + DigitVal (C);
206 InfoTok = INFOTOK_INTCON;
210 /* Other characters */
215 InfoTok = INFOTOK_LCURLY;
220 InfoTok = INFOTOK_RCURLY;
225 InfoTok = INFOTOK_SEMI;
230 InfoTok = INFOTOK_DOT;
235 InfoTok = INFOTOK_COMMA;
240 InfoTok = INFOTOK_EQ;
245 InfoTok = INFOTOK_COLON;
252 if (C == EOF || C == '\n') {
253 InfoError ("Unterminated string");
255 if (I < CFG_MAX_IDENT_LEN) {
262 InfoTok = INFOTOK_STRCON;
267 while (C != '\n' && C != EOF) {
273 InfoTok = INFOTOK_EOF;
277 InfoTok = INFOTOK_EOF;
281 InfoError ("Invalid character `%c'", C);
288 void InfoConsume (unsigned T, const char* Msg)
289 /* Skip a token, print an error message if not found */
299 void InfoConsumeLCurly (void)
300 /* Consume a left curly brace */
302 InfoConsume (INFOTOK_LCURLY, "`{' expected");
307 void InfoConsumeRCurly (void)
308 /* Consume a right curly brace */
310 InfoConsume (INFOTOK_RCURLY, "`}' expected");
315 void InfoConsumeSemi (void)
316 /* Consume a semicolon */
318 InfoConsume (INFOTOK_SEMI, "`;' expected");
323 void InfoConsumeColon (void)
324 /* Consume a colon */
326 InfoConsume (INFOTOK_COLON, "`:' expected");
331 void InfoOptionalComma (void)
332 /* Consume a comma if there is one */
334 if (InfoTok == INFOTOK_COMMA) {
341 void InfoOptionalAssign (void)
342 /* Consume an equal sign if there is one */
344 if (InfoTok == INFOTOK_EQ) {
351 void InfoAssureInt (void)
352 /* Make sure the next token is an integer */
354 if (InfoTok != INFOTOK_INTCON) {
355 InfoError ("Integer constant expected");
361 void InfoAssureStr (void)
362 /* Make sure the next token is a string constant */
364 if (InfoTok != INFOTOK_STRCON) {
365 InfoError ("String constant expected");
371 void InfoAssureIdent (void)
372 /* Make sure the next token is an identifier */
374 if (InfoTok != INFOTOK_IDENT) {
375 InfoError ("Identifier expected");
381 void InfoRangeCheck (long Lo, long Hi)
382 /* Check the range of InfoIVal */
384 if (InfoIVal < Lo || InfoIVal > Hi) {
385 InfoError ("Range error");
391 void InfoSpecialToken (const IdentTok* Table, unsigned Size, const char* Name)
392 /* Map an identifier to one of the special tokens in the table */
396 /* We need an identifier */
397 if (InfoTok == INFOTOK_IDENT) {
399 /* Make it upper case */
401 while (InfoSVal [I]) {
402 InfoSVal [I] = toupper (InfoSVal [I]);
407 for (I = 0; I < Size; ++I) {
408 if (strcmp (InfoSVal, Table [I].Ident) == 0) {
409 InfoTok = Table [I].Tok;
416 /* Not found or no identifier */
417 InfoError ("%s expected", Name);
422 void InfoBoolToken (void)
423 /* Map an identifier or integer to a boolean token */
425 static const IdentTok Booleans [] = {
426 { "YES", INFOTOK_TRUE },
427 { "NO", INFOTOK_FALSE },
428 { "TRUE", INFOTOK_TRUE },
429 { "FALSE", INFOTOK_FALSE },
432 /* If we have an identifier, map it to a boolean token */
433 if (InfoTok == INFOTOK_IDENT) {
434 InfoSpecialToken (Booleans, ENTRY_COUNT (Booleans), "Boolean");
436 /* We expected an integer here */
437 if (InfoTok != INFOTOK_INTCON) {
438 InfoError ("Boolean value expected");
440 InfoTok = (InfoIVal == 0)? INFOTOK_FALSE : INFOTOK_TRUE;
446 void InfoSetName (const char* Name)
447 /* Set a name for a config file */
454 const char* InfoGetName (void)
455 /* Get the name of the config file */
457 return InfoFile? InfoFile : "";
463 /* Return true if we have an info file given */
465 return (InfoFile != 0);
470 void InfoOpenInput (void)
471 /* Open the input file */
474 InputFile = fopen (InfoFile, "r");
475 if (InputFile == 0) {
476 Error ("Cannot open `%s': %s", InfoFile, strerror (errno));
479 /* Initialize variables */
484 /* Start the ball rolling ... */
490 void InfoCloseInput (void)
491 /* Close the input file if we have one */
493 /* Close the input file if we had one */
495 (void) fclose (InputFile);