1 /*****************************************************************************/
5 /* Configuration file scanner for the da65 disassembler */
9 /* (C) 2000-2005 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;
256 if (C == EOF || C == '\n') {
257 InfoError ("Unterminated string");
261 case '\"': C = '\"'; break;
262 case '\'': C = '\''; break;
263 default: InfoError ("Invalid escape char: %c", C);
266 if (I < CFG_MAX_IDENT_LEN) {
273 InfoTok = INFOTOK_STRCON;
278 if (C == EOF || IsControl (C)) {
279 InfoError ("Invalid character constant");
284 InfoError ("Unterminated character constant");
287 InfoTok = INFOTOK_CHARCON;
292 while (C != '\n' && C != EOF) {
298 InfoTok = INFOTOK_EOF;
302 InfoTok = INFOTOK_EOF;
306 InfoError ("Invalid character `%c'", C);
313 void InfoConsume (unsigned T, const char* Msg)
314 /* Skip a token, print an error message if not found */
324 void InfoConsumeLCurly (void)
325 /* Consume a left curly brace */
327 InfoConsume (INFOTOK_LCURLY, "`{' expected");
332 void InfoConsumeRCurly (void)
333 /* Consume a right curly brace */
335 InfoConsume (INFOTOK_RCURLY, "`}' expected");
340 void InfoConsumeSemi (void)
341 /* Consume a semicolon */
343 InfoConsume (INFOTOK_SEMI, "`;' expected");
348 void InfoConsumeColon (void)
349 /* Consume a colon */
351 InfoConsume (INFOTOK_COLON, "`:' expected");
356 void InfoOptionalComma (void)
357 /* Consume a comma if there is one */
359 if (InfoTok == INFOTOK_COMMA) {
366 void InfoOptionalAssign (void)
367 /* Consume an equal sign if there is one */
369 if (InfoTok == INFOTOK_EQ) {
376 void InfoAssureInt (void)
377 /* Make sure the next token is an integer */
379 if (InfoTok != INFOTOK_INTCON) {
380 InfoError ("Integer constant expected");
386 void InfoAssureStr (void)
387 /* Make sure the next token is a string constant */
389 if (InfoTok != INFOTOK_STRCON) {
390 InfoError ("String constant expected");
396 void InfoAssureChar (void)
397 /* Make sure the next token is a char constant */
399 if (InfoTok != INFOTOK_STRCON) {
400 InfoError ("Character constant expected");
406 void InfoAssureIdent (void)
407 /* Make sure the next token is an identifier */
409 if (InfoTok != INFOTOK_IDENT) {
410 InfoError ("Identifier expected");
416 void InfoRangeCheck (long Lo, long Hi)
417 /* Check the range of InfoIVal */
419 if (InfoIVal < Lo || InfoIVal > Hi) {
420 InfoError ("Range error");
426 void InfoSpecialToken (const IdentTok* Table, unsigned Size, const char* Name)
427 /* Map an identifier to one of the special tokens in the table */
431 /* We need an identifier */
432 if (InfoTok == INFOTOK_IDENT) {
434 /* Make it upper case */
436 while (InfoSVal [I]) {
437 InfoSVal [I] = toupper (InfoSVal [I]);
442 for (I = 0; I < Size; ++I) {
443 if (strcmp (InfoSVal, Table [I].Ident) == 0) {
444 InfoTok = Table [I].Tok;
451 /* Not found or no identifier */
452 InfoError ("%s expected", Name);
457 void InfoBoolToken (void)
458 /* Map an identifier or integer to a boolean token */
460 static const IdentTok Booleans [] = {
461 { "YES", INFOTOK_TRUE },
462 { "NO", INFOTOK_FALSE },
463 { "TRUE", INFOTOK_TRUE },
464 { "FALSE", INFOTOK_FALSE },
465 { "ON", INFOTOK_TRUE },
466 { "OFF", INFOTOK_FALSE },
469 /* If we have an identifier, map it to a boolean token */
470 if (InfoTok == INFOTOK_IDENT) {
471 InfoSpecialToken (Booleans, ENTRY_COUNT (Booleans), "Boolean");
473 /* We expected an integer here */
474 if (InfoTok != INFOTOK_INTCON) {
475 InfoError ("Boolean value expected");
477 InfoTok = (InfoIVal == 0)? INFOTOK_FALSE : INFOTOK_TRUE;
483 void InfoSetName (const char* Name)
484 /* Set a name for a config file */
491 const char* InfoGetName (void)
492 /* Get the name of the config file */
494 return InfoFile? InfoFile : "";
500 /* Return true if we have an info file given */
502 return (InfoFile != 0);
507 void InfoOpenInput (void)
508 /* Open the input file */
511 InputFile = fopen (InfoFile, "r");
512 if (InputFile == 0) {
513 Error ("Cannot open `%s': %s", InfoFile, strerror (errno));
516 /* Initialize variables */
521 /* Start the ball rolling ... */
527 void InfoCloseInput (void)
528 /* Close the input file if we have one */
530 /* Close the input file if we had one */
532 (void) fclose (InputFile);