]> git.sur5r.net Git - cc65/blob - src/da65/scanner.c
Removed (pretty inconsistently used) tab chars from source code base.
[cc65] / src / da65 / scanner.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 scanner.c                                 */
4 /*                                                                           */
5 /*           Configuration file scanner for the da65 disassembler            */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2000-2005 Ullrich von Bassewitz                                       */
10 /*               Römerstrasse 52                                             */
11 /*               D-70794 Filderstadt                                         */
12 /* EMail:        uz@cc65.org                                                 */
13 /*                                                                           */
14 /*                                                                           */
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.                                    */
18 /*                                                                           */
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:                            */
22 /*                                                                           */
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              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdarg.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <errno.h>
40
41 /* common */
42 #include "chartype.h"
43 #include "xsprintf.h"
44
45 /* ld65 */
46 #include "global.h"
47 #include "error.h"
48 #include "scanner.h"
49
50
51
52 /*****************************************************************************/
53 /*                                   Data                                    */
54 /*****************************************************************************/
55
56
57
58 /* Current token and attributes */
59 unsigned        InfoTok;
60 char            InfoSVal [CFG_MAX_IDENT_LEN+1];
61 long            InfoIVal;
62
63 /* Error location */
64 unsigned                InfoErrorLine;
65 unsigned                InfoErrorCol;
66
67 /* Input sources for the configuration */
68 static const char*      InfoFile        = 0;
69
70 /* Other input stuff */
71 static int              C               = ' ';
72 static unsigned         InputLine       = 1;
73 static unsigned         InputCol        = 0;
74 static FILE*            InputFile       = 0;
75
76
77
78 /*****************************************************************************/
79 /*                              Error handling                               */
80 /*****************************************************************************/
81
82
83
84 void InfoWarning (const char* Format, ...)
85 /* Print a warning message adding file name and line number of the config file */
86 {
87     char Buf [512];
88     va_list ap;
89
90     va_start (ap, Format);
91     xvsprintf (Buf, sizeof (Buf), Format, ap);
92     va_end (ap);
93
94     Warning ("%s(%u): %s", InfoFile, InfoErrorLine, Buf);
95 }
96
97
98
99 void InfoError (const char* Format, ...)
100 /* Print an error message adding file name and line number of the config file */
101 {
102     char Buf [512];
103     va_list ap;
104
105     va_start (ap, Format);
106     xvsprintf (Buf, sizeof (Buf), Format, ap);
107     va_end (ap);
108
109     Error ("%s(%u): %s", InfoFile, InfoErrorLine, Buf);
110 }
111
112
113
114 /*****************************************************************************/
115 /*                                   Code                                    */
116 /*****************************************************************************/
117
118
119
120 static void NextChar (void)
121 /* Read the next character from the input file */
122 {
123     /* Read from the file */
124     C = getc (InputFile);
125
126     /* Count columns */
127     if (C != EOF) {
128         ++InputCol;
129     }
130
131     /* Count lines */
132     if (C == '\n') {
133         ++InputLine;
134         InputCol = 0;
135     }
136 }
137
138
139
140 static unsigned DigitVal (int C)
141 /* Return the value for a numeric digit */
142 {
143     if (IsDigit (C)) {
144         return C - '0';
145     } else {
146         return toupper (C) - 'A' + 10;
147     }
148 }
149
150
151
152 void InfoNextTok (void)
153 /* Read the next token from the input stream */
154 {
155     unsigned I;
156     int      Esc;
157
158 Again:
159     /* Skip whitespace */
160     while (IsSpace (C)) {
161         NextChar ();
162     }
163
164     /* Remember the current position */
165     InfoErrorLine = InputLine;
166     InfoErrorCol  = InputCol;
167
168     /* Identifier? */
169     if (C == '_' || IsAlpha (C)) {
170
171         /* Read the identifier */
172         I = 0;
173         while (C == '_' || IsAlNum (C)) {
174             if (I < CFG_MAX_IDENT_LEN) {
175                 InfoSVal [I++] = C;
176             }
177             NextChar ();
178         }
179         InfoSVal [I] = '\0';
180         InfoTok = INFOTOK_IDENT;
181         return;
182     }
183
184     /* Hex number? */
185     if (C == '$') {
186         NextChar ();
187         if (!IsXDigit (C)) {
188             InfoError ("Hex digit expected");
189         }
190         InfoIVal = 0;
191         while (IsXDigit (C)) {
192             InfoIVal = InfoIVal * 16 + DigitVal (C);
193             NextChar ();
194         }
195         InfoTok = INFOTOK_INTCON;
196         return;
197     }
198
199     /* Decimal number? */
200     if (IsDigit (C)) {
201         InfoIVal = 0;
202         while (IsDigit (C)) {
203             InfoIVal = InfoIVal * 10 + DigitVal (C);
204             NextChar ();
205         }
206         InfoTok = INFOTOK_INTCON;
207         return;
208     }
209
210     /* Other characters */
211     switch (C) {
212
213         case '{':
214             NextChar ();
215             InfoTok = INFOTOK_LCURLY;
216             break;
217
218         case '}':
219             NextChar ();
220             InfoTok = INFOTOK_RCURLY;
221             break;
222
223         case ';':
224             NextChar ();
225             InfoTok = INFOTOK_SEMI;
226             break;
227
228         case '.':
229             NextChar ();
230             InfoTok = INFOTOK_DOT;
231             break;
232
233         case ',':
234             NextChar ();
235             InfoTok = INFOTOK_COMMA;
236             break;
237
238         case '=':
239             NextChar ();
240             InfoTok = INFOTOK_EQ;
241             break;
242
243         case ':':
244             NextChar ();
245             InfoTok = INFOTOK_COLON;
246             break;
247
248         case '\"':
249             NextChar ();
250             I = 0;
251             while (C != '\"') {
252                 Esc = (C == '\\');
253                 if (Esc) {
254                     NextChar ();
255                 }
256                 if (C == EOF || C == '\n') {
257                     InfoError ("Unterminated string");
258                 }
259                 if (Esc) {
260                     switch (C) {
261                         case '\"':      C = '\"';       break;
262                         case '\'':      C = '\'';       break;
263                         default:        InfoError ("Invalid escape char: %c", C);
264                     }
265                 }
266                 if (I < CFG_MAX_IDENT_LEN) {
267                     InfoSVal [I++] = C;
268                 }
269                 NextChar ();
270             }
271             NextChar ();
272             InfoSVal [I] = '\0';
273             InfoTok = INFOTOK_STRCON;
274             break;
275
276         case '\'':
277             NextChar ();
278             if (C == EOF || IsControl (C)) {
279                 InfoError ("Invalid character constant");
280             }
281             InfoIVal = C;
282             NextChar ();
283             if (C != '\'') {
284                 InfoError ("Unterminated character constant");
285             }
286             NextChar ();
287             InfoTok = INFOTOK_CHARCON;
288             break;
289
290         case '#':
291             /* Comment */
292             while (C != '\n' && C != EOF) {
293                 NextChar ();
294             }
295             if (C != EOF) {
296                 goto Again;
297             }
298             InfoTok = INFOTOK_EOF;
299             break;
300
301         case EOF:
302             InfoTok = INFOTOK_EOF;
303             break;
304
305         default:
306             InfoError ("Invalid character `%c'", C);
307
308     }
309 }
310
311
312
313 void InfoConsume (unsigned T, const char* Msg)
314 /* Skip a token, print an error message if not found */
315 {
316     if (InfoTok != T) {
317         InfoError (Msg);
318     }
319     InfoNextTok ();
320 }
321
322
323
324 void InfoConsumeLCurly (void)
325 /* Consume a left curly brace */
326 {
327     InfoConsume (INFOTOK_LCURLY, "`{' expected");
328 }
329
330
331
332 void InfoConsumeRCurly (void)
333 /* Consume a right curly brace */
334 {
335     InfoConsume (INFOTOK_RCURLY, "`}' expected");
336 }
337
338
339
340 void InfoConsumeSemi (void)
341 /* Consume a semicolon */
342 {
343     InfoConsume (INFOTOK_SEMI, "`;' expected");
344 }
345
346
347
348 void InfoConsumeColon (void)
349 /* Consume a colon */
350 {
351     InfoConsume (INFOTOK_COLON, "`:' expected");
352 }
353
354
355
356 void InfoOptionalComma (void)
357 /* Consume a comma if there is one */
358 {
359     if (InfoTok == INFOTOK_COMMA) {
360         InfoNextTok ();
361     }
362 }
363
364
365
366 void InfoOptionalAssign (void)
367 /* Consume an equal sign if there is one */
368 {
369     if (InfoTok == INFOTOK_EQ) {
370         InfoNextTok ();
371     }
372 }
373
374
375
376 void InfoAssureInt (void)
377 /* Make sure the next token is an integer */
378 {
379     if (InfoTok != INFOTOK_INTCON) {
380         InfoError ("Integer constant expected");
381     }
382 }
383
384
385
386 void InfoAssureStr (void)
387 /* Make sure the next token is a string constant */
388 {
389     if (InfoTok != INFOTOK_STRCON) {
390         InfoError ("String constant expected");
391     }
392 }
393
394
395
396 void InfoAssureChar (void)
397 /* Make sure the next token is a char constant */
398 {
399     if (InfoTok != INFOTOK_STRCON) {
400         InfoError ("Character constant expected");
401     }
402 }
403
404
405
406 void InfoAssureIdent (void)
407 /* Make sure the next token is an identifier */
408 {
409     if (InfoTok != INFOTOK_IDENT) {
410         InfoError ("Identifier expected");
411     }
412 }
413
414
415
416 void InfoRangeCheck (long Lo, long Hi)
417 /* Check the range of InfoIVal */
418 {
419     if (InfoIVal < Lo || InfoIVal > Hi) {
420         InfoError ("Range error");
421     }
422 }
423
424
425
426 void InfoSpecialToken (const IdentTok* Table, unsigned Size, const char* Name)
427 /* Map an identifier to one of the special tokens in the table */
428 {
429     unsigned I;
430
431     /* We need an identifier */
432     if (InfoTok == INFOTOK_IDENT) {
433
434         /* Make it upper case */
435         I = 0;
436         while (InfoSVal [I]) {
437             InfoSVal [I] = toupper (InfoSVal [I]);
438             ++I;
439         }
440
441         /* Linear search */
442         for (I = 0; I < Size; ++I) {
443             if (strcmp (InfoSVal, Table [I].Ident) == 0) {
444                 InfoTok = Table [I].Tok;
445                 return;
446             }
447         }
448
449     }
450
451     /* Not found or no identifier */
452     InfoError ("%s expected", Name);
453 }
454
455
456
457 void InfoBoolToken (void)
458 /* Map an identifier or integer to a boolean token */
459 {
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    },
467     };
468
469     /* If we have an identifier, map it to a boolean token */
470     if (InfoTok == INFOTOK_IDENT) {
471         InfoSpecialToken (Booleans, ENTRY_COUNT (Booleans), "Boolean");
472     } else {
473         /* We expected an integer here */
474         if (InfoTok != INFOTOK_INTCON) {
475             InfoError ("Boolean value expected");
476         }
477         InfoTok = (InfoIVal == 0)? INFOTOK_FALSE : INFOTOK_TRUE;
478     }
479 }
480
481
482
483 void InfoSetName (const char* Name)
484 /* Set a name for a config file */
485 {
486     InfoFile = Name;
487 }
488
489
490
491 const char* InfoGetName (void)
492 /* Get the name of the config file */
493 {
494     return InfoFile? InfoFile : "";
495 }
496
497
498
499 int InfoAvail ()
500 /* Return true if we have an info file given */
501 {
502     return (InfoFile != 0);
503 }
504
505
506
507 void InfoOpenInput (void)
508 /* Open the input file */
509 {
510     /* Open the file */
511     InputFile = fopen (InfoFile, "r");
512     if (InputFile == 0) {
513         Error ("Cannot open `%s': %s", InfoFile, strerror (errno));
514     }
515
516     /* Initialize variables */
517     C         = ' ';
518     InputLine = 1;
519     InputCol  = 0;
520
521     /* Start the ball rolling ... */
522     InfoNextTok ();
523 }
524
525
526
527 void InfoCloseInput (void)
528 /* Close the input file if we have one */
529 {
530     /* Close the input file if we had one */
531     if (InputFile) {
532         (void) fclose (InputFile);
533         InputFile = 0;
534     }
535 }
536
537
538
539