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;
252 if (C == EOF || C == '\n') {
253 InfoError ("Unterminated string");
255 if (I < CFG_MAX_IDENT_LEN) {
262 InfoTok = INFOTOK_STRCON;
267 if (C == EOF || IsControl (C)) {
268 InfoError ("Invalid character constant");
273 InfoError ("Unterminated character constant");
276 InfoTok = INFOTOK_CHARCON;
281 while (C != '\n' && C != EOF) {
287 InfoTok = INFOTOK_EOF;
291 InfoTok = INFOTOK_EOF;
295 InfoError ("Invalid character `%c'", C);
302 void InfoConsume (unsigned T, const char* Msg)
303 /* Skip a token, print an error message if not found */
313 void InfoConsumeLCurly (void)
314 /* Consume a left curly brace */
316 InfoConsume (INFOTOK_LCURLY, "`{' expected");
321 void InfoConsumeRCurly (void)
322 /* Consume a right curly brace */
324 InfoConsume (INFOTOK_RCURLY, "`}' expected");
329 void InfoConsumeSemi (void)
330 /* Consume a semicolon */
332 InfoConsume (INFOTOK_SEMI, "`;' expected");
337 void InfoConsumeColon (void)
338 /* Consume a colon */
340 InfoConsume (INFOTOK_COLON, "`:' expected");
345 void InfoOptionalComma (void)
346 /* Consume a comma if there is one */
348 if (InfoTok == INFOTOK_COMMA) {
355 void InfoOptionalAssign (void)
356 /* Consume an equal sign if there is one */
358 if (InfoTok == INFOTOK_EQ) {
365 void InfoAssureInt (void)
366 /* Make sure the next token is an integer */
368 if (InfoTok != INFOTOK_INTCON) {
369 InfoError ("Integer constant expected");
375 void InfoAssureStr (void)
376 /* Make sure the next token is a string constant */
378 if (InfoTok != INFOTOK_STRCON) {
379 InfoError ("String constant expected");
385 void InfoAssureChar (void)
386 /* Make sure the next token is a char constant */
388 if (InfoTok != INFOTOK_STRCON) {
389 InfoError ("Character constant expected");
395 void InfoAssureIdent (void)
396 /* Make sure the next token is an identifier */
398 if (InfoTok != INFOTOK_IDENT) {
399 InfoError ("Identifier expected");
405 void InfoRangeCheck (long Lo, long Hi)
406 /* Check the range of InfoIVal */
408 if (InfoIVal < Lo || InfoIVal > Hi) {
409 InfoError ("Range error");
415 void InfoSpecialToken (const IdentTok* Table, unsigned Size, const char* Name)
416 /* Map an identifier to one of the special tokens in the table */
420 /* We need an identifier */
421 if (InfoTok == INFOTOK_IDENT) {
423 /* Make it upper case */
425 while (InfoSVal [I]) {
426 InfoSVal [I] = toupper (InfoSVal [I]);
431 for (I = 0; I < Size; ++I) {
432 if (strcmp (InfoSVal, Table [I].Ident) == 0) {
433 InfoTok = Table [I].Tok;
440 /* Not found or no identifier */
441 InfoError ("%s expected", Name);
446 void InfoBoolToken (void)
447 /* Map an identifier or integer to a boolean token */
449 static const IdentTok Booleans [] = {
450 { "YES", INFOTOK_TRUE },
451 { "NO", INFOTOK_FALSE },
452 { "TRUE", INFOTOK_TRUE },
453 { "FALSE", INFOTOK_FALSE },
454 { "ON", INFOTOK_TRUE },
455 { "OFF", INFOTOK_FALSE },
458 /* If we have an identifier, map it to a boolean token */
459 if (InfoTok == INFOTOK_IDENT) {
460 InfoSpecialToken (Booleans, ENTRY_COUNT (Booleans), "Boolean");
462 /* We expected an integer here */
463 if (InfoTok != INFOTOK_INTCON) {
464 InfoError ("Boolean value expected");
466 InfoTok = (InfoIVal == 0)? INFOTOK_FALSE : INFOTOK_TRUE;
472 void InfoSetName (const char* Name)
473 /* Set a name for a config file */
480 const char* InfoGetName (void)
481 /* Get the name of the config file */
483 return InfoFile? InfoFile : "";
489 /* Return true if we have an info file given */
491 return (InfoFile != 0);
496 void InfoOpenInput (void)
497 /* Open the input file */
500 InputFile = fopen (InfoFile, "r");
501 if (InputFile == 0) {
502 Error ("Cannot open `%s': %s", InfoFile, strerror (errno));
505 /* Initialize variables */
510 /* Start the ball rolling ... */
516 void InfoCloseInput (void)
517 /* Close the input file if we have one */
519 /* Close the input file if we had one */
521 (void) fclose (InputFile);