]> git.sur5r.net Git - cc65/blob - src/cc65/scanstrbuf.c
b441ae3090ccc2af29c5c7c705b055afd03dd11d
[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      Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
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     int C;
60
61     /* Check for escape chars */
62     if ((C = SB_Get (B)) == '\\') {
63         switch (SB_Get (B)) {
64             case 'a':
65                 C = '\a';
66                 break;
67             case 'b':
68                 C = '\b';
69                 break;
70             case 'f':
71                 C = '\f';
72                 break;
73             case 'r':
74                 C = '\r';
75                 break;
76             case 'n':
77                 C = '\n';
78                 break;
79             case 't':
80                 C = '\t';
81                 break;
82             case 'v':
83                 C = '\v';
84                 break;
85             case '\"':
86                 C = '\"';
87                 break;
88             case '\'':
89                 C = '\'';
90                 break;
91             case '\\':
92                 C = '\\';
93                 break;
94             case '\?':
95                 C = '\?';
96                 break;
97             case 'x':
98             case 'X':
99                 /* Hex character constant */
100                 C = HexVal (SB_Get (B)) << 4;
101                 C |= HexVal (SB_Get (B));
102                 break;
103             case '0':
104                 /* Octal constant */
105                 C = 0;
106                 goto Octal;
107             case '1':
108                 /* Octal constant */
109                 C = 1;
110 Octal:          I = 0;
111                 while (SB_Peek (B) >= '0' && SB_Peek (B) <= '7' && I++ < 4) {
112                     C = (C << 3) | (SB_Get (B) - '0');
113                 }
114                 break;
115             default:
116                 Error ("Illegal character constant");
117                 C = ' ';
118                 break;
119         }
120     }
121
122     /* Return the character */
123     return C;
124 }
125
126
127
128 /*****************************************************************************/
129 /*                                   Code                                    */
130 /*****************************************************************************/
131
132
133
134 void SB_SkipWhite (StrBuf* B)
135 /* Skip whitespace in the string buffer */
136 {
137     while (IsBlank (SB_Peek (B))) {
138         SB_Skip (B);
139     }
140 }
141
142
143
144 int SB_GetSym (StrBuf* B, char* S)
145 /* Get a symbol from the string buffer. S must be able to hold MAX_IDENTLEN
146  * characters. Returns 1 if a symbol was found and 0 otherwise.
147  */                               
148 {
149     if (IsIdent (SB_Peek (B))) {
150         unsigned I = 0;
151         char C = SB_Peek (B);
152         do {
153             if (I < MAX_IDENTLEN) {
154                 ++I;
155                 *S++ = C;
156             }
157             SB_Skip (B);
158             C = SB_Peek (B);
159         } while (IsIdent (C) || IsDigit (C));
160         *S = '\0';
161         return 1;
162     } else {
163         return 0;
164     }
165 }
166
167
168
169 int SB_GetString (StrBuf* B, StrBuf* S)
170 /* Get a string from the string buffer. S will be initialized by the function
171  * and will return the correctly terminated string on return. The function
172  * returns 1 if a string was found and 0 otherwise.
173  */
174 {
175     char C;
176
177     /* Initialize S */
178     *S = AUTO_STRBUF_INITIALIZER;
179     if (SB_Peek (B) == '\"') {
180
181         /* String follows, be sure to concatenate strings */
182         while (SB_Peek (B) == '\"') {
183
184             /* Skip the quote char */
185             SB_Skip (B);
186
187             /* Read the actual string contents */
188             while ((C = SB_Peek (B)) != '\"') {
189                 if (C == '\0') {
190                     Error ("Unexpected end of string");
191                     break;
192                 }
193                 SB_AppendChar (S, ParseChar (B));
194             }
195
196             /* Skip the closing quote char if there was one */
197             SB_Skip (B);
198
199             /* Skip white space, read new input */
200             SB_SkipWhite (B);
201         }
202
203         /* Terminate the string */
204         SB_Terminate (S);
205
206         /* Success */
207         return 1;
208
209     } else {
210
211         /* Not a string */
212         SB_Terminate (S);
213         return 0;
214     }
215 }
216
217
218
219 int SB_GetNumber (StrBuf* B, long* Val)
220 /* Get a number from the string buffer. Accepted formats are decimal, octal,
221  * hex and character constants. Numeric constants may be preceeded by a
222  * minus or plus sign. The function returns 1 if a number was found and
223  * zero otherwise.
224  */
225 {
226     int      Sign;
227     char     C;
228     unsigned Base;
229     unsigned DigitVal;
230
231     /* Initialize Val */
232     *Val = 0;
233
234     /* Check for a sign */
235     Sign = 1;
236     switch (SB_Peek (B)) {
237         case '-':
238             Sign = -1;
239             /* FALLTHROUGH */
240         case '+':
241             SB_Skip (B);
242             SB_SkipWhite (B);
243             break;
244     }
245
246     /* Check for the different formats */
247     C = SB_Peek (B);
248     if (IsDigit (C)) {
249
250         if (C == '0') {
251             /* Hex or octal */
252             SB_Skip (B);
253             if (tolower (SB_Peek (B)) == 'x') {
254                 SB_Skip (B);
255                 Base = 16;
256                 if (!IsXDigit (SB_Peek (B))) {
257                     Error ("Invalid hexadecimal number");
258                     return 0;
259                 }
260             } else {
261                 Base = 8;
262             }
263         } else {
264             Base = 10;
265         }
266
267         /* Read the number */
268         while (IsXDigit (C = SB_Peek (B)) && (DigitVal = HexVal (C)) < Base) {
269             *Val = (*Val * Base) + DigitVal;
270             SB_Skip (B);
271         }
272
273         /* Allow optional 'U' and 'L' modifiers */
274         C = SB_Peek (B);
275         if (C == 'u' || C == 'U') {
276             SB_Skip (B);
277             C = SB_Peek (B);
278             if (C == 'l' || C == 'L') {
279                 SB_Skip (B);
280             }
281         } else if (C == 'l' || C == 'L') {
282             SB_Skip (B);
283             C = SB_Peek (B);
284             if (C == 'u' || C == 'U') {
285                 SB_Skip (B);
286             }
287         }
288
289     } else if (C == '\'') {
290
291         /* Character constant */
292         SB_Skip (B);
293         *Val = SignExtendChar (TgtTranslateChar (ParseChar (B)));
294         if (SB_Peek (B) != '\'') {
295             Error ("`\'' expected");
296             return 0;
297         } else {
298             /* Skip the quote */
299             SB_Skip (B);
300         }
301
302     } else {
303
304         /* Invalid number */
305         Error ("Numeric constant expected");
306         return 0;
307
308     }
309
310     /* Success, value read is in Val */
311     return 1;
312 }
313
314
315