]> git.sur5r.net Git - cc65/blob - src/da65/scanner.c
9b58981df0420da48ed452a8a8b6015f3e382163
[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
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                 if (C == EOF || C == '\n') {
253                     InfoError ("Unterminated string");
254                 }
255                 if (I < CFG_MAX_IDENT_LEN) {
256                     InfoSVal [I++] = C;
257                 }
258                 NextChar ();
259             }
260             NextChar ();
261             InfoSVal [I] = '\0';
262             InfoTok = INFOTOK_STRCON;
263             break;
264
265         case '\'':
266             NextChar ();
267             if (C == EOF || IsControl (C)) {
268                 InfoError ("Invalid character constant");
269             }
270             InfoIVal = C;
271             NextChar ();
272             if (C != '\'') {
273                 InfoError ("Unterminated character constant");
274             }
275             NextChar ();
276             InfoTok = INFOTOK_CHARCON;
277             break;
278
279         case '#':
280             /* Comment */
281             while (C != '\n' && C != EOF) {
282                 NextChar ();
283             }
284             if (C != EOF) {
285                 goto Again;
286             }
287             InfoTok = INFOTOK_EOF;
288             break;
289
290         case EOF:
291             InfoTok = INFOTOK_EOF;
292             break;
293
294         default:
295             InfoError ("Invalid character `%c'", C);
296
297     }
298 }
299
300
301
302 void InfoConsume (unsigned T, const char* Msg)
303 /* Skip a token, print an error message if not found */
304 {
305     if (InfoTok != T) {
306         InfoError (Msg);
307     }
308     InfoNextTok ();
309 }
310
311
312
313 void InfoConsumeLCurly (void)
314 /* Consume a left curly brace */
315 {
316     InfoConsume (INFOTOK_LCURLY, "`{' expected");
317 }
318
319
320
321 void InfoConsumeRCurly (void)
322 /* Consume a right curly brace */
323 {
324     InfoConsume (INFOTOK_RCURLY, "`}' expected");
325 }
326
327
328
329 void InfoConsumeSemi (void)
330 /* Consume a semicolon */
331 {
332     InfoConsume (INFOTOK_SEMI, "`;' expected");
333 }
334
335
336
337 void InfoConsumeColon (void)
338 /* Consume a colon */
339 {
340     InfoConsume (INFOTOK_COLON, "`:' expected");
341 }
342
343
344
345 void InfoOptionalComma (void)
346 /* Consume a comma if there is one */
347 {
348     if (InfoTok == INFOTOK_COMMA) {
349         InfoNextTok ();
350     }
351 }
352
353
354
355 void InfoOptionalAssign (void)
356 /* Consume an equal sign if there is one */
357 {
358     if (InfoTok == INFOTOK_EQ) {
359         InfoNextTok ();
360     }
361 }
362
363
364
365 void InfoAssureInt (void)
366 /* Make sure the next token is an integer */
367 {
368     if (InfoTok != INFOTOK_INTCON) {
369         InfoError ("Integer constant expected");
370     }
371 }
372
373
374
375 void InfoAssureStr (void)
376 /* Make sure the next token is a string constant */
377 {
378     if (InfoTok != INFOTOK_STRCON) {
379         InfoError ("String constant expected");
380     }
381 }
382
383
384
385 void InfoAssureChar (void)
386 /* Make sure the next token is a char constant */
387 {
388     if (InfoTok != INFOTOK_STRCON) {
389         InfoError ("Character constant expected");
390     }
391 }
392
393
394
395 void InfoAssureIdent (void)
396 /* Make sure the next token is an identifier */
397 {
398     if (InfoTok != INFOTOK_IDENT) {
399         InfoError ("Identifier expected");
400     }
401 }
402
403
404
405 void InfoRangeCheck (long Lo, long Hi)
406 /* Check the range of InfoIVal */
407 {
408     if (InfoIVal < Lo || InfoIVal > Hi) {
409         InfoError ("Range error");
410     }
411 }
412
413
414
415 void InfoSpecialToken (const IdentTok* Table, unsigned Size, const char* Name)
416 /* Map an identifier to one of the special tokens in the table */
417 {
418     unsigned I;
419
420     /* We need an identifier */
421     if (InfoTok == INFOTOK_IDENT) {
422
423         /* Make it upper case */
424         I = 0;
425         while (InfoSVal [I]) {
426             InfoSVal [I] = toupper (InfoSVal [I]);
427             ++I;
428         }
429
430         /* Linear search */
431         for (I = 0; I < Size; ++I) {
432             if (strcmp (InfoSVal, Table [I].Ident) == 0) {
433                 InfoTok = Table [I].Tok;
434                 return;
435             }
436         }
437
438     }
439
440     /* Not found or no identifier */
441     InfoError ("%s expected", Name);
442 }
443
444
445
446 void InfoBoolToken (void)
447 /* Map an identifier or integer to a boolean token */
448 {
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    },
456     };
457
458     /* If we have an identifier, map it to a boolean token */
459     if (InfoTok == INFOTOK_IDENT) {
460         InfoSpecialToken (Booleans, ENTRY_COUNT (Booleans), "Boolean");
461     } else {
462         /* We expected an integer here */
463         if (InfoTok != INFOTOK_INTCON) {
464             InfoError ("Boolean value expected");
465         }
466         InfoTok = (InfoIVal == 0)? INFOTOK_FALSE : INFOTOK_TRUE;
467     }
468 }
469
470
471
472 void InfoSetName (const char* Name)
473 /* Set a name for a config file */
474 {
475     InfoFile = Name;
476 }
477
478
479
480 const char* InfoGetName (void)
481 /* Get the name of the config file */
482 {
483     return InfoFile? InfoFile : "";
484 }
485
486
487
488 int InfoAvail ()
489 /* Return true if we have an info file given */
490 {
491     return (InfoFile != 0);
492 }
493
494
495
496 void InfoOpenInput (void)
497 /* Open the input file */
498 {
499     /* Open the file */
500     InputFile = fopen (InfoFile, "r");
501     if (InputFile == 0) {
502         Error ("Cannot open `%s': %s", InfoFile, strerror (errno));
503     }
504
505     /* Initialize variables */
506     C         = ' ';
507     InputLine = 1;
508     InputCol  = 0;
509
510     /* Start the ball rolling ... */
511     InfoNextTok ();
512 }
513
514
515
516 void InfoCloseInput (void)
517 /* Close the input file if we have one */
518 {
519     /* Close the input file if we had one */
520     if (InputFile) {
521         (void) fclose (InputFile);
522         InputFile = 0;
523     }
524 }
525
526
527
528