]> git.sur5r.net Git - cc65/blob - src/cc65/scanstrbuf.c
Removed (pretty inconsistently used) tab chars from source code base.
[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) || 
189                  (C != '\0' && strchr (SpecialChars, C) != 0));
190         SB_Terminate (Ident);
191         return 1;
192     } else {
193         return 0;
194     }
195 }
196
197
198
199 int SB_GetString (StrBuf* B, StrBuf* S)
200 /* Get a string from the string buffer. Returns 1 if a string was found and 0
201  * otherwise. Errors are only output in case of invalid strings (missing end
202  * of string).
203  */
204 {
205     char C;
206
207     /* Clear S */
208     SB_Clear (S);
209
210     /* A string starts with quote marks */
211     if (SB_Peek (B) == '\"') {
212
213         /* String follows, be sure to concatenate strings */
214         while (SB_Peek (B) == '\"') {
215
216             /* Skip the quote char */
217             SB_Skip (B);
218
219             /* Read the actual string contents */
220             while ((C = SB_Peek (B)) != '\"') {
221                 if (C == '\0') {
222                     Error ("Unexpected end of string");
223                     break;
224                 }
225                 SB_AppendChar (S, ParseChar (B));
226             }
227
228             /* Skip the closing quote char if there was one */
229             SB_Skip (B);
230
231             /* Skip white space, read new input */
232             SB_SkipWhite (B);
233         }
234
235         /* Terminate the string */
236         SB_Terminate (S);
237
238         /* Success */
239         return 1;
240
241     } else {
242
243         /* Not a string */
244         SB_Terminate (S);
245         return 0;
246     }
247 }
248
249
250
251 int SB_GetNumber (StrBuf* B, long* Val)
252 /* Get a number from the string buffer. Accepted formats are decimal, octal,
253  * hex and character constants. Numeric constants may be preceeded by a
254  * minus or plus sign. The function returns 1 if a number was found and
255  * zero otherwise. Errors are only output for invalid numbers.
256  */
257 {
258     int      Sign;
259     char     C;
260     unsigned Base;
261     unsigned DigitVal;
262
263
264     /* Initialize Val */
265     *Val = 0;
266
267     /* Handle character constants */
268     if (SB_Peek (B) == '\'') {
269
270         /* Character constant */
271         SB_Skip (B);
272         *Val = SignExtendChar (TgtTranslateChar (ParseChar (B)));
273         if (SB_Peek (B) != '\'') {
274             Error ("`\'' expected");
275             return 0;
276         } else {
277             /* Skip the quote */
278             SB_Skip (B);
279             return 1;
280         }
281     }
282
283     /* Check for a sign. A sign must be followed by a digit, otherwise it's
284      * not a number
285      */
286     Sign = 1;
287     switch (SB_Peek (B)) {
288         case '-':
289             Sign = -1;
290             /* FALLTHROUGH */
291         case '+':
292             if (!IsDigit (SB_LookAt (B, SB_GetIndex (B) + 1))) {
293                 return 0;
294             }
295             SB_Skip (B);
296             break;
297     }
298
299     /* We must have a digit now, otherwise its not a number */
300     C = SB_Peek (B);
301     if (!IsDigit (C)) {
302         return 0;
303     }
304
305     /* Determine the base */
306     if (C == '0') {
307         /* Hex or octal */
308         SB_Skip (B);
309         if (tolower (SB_Peek (B)) == 'x') {
310             SB_Skip (B);
311             Base = 16;
312             if (!IsXDigit (SB_Peek (B))) {
313                 Error ("Invalid hexadecimal number");
314                 return 0;
315             }
316         } else {
317             Base = 8;
318         }
319     } else {
320         Base = 10;
321     }
322
323     /* Read the number */
324     while (IsXDigit (C = SB_Peek (B)) && (DigitVal = HexVal (C)) < Base) {
325         *Val = (*Val * Base) + DigitVal;
326         SB_Skip (B);
327     }
328
329     /* Allow optional 'U' and 'L' modifiers */
330     C = SB_Peek (B);
331     if (C == 'u' || C == 'U') {
332         SB_Skip (B);
333         C = SB_Peek (B);
334         if (C == 'l' || C == 'L') {
335             SB_Skip (B);
336         }
337     } else if (C == 'l' || C == 'L') {
338         SB_Skip (B);
339         C = SB_Peek (B);
340         if (C == 'u' || C == 'U') {
341             SB_Skip (B);
342         }
343     }
344
345     /* Success, value read is in Val */
346     *Val *= Sign;
347     return 1;
348 }
349
350
351