]> git.sur5r.net Git - cc65/blob - src/cc65/scanstrbuf.c
Rewrote most of the #pragma parsing code. I'm still not satisfied, but at
[cc65] / src / cc65 / scanstrbuf.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 scanstrbuf.c                              */
4 /*                                                                           */
5 /*                     Small scanner for input from a StrBuf                 */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2002-2009, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 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 /* common */
37 #include "chartype.h"
38 #include "tgttrans.h"
39
40 /* cc65 */
41 #include "datatype.h"
42 #include "error.h"
43 #include "hexval.h"
44 #include "ident.h"
45 #include "scanstrbuf.h"
46
47
48
49 /*****************************************************************************/
50 /*                               Helper functions                            */
51 /*****************************************************************************/
52
53
54
55 static int ParseChar (StrBuf* B)
56 /* Parse a character. Converts \n into EOL, etc. */
57 {
58     unsigned I;
59     unsigned Val;
60     int C;
61
62     /* Check for escape chars */
63     if ((C = SB_Get (B)) == '\\') {
64         switch (SB_Peek (B)) {
65             case '?':
66                 C = '?';
67                 SB_Skip (B);
68                 break;
69             case 'a':
70                 C = '\a';
71                 SB_Skip (B);
72                 break;
73             case 'b':
74                 C = '\b';
75                 SB_Skip (B);
76                 break;
77             case 'f':
78                 C = '\f';
79                 SB_Skip (B);
80                 break;
81             case 'r':
82                 C = '\r';
83                 SB_Skip (B);
84                 break;
85             case 'n':
86                 C = '\n';
87                 SB_Skip (B);
88                 break;
89             case 't':
90                 C = '\t';
91                 SB_Skip (B);
92                 break;
93             case 'v':
94                 C = '\v';
95                 SB_Skip (B);
96                 break;
97             case '\"':
98                 C = '\"';
99                 SB_Skip (B);
100                 break;
101             case '\'':
102                 C = '\'';
103                 SB_Skip (B);
104                 break;
105             case '\\':
106                 C = '\\';
107                 SB_Skip (B);
108                 break;
109             case 'x':
110             case 'X':
111                 /* Hex character constant */
112                 SB_Skip (B);
113                 C = HexVal (SB_Get (B)) << 4;
114                 C |= HexVal (SB_Get (B));
115                 break;
116             case '0':
117             case '1':
118             case '2':
119             case '3':
120             case '4':
121             case '5':
122             case '6':
123             case '7':
124                 /* Octal constant */
125                 I = 0;
126                 Val = SB_Get (B) - '0';
127                 while (SB_Peek (B) >= '0' && SB_Peek (B) <= '7' && ++I <= 3) {
128                     Val = (Val << 3) | (SB_Get (B) - '0');
129                 }
130                 C = (int) Val;
131                 if (Val > 256) {
132                     Error ("Character constant out of range");
133                     C = ' ';
134                 }
135                 break;
136             default:
137                 Error ("Illegal character constant 0x%02X", SB_Get (B));
138                 C = ' ';
139                 break;
140         }
141     }
142
143     /* Return the character */
144     return C;
145 }
146
147
148
149 /*****************************************************************************/
150 /*                                   Code                                    */
151 /*****************************************************************************/
152
153
154
155 void SB_SkipWhite (StrBuf* B)
156 /* Skip whitespace in the string buffer */
157 {
158     while (IsBlank (SB_Peek (B))) {
159         SB_Skip (B);
160     }
161 }
162
163
164
165 int SB_GetSym (StrBuf* B, StrBuf* Ident, const char* SpecialChars)
166 /* Get a symbol from the string buffer. If SpecialChars is not NULL, it
167  * points to a string that contains characters allowed within the string in
168  * addition to letters, digits and the underline. Note: The identifier must
169  * still begin with a letter.
170  * Returns 1 if a symbol was found and 0 otherwise but doesn't output any
171  * errors.
172  */
173 {
174     /* Handle a NULL argument for SpecialChars transparently */
175     if (SpecialChars == 0) {
176         SpecialChars = "";
177     }
178
179     /* Clear Ident */
180     SB_Clear (Ident);
181
182     if (IsIdent (SB_Peek (B))) {
183         char C = SB_Peek (B);
184         do {
185             SB_AppendChar (Ident, C);
186             SB_Skip (B);
187             C = SB_Peek (B);
188         } while (IsIdent (C) || IsDigit (C) || strchr (SpecialChars, C) != 0);
189         SB_Terminate (Ident);
190         return 1;
191     } else {
192         return 0;
193     }
194 }
195
196
197
198 int SB_GetString (StrBuf* B, StrBuf* S)
199 /* Get a string from the string buffer. Returns 1 if a string was found and 0
200  * otherwise. Errors are only output in case of invalid strings (missing end
201  * of string).
202  */
203 {
204     char C;
205
206     /* Clear S */
207     SB_Clear (S);
208
209     /* A string starts with quote marks */
210     if (SB_Peek (B) == '\"') {
211
212         /* String follows, be sure to concatenate strings */
213         while (SB_Peek (B) == '\"') {
214
215             /* Skip the quote char */
216             SB_Skip (B);
217
218             /* Read the actual string contents */
219             while ((C = SB_Peek (B)) != '\"') {
220                 if (C == '\0') {
221                     Error ("Unexpected end of string");
222                     break;
223                 }
224                 SB_AppendChar (S, ParseChar (B));
225             }
226
227             /* Skip the closing quote char if there was one */
228             SB_Skip (B);
229
230             /* Skip white space, read new input */
231             SB_SkipWhite (B);
232         }
233
234         /* Terminate the string */
235         SB_Terminate (S);
236
237         /* Success */
238         return 1;
239
240     } else {
241
242         /* Not a string */
243         SB_Terminate (S);
244         return 0;
245     }
246 }
247
248
249
250 int SB_GetNumber (StrBuf* B, long* Val)
251 /* Get a number from the string buffer. Accepted formats are decimal, octal,
252  * hex and character constants. Numeric constants may be preceeded by a
253  * minus or plus sign. The function returns 1 if a number was found and
254  * zero otherwise. Errors are only output for invalid numbers.
255  */
256 {
257     int      Sign;
258     char     C;
259     unsigned Base;
260     unsigned DigitVal;
261
262
263     /* Initialize Val */
264     *Val = 0;
265
266     /* Handle character constants */
267     if (SB_Peek (B) == '\'') {
268
269         /* Character constant */
270         SB_Skip (B);
271         *Val = SignExtendChar (TgtTranslateChar (ParseChar (B)));
272         if (SB_Peek (B) != '\'') {
273             Error ("`\'' expected");
274             return 0;
275         } else {
276             /* Skip the quote */
277             SB_Skip (B);
278             return 1;
279         }
280     }
281
282     /* Check for a sign. A sign must be followed by a digit, otherwise it's
283      * not a number
284      */
285     Sign = 1;
286     switch (SB_Peek (B)) {
287         case '-':
288             Sign = -1;
289             /* FALLTHROUGH */
290         case '+':
291             if (!IsDigit (SB_LookAt (B, SB_GetIndex (B) + 1))) {
292                 return 0;
293             }
294             SB_Skip (B);
295             break;
296     }
297
298     /* We must have a digit now, otherwise its not a number */
299     C = SB_Peek (B);
300     if (!IsDigit (C)) {
301         return 0;
302     }
303
304     /* Determine the base */
305     if (C == '0') {
306         /* Hex or octal */
307         SB_Skip (B);
308         if (tolower (SB_Peek (B)) == 'x') {
309             SB_Skip (B);
310             Base = 16;
311             if (!IsXDigit (SB_Peek (B))) {
312                 Error ("Invalid hexadecimal number");
313                 return 0;
314             }
315         } else {
316             Base = 8;
317         }
318     } else {
319         Base = 10;
320     }
321
322     /* Read the number */
323     while (IsXDigit (C = SB_Peek (B)) && (DigitVal = HexVal (C)) < Base) {
324         *Val = (*Val * Base) + DigitVal;
325         SB_Skip (B);
326     }
327
328     /* Allow optional 'U' and 'L' modifiers */
329     C = SB_Peek (B);
330     if (C == 'u' || C == 'U') {
331         SB_Skip (B);
332         C = SB_Peek (B);
333         if (C == 'l' || C == 'L') {
334             SB_Skip (B);
335         }
336     } else if (C == 'l' || C == 'L') {
337         SB_Skip (B);
338         C = SB_Peek (B);
339         if (C == 'u' || C == 'U') {
340             SB_Skip (B);
341         }
342     }
343
344     /* Success, value read is in Val */
345     *Val *= Sign;
346     return 1;
347 }
348
349
350