/* */
This source file includes following definitions.
- opentoken
- closetoken
- nexttoken
- pushbacktoken
- peekc
- throwaway_nextchar
- atfirst_exceptspace
- pushbackchar
1 /*
2 * Copyright (c) 1998, 1999, 2000, 2002, 2003, 2008
3 * Tama Communications Corporation
4 *
5 * This file is part of GNU GLOBAL.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <ctype.h>
25 #include <stdio.h>
26 #ifdef HAVE_STRING_H
27 #include <string.h>
28 #else
29 #include <strings.h>
30 #endif
31
32 #include "die.h"
33 #include "gparam.h"
34 #include "strlimcpy.h"
35 #include "token.h"
36
37 /*
38 * File input method.
39 */
40 int lineno;
41 const char *sp, *cp, *lp;
42 int crflag; /**< 1: return '\\n', 0: doesn't return */
43 int cmode; /**< allow token which start with '\#' */
44 int cppmode; /**< allow '\::' as a token */
45 int ymode; /**< allow token which start with '\%' */
46 char token[MAXTOKEN];
47 char curfile[MAXPATHLEN];
48 int continued_line; /**< previous line ends with '\\\\' */
49
50 static char ptok[MAXTOKEN];
51 static int lasttok;
52 static FILE *ip;
53 static STRBUF *ib;
54
55 #define tlen (p - &token[0])
56 static void pushbackchar(void);
57
58 /**
59 * opentoken:
60 *
61 * @param[in] file
62 */
63 int
64 opentoken(const char *file)
65 {
66 /*
67 * b flag is needed for WIN32 environment. Almost unix ignore it.
68 */
69 if ((ip = fopen(file, "rb")) == NULL)
70 return 0;
71 ib = strbuf_open(MAXBUFLEN);
72 strlimcpy(curfile, file, sizeof(curfile));
73 sp = cp = lp = NULL; ptok[0] = '\0'; lineno = 0;
74 crflag = cmode = cppmode = ymode = 0;
75 continued_line = 0;
76 return 1;
77 }
78 /**
79 * closetoken:
80 */
81 void
82 closetoken(void)
83 {
84 strbuf_close(ib);
85 fclose(ip);
86 }
87
88 /**
89 * nexttoken: get next token
90 *
91 * @param[in] interested interested special character <br>
92 * if @VAR{NULL} then all character.
93 * @param[in] reserved converter from token to token number <br>
94 * if this is specified, nexttoken() return <br>
95 * word number, else return symbol.
96 * @return @VAR{EOF}(-1) end of file <br>
97 * c ==0 symbol (#SYMBOL; #token has the value.) <br>
98 * c \< 256 interested special character <br>
99 * c \> 1000 reserved word
100 *
101 * @note nexttoken() doesn't return followings:
102 * - comment
103 * - space (@CODE{' '}, @CODE{'\\t'}, @CODE{'\\f'}, @CODE{'\\v'}, @CODE{'\\r'})
104 * - quoted string (@CODE{\"...\"}, @CODE{'.'})
105 * - number
106 */
107
108 int
109 nexttoken(const char *interested, int (*reserved)(const char *, int))
110 {
111 int c;
112 char *p;
113 int sharp = 0;
114 int percent = 0;
115
116 /* check push back buffer */
117 if (ptok[0]) {
118 strlimcpy(token, ptok, sizeof(token));
119 ptok[0] = '\0';
120 return lasttok;
121 }
122
123 for (;;) {
124 /* skip spaces */
125 if (!crflag)
126 while ((c = nextchar()) != EOF && isspace(c))
127 ;
128 else
129 while ((c = nextchar()) != EOF && isspace(c) && c != '\n')
130 ;
131 if (c == EOF || c == '\n')
132 break;
133
134 if (c == '"' || c == '\'') { /* quoted string */
135 int quote = c;
136
137 while ((c = nextchar()) != EOF) {
138 if (c == quote)
139 break;
140 if (quote == '\'' && c == '\n')
141 break;
142 if (c == '\\' && (c = nextchar()) == EOF)
143 break;
144 }
145 } else if (c == '/') { /* comment */
146 if ((c = nextchar()) == '/') {
147 while ((c = nextchar()) != EOF)
148 if (c == '\n') {
149 pushbackchar();
150 break;
151 }
152 } else if (c == '*') {
153 while ((c = nextchar()) != EOF) {
154 if (c == '*') {
155 if ((c = nextchar()) == '/')
156 break;
157 pushbackchar();
158 }
159 }
160 } else
161 pushbackchar();
162 } else if (c == '\\') {
163 if (nextchar() == '\n')
164 continued_line = 1;
165 } else if (isdigit(c)) { /* digit */
166 while ((c = nextchar()) != EOF && (c == '.' || isalnum(c)))
167 ;
168 pushbackchar();
169 } else if (c == '#' && cmode) {
170 /* recognize '##' as a token if it is reserved word. */
171 if (peekc(1) == '#') {
172 p = token;
173 *p++ = c;
174 *p++ = nextchar();
175 *p = 0;
176 if (reserved && (c = (*reserved)(token, tlen)) == 0)
177 break;
178 } else if (!continued_line && atfirst_exceptspace()) {
179 sharp = 1;
180 continue;
181 }
182 } else if (c == ':' && cppmode) {
183 if (peekc(1) == ':') {
184 p = token;
185 *p++ = c;
186 *p++ = nextchar();
187 *p = 0;
188 if (reserved && (c = (*reserved)(token, tlen)) == 0)
189 break;
190 }
191 } else if (c == '%' && ymode) {
192 /* recognize '%%' as a token if it is reserved word. */
193 if (atfirst) {
194 p = token;
195 *p++ = c;
196 if ((c = peekc(1)) == '%' || c == '{' || c == '}') {
197 *p++ = nextchar();
198 *p = 0;
199 if (reserved && (c = (*reserved)(token, tlen)) != 0)
200 break;
201 } else if (!isspace(c)) {
202 percent = 1;
203 continue;
204 }
205 }
206 } else if (c & 0x80 || isalpha(c) || c == '_') {/* symbol */
207 p = token;
208 if (sharp) {
209 sharp = 0;
210 *p++ = '#';
211 } else if (percent) {
212 percent = 0;
213 *p++ = '%';
214 } else if (c == 'L') {
215 int tmp = peekc(1);
216
217 if (tmp == '\"' || tmp == '\'')
218 continue;
219 }
220 for (*p++ = c; (c = nextchar()) != EOF && (c & 0x80 || isalnum(c) || c == '_');) {
221 if (tlen < sizeof(token))
222 *p++ = c;
223 }
224 if (tlen == sizeof(token)) {
225 warning("symbol name is too long. (Ignored)[+%d %s]", lineno, curfile);
226 continue;
227 }
228 *p = 0;
229
230 if (c != EOF)
231 pushbackchar();
232 /* convert token string into token number */
233 c = SYMBOL;
234 if (reserved)
235 c = (*reserved)(token, tlen);
236 break;
237 } else { /* special char */
238 if (interested == NULL || strchr(interested, c))
239 break;
240 /* otherwise ignore it */
241 }
242 sharp = percent = 0;
243 }
244 return lasttok = c;
245 }
246 /**
247 * pushbacktoken: push back token
248 *
249 * following nexttoken() return same token again.
250 */
251 void
252 pushbacktoken(void)
253 {
254 strlimcpy(ptok, token, sizeof(ptok));
255 }
256 /**
257 * peekc: peek next char
258 *
259 * @param[in] immediate 0: ignore blank, 1: include blank
260 *
261 * peekc() read ahead following blanks but doesn't change line.
262 */
263 int
264 peekc(int immediate)
265 {
266 int c;
267 long pos;
268 int comment = 0;
269
270 if (cp != NULL) {
271 if (immediate)
272 c = nextchar();
273 else
274 while ((c = nextchar()) != EOF && c != '\n') {
275 if (c == '/') { /* comment */
276 if ((c = nextchar()) == '/') {
277 while ((c = nextchar()) != EOF)
278 if (c == '\n') {
279 pushbackchar();
280 break;
281 }
282 } else if (c == '*') {
283 comment = 1;
284 while ((c = nextchar()) != EOF) {
285 if (c == '*') {
286 if ((c = nextchar()) == '/')
287 {
288 comment = 0;
289 break;
290 }
291 }
292 else if (c == '\n')
293 {
294 pushbackchar();
295 break;
296 }
297 }
298 } else
299 pushbackchar();
300 }
301 else if (!isspace(c))
302 break;
303 }
304 if (c != EOF)
305 pushbackchar();
306 if (c != '\n' || immediate)
307 return c;
308 }
309 pos = ftell(ip);
310 if (immediate)
311 c = getc(ip);
312 else
313 while ((c = getc(ip)) != EOF) {
314 if (comment) {
315 while ((c = getc(ip)) != EOF) {
316 if (c == '*') {
317 if ((c = getc(ip)) == '/')
318 {
319 comment = 0;
320 break;
321 }
322 }
323 }
324 }
325 else if (c == '/') { /* comment */
326 if ((c = getc(ip)) == '/') {
327 while ((c = getc(ip)) != EOF)
328 if (c == '\n') {
329 break;
330 }
331 } else if (c == '*') {
332 while ((c = getc(ip)) != EOF) {
333 if (c == '*') {
334 if ((c = getc(ip)) == '/')
335 break;
336 }
337 }
338 } else
339 break;
340 }
341 else if (!isspace(c))
342 break;
343 }
344
345 (void)fseek(ip, pos, SEEK_SET);
346
347 return c;
348 }
349 /**
350 * throwaway_nextchar: throw away next character
351 */
352 void
353 throwaway_nextchar(void)
354 {
355 nextchar();
356 }
357 /**
358 * atfirst_exceptspace: return if current position is the first column
359 * except for space.
360 * @code
361 * | 1 0
362 * | v v
363 * | # define
364 * @endcode
365 */
366 int
367 atfirst_exceptspace(void)
368 {
369 const char *start = sp;
370 const char *end = cp ? cp - 1 : lp;
371
372 while (start < end && *start && isspace(*start))
373 start++;
374 return (start == end) ? 1 : 0;
375 }
376 /**
377 * pushbackchar: push back character.
378 *
379 * following nextchar() return same character again.
380 *
381 */
382 static void
383 pushbackchar(void)
384 {
385 if (sp == NULL)
386 return; /* nothing to do */
387 if (cp == NULL)
388 cp = lp;
389 else
390 --cp;
391 }
/* */