|
1 /* GLIB - Library of useful routines for C programming |
|
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald |
|
3 * |
|
4 * GScanner: Flexible lexical scanner for general purpose. |
|
5 * Copyright (C) 1997, 1998 Tim Janik |
|
6 * Portions copyright (c) 2006 Nokia Corporation. All rights reserved. |
|
7 * |
|
8 * This library is free software; you can redistribute it and/or |
|
9 * modify it under the terms of the GNU Lesser General Public |
|
10 * License as published by the Free Software Foundation; either |
|
11 * version 2 of the License, or (at your option) any later version. |
|
12 * |
|
13 * This library is distributed in the hope that it will be useful, |
|
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
16 * Lesser General Public License for more details. |
|
17 * |
|
18 * You should have received a copy of the GNU Lesser General Public |
|
19 * License along with this library; if not, write to the |
|
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
|
21 * Boston, MA 02111-1307, USA. |
|
22 */ |
|
23 |
|
24 /* |
|
25 * Modified by the GLib Team and others 1997-2000. See the AUTHORS |
|
26 * file for a list of people on the GLib Team. See the ChangeLog |
|
27 * files for a list of changes. These files are distributed with |
|
28 * GLib at ftp://ftp.gtk.org/pub/gtk/. |
|
29 */ |
|
30 |
|
31 /* |
|
32 * MT safe |
|
33 */ |
|
34 |
|
35 #include "config.h" |
|
36 |
|
37 #include <errno.h> |
|
38 #include <stdlib.h> |
|
39 #include <stdarg.h> |
|
40 #include <string.h> |
|
41 #include <stdio.h> |
|
42 #ifdef HAVE_UNISTD_H |
|
43 #include <unistd.h> |
|
44 #endif |
|
45 |
|
46 #include "glib.h" |
|
47 #include "gprintfint.h" |
|
48 #include "galias.h" |
|
49 |
|
50 #ifdef __SYMBIAN32__ |
|
51 #include <glib_wsd.h> |
|
52 #endif |
|
53 |
|
54 #ifdef G_OS_WIN32 |
|
55 #include <io.h> /* For _read() */ |
|
56 #endif |
|
57 |
|
58 /* --- defines --- */ |
|
59 #define to_lower(c) ( \ |
|
60 (guchar) ( \ |
|
61 ( (((guchar)(c))>='A' && ((guchar)(c))<='Z') * ('a'-'A') ) | \ |
|
62 ( (((guchar)(c))>=192 && ((guchar)(c))<=214) * (224-192) ) | \ |
|
63 ( (((guchar)(c))>=216 && ((guchar)(c))<=222) * (248-216) ) | \ |
|
64 ((guchar)(c)) \ |
|
65 ) \ |
|
66 ) |
|
67 #define READ_BUFFER_SIZE (4000) |
|
68 |
|
69 |
|
70 /* --- typedefs --- */ |
|
71 typedef struct _GScannerKey GScannerKey; |
|
72 |
|
73 struct _GScannerKey |
|
74 { |
|
75 guint scope_id; |
|
76 gchar *symbol; |
|
77 gpointer value; |
|
78 }; |
|
79 |
|
80 |
|
81 /* --- variables --- */ |
|
82 #if EMULATOR |
|
83 |
|
84 PLS(g_scanner_config_template ,gscanner,GScannerConfig) |
|
85 |
|
86 #define g_scanner_config_template (*FUNCTION_NAME(g_scanner_config_template ,gscanner)()) |
|
87 |
|
88 #else |
|
89 |
|
90 static GScannerConfig g_scanner_config_template = |
|
91 { |
|
92 ( |
|
93 " \t\r\n" |
|
94 ) /* cset_skip_characters */, |
|
95 ( |
|
96 G_CSET_a_2_z |
|
97 "_" |
|
98 G_CSET_A_2_Z |
|
99 ) /* cset_identifier_first */, |
|
100 ( |
|
101 G_CSET_a_2_z |
|
102 "_" |
|
103 G_CSET_A_2_Z |
|
104 G_CSET_DIGITS |
|
105 G_CSET_LATINS |
|
106 G_CSET_LATINC |
|
107 ) /* cset_identifier_nth */, |
|
108 ( "#\n" ) /* cpair_comment_single */, |
|
109 |
|
110 FALSE /* case_sensitive */, |
|
111 |
|
112 TRUE /* skip_comment_multi */, |
|
113 TRUE /* skip_comment_single */, |
|
114 TRUE /* scan_comment_multi */, |
|
115 TRUE /* scan_identifier */, |
|
116 FALSE /* scan_identifier_1char */, |
|
117 FALSE /* scan_identifier_NULL */, |
|
118 TRUE /* scan_symbols */, |
|
119 FALSE /* scan_binary */, |
|
120 TRUE /* scan_octal */, |
|
121 TRUE /* scan_float */, |
|
122 TRUE /* scan_hex */, |
|
123 FALSE /* scan_hex_dollar */, |
|
124 TRUE /* scan_string_sq */, |
|
125 TRUE /* scan_string_dq */, |
|
126 TRUE /* numbers_2_int */, |
|
127 FALSE /* int_2_float */, |
|
128 FALSE /* identifier_2_string */, |
|
129 TRUE /* char_2_token */, |
|
130 FALSE /* symbol_2_token */, |
|
131 FALSE /* scope_0_fallback */, |
|
132 FALSE /* store_int64 */, |
|
133 }; |
|
134 |
|
135 #endif /* EMULATOR */ |
|
136 |
|
137 |
|
138 /* --- prototypes --- */ |
|
139 static inline |
|
140 GScannerKey* g_scanner_lookup_internal (GScanner *scanner, |
|
141 guint scope_id, |
|
142 const gchar *symbol); |
|
143 static gboolean g_scanner_key_equal (gconstpointer v1, |
|
144 gconstpointer v2); |
|
145 static guint g_scanner_key_hash (gconstpointer v); |
|
146 static void g_scanner_get_token_ll (GScanner *scanner, |
|
147 GTokenType *token_p, |
|
148 GTokenValue *value_p, |
|
149 guint *line_p, |
|
150 guint *position_p); |
|
151 static void g_scanner_get_token_i (GScanner *scanner, |
|
152 GTokenType *token_p, |
|
153 GTokenValue *value_p, |
|
154 guint *line_p, |
|
155 guint *position_p); |
|
156 |
|
157 static guchar g_scanner_peek_next_char (GScanner *scanner); |
|
158 static guchar g_scanner_get_char (GScanner *scanner, |
|
159 guint *line_p, |
|
160 guint *position_p); |
|
161 static void g_scanner_msg_handler (GScanner *scanner, |
|
162 gchar *message, |
|
163 gboolean is_error); |
|
164 |
|
165 |
|
166 /* --- functions --- */ |
|
167 static inline gint |
|
168 g_scanner_char_2_num (guchar c, |
|
169 guchar base) |
|
170 { |
|
171 if (c >= '0' && c <= '9') |
|
172 c -= '0'; |
|
173 else if (c >= 'A' && c <= 'Z') |
|
174 c -= 'A' - 10; |
|
175 else if (c >= 'a' && c <= 'z') |
|
176 c -= 'a' - 10; |
|
177 else |
|
178 return -1; |
|
179 |
|
180 if (c < base) |
|
181 return c; |
|
182 |
|
183 return -1; |
|
184 } |
|
185 |
|
186 EXPORT_C GScanner* |
|
187 g_scanner_new (const GScannerConfig *config_templ) |
|
188 { |
|
189 GScanner *scanner; |
|
190 |
|
191 if (!config_templ) |
|
192 config_templ = &g_scanner_config_template; |
|
193 scanner = g_new0 (GScanner, 1); |
|
194 |
|
195 scanner->user_data = NULL; |
|
196 scanner->max_parse_errors = 1; |
|
197 scanner->parse_errors = 0; |
|
198 scanner->input_name = NULL; |
|
199 g_datalist_init (&scanner->qdata); |
|
200 scanner->config = g_new0 (GScannerConfig, 1); |
|
201 |
|
202 scanner->config->case_sensitive = config_templ->case_sensitive; |
|
203 scanner->config->cset_skip_characters = config_templ->cset_skip_characters; |
|
204 if (!scanner->config->cset_skip_characters) |
|
205 scanner->config->cset_skip_characters = ""; |
|
206 scanner->config->cset_identifier_first = config_templ->cset_identifier_first; |
|
207 scanner->config->cset_identifier_nth = config_templ->cset_identifier_nth; |
|
208 scanner->config->cpair_comment_single = config_templ->cpair_comment_single; |
|
209 scanner->config->skip_comment_multi = config_templ->skip_comment_multi; |
|
210 scanner->config->skip_comment_single = config_templ->skip_comment_single; |
|
211 scanner->config->scan_comment_multi = config_templ->scan_comment_multi; |
|
212 scanner->config->scan_identifier = config_templ->scan_identifier; |
|
213 scanner->config->scan_identifier_1char = config_templ->scan_identifier_1char; |
|
214 scanner->config->scan_identifier_NULL = config_templ->scan_identifier_NULL; |
|
215 scanner->config->scan_symbols = config_templ->scan_symbols; |
|
216 scanner->config->scan_binary = config_templ->scan_binary; |
|
217 scanner->config->scan_octal = config_templ->scan_octal; |
|
218 scanner->config->scan_float = config_templ->scan_float; |
|
219 scanner->config->scan_hex = config_templ->scan_hex; |
|
220 scanner->config->scan_hex_dollar = config_templ->scan_hex_dollar; |
|
221 scanner->config->scan_string_sq = config_templ->scan_string_sq; |
|
222 scanner->config->scan_string_dq = config_templ->scan_string_dq; |
|
223 scanner->config->numbers_2_int = config_templ->numbers_2_int; |
|
224 scanner->config->int_2_float = config_templ->int_2_float; |
|
225 scanner->config->identifier_2_string = config_templ->identifier_2_string; |
|
226 scanner->config->char_2_token = config_templ->char_2_token; |
|
227 scanner->config->symbol_2_token = config_templ->symbol_2_token; |
|
228 scanner->config->scope_0_fallback = config_templ->scope_0_fallback; |
|
229 scanner->config->store_int64 = config_templ->store_int64; |
|
230 |
|
231 scanner->token = G_TOKEN_NONE; |
|
232 scanner->value.v_int64 = 0; |
|
233 scanner->line = 1; |
|
234 scanner->position = 0; |
|
235 |
|
236 scanner->next_token = G_TOKEN_NONE; |
|
237 scanner->next_value.v_int64 = 0; |
|
238 scanner->next_line = 1; |
|
239 scanner->next_position = 0; |
|
240 |
|
241 scanner->symbol_table = g_hash_table_new (g_scanner_key_hash, g_scanner_key_equal); |
|
242 scanner->input_fd = -1; |
|
243 scanner->text = NULL; |
|
244 scanner->text_end = NULL; |
|
245 scanner->buffer = NULL; |
|
246 scanner->scope_id = 0; |
|
247 |
|
248 scanner->msg_handler = g_scanner_msg_handler; |
|
249 |
|
250 return scanner; |
|
251 } |
|
252 |
|
253 static inline void |
|
254 g_scanner_free_value (GTokenType *token_p, |
|
255 GTokenValue *value_p) |
|
256 { |
|
257 switch (*token_p) |
|
258 { |
|
259 case G_TOKEN_STRING: |
|
260 case G_TOKEN_IDENTIFIER: |
|
261 case G_TOKEN_IDENTIFIER_NULL: |
|
262 case G_TOKEN_COMMENT_SINGLE: |
|
263 case G_TOKEN_COMMENT_MULTI: |
|
264 g_free (value_p->v_string); |
|
265 break; |
|
266 |
|
267 default: |
|
268 break; |
|
269 } |
|
270 |
|
271 *token_p = G_TOKEN_NONE; |
|
272 } |
|
273 |
|
274 static void |
|
275 g_scanner_destroy_symbol_table_entry (gpointer _key, |
|
276 gpointer _value, |
|
277 gpointer _data) |
|
278 { |
|
279 GScannerKey *key = _key; |
|
280 |
|
281 g_free (key->symbol); |
|
282 g_free (key); |
|
283 } |
|
284 |
|
285 EXPORT_C void |
|
286 g_scanner_destroy (GScanner *scanner) |
|
287 { |
|
288 g_return_if_fail (scanner != NULL); |
|
289 |
|
290 g_datalist_clear (&scanner->qdata); |
|
291 g_hash_table_foreach (scanner->symbol_table, |
|
292 g_scanner_destroy_symbol_table_entry, NULL); |
|
293 g_hash_table_destroy (scanner->symbol_table); |
|
294 g_scanner_free_value (&scanner->token, &scanner->value); |
|
295 g_scanner_free_value (&scanner->next_token, &scanner->next_value); |
|
296 g_free (scanner->config); |
|
297 g_free (scanner->buffer); |
|
298 g_free (scanner); |
|
299 } |
|
300 |
|
301 static void |
|
302 g_scanner_msg_handler (GScanner *scanner, |
|
303 gchar *message, |
|
304 gboolean is_error) |
|
305 { |
|
306 g_return_if_fail (scanner != NULL); |
|
307 |
|
308 _g_fprintf (stderr, "%s:%d: ", |
|
309 scanner->input_name ? scanner->input_name : "<memory>", |
|
310 scanner->line); |
|
311 if (is_error) |
|
312 _g_fprintf (stderr, "error: "); |
|
313 _g_fprintf (stderr, "%s\n", message); |
|
314 } |
|
315 |
|
316 EXPORT_C void |
|
317 g_scanner_error (GScanner *scanner, |
|
318 const gchar *format, |
|
319 ...) |
|
320 { |
|
321 g_return_if_fail (scanner != NULL); |
|
322 g_return_if_fail (format != NULL); |
|
323 |
|
324 scanner->parse_errors++; |
|
325 |
|
326 if (scanner->msg_handler) |
|
327 { |
|
328 va_list args; |
|
329 gchar *string; |
|
330 |
|
331 va_start (args, format); |
|
332 string = g_strdup_vprintf (format, args); |
|
333 va_end (args); |
|
334 |
|
335 scanner->msg_handler (scanner, string, TRUE); |
|
336 |
|
337 g_free (string); |
|
338 } |
|
339 } |
|
340 |
|
341 EXPORT_C void |
|
342 g_scanner_warn (GScanner *scanner, |
|
343 const gchar *format, |
|
344 ...) |
|
345 { |
|
346 g_return_if_fail (scanner != NULL); |
|
347 g_return_if_fail (format != NULL); |
|
348 |
|
349 if (scanner->msg_handler) |
|
350 { |
|
351 va_list args; |
|
352 gchar *string; |
|
353 |
|
354 va_start (args, format); |
|
355 string = g_strdup_vprintf (format, args); |
|
356 va_end (args); |
|
357 |
|
358 scanner->msg_handler (scanner, string, FALSE); |
|
359 |
|
360 g_free (string); |
|
361 } |
|
362 } |
|
363 |
|
364 static gboolean |
|
365 g_scanner_key_equal (gconstpointer v1, |
|
366 gconstpointer v2) |
|
367 { |
|
368 const GScannerKey *key1 = v1; |
|
369 const GScannerKey *key2 = v2; |
|
370 |
|
371 return (key1->scope_id == key2->scope_id) && (strcmp (key1->symbol, key2->symbol) == 0); |
|
372 } |
|
373 |
|
374 static guint |
|
375 g_scanner_key_hash (gconstpointer v) |
|
376 { |
|
377 const GScannerKey *key = v; |
|
378 gchar *c; |
|
379 guint h; |
|
380 |
|
381 h = key->scope_id; |
|
382 for (c = key->symbol; *c; c++) |
|
383 h = (h << 5) - h + *c; |
|
384 |
|
385 return h; |
|
386 } |
|
387 |
|
388 static inline GScannerKey* |
|
389 g_scanner_lookup_internal (GScanner *scanner, |
|
390 guint scope_id, |
|
391 const gchar *symbol) |
|
392 { |
|
393 GScannerKey *key_p; |
|
394 GScannerKey key; |
|
395 |
|
396 key.scope_id = scope_id; |
|
397 |
|
398 if (!scanner->config->case_sensitive) |
|
399 { |
|
400 gchar *d; |
|
401 const gchar *c; |
|
402 key.symbol = g_new (gchar, strlen (symbol) + 1); |
|
403 for (d = key.symbol, c = symbol; *c; c++, d++) |
|
404 *d = to_lower (*c); |
|
405 *d = 0; |
|
406 key_p = g_hash_table_lookup (scanner->symbol_table, &key); |
|
407 g_free (key.symbol); |
|
408 } |
|
409 else |
|
410 { |
|
411 key.symbol = (gchar*) symbol; |
|
412 key_p = g_hash_table_lookup (scanner->symbol_table, &key); |
|
413 } |
|
414 |
|
415 return key_p; |
|
416 } |
|
417 |
|
418 EXPORT_C void |
|
419 g_scanner_scope_add_symbol (GScanner *scanner, |
|
420 guint scope_id, |
|
421 const gchar *symbol, |
|
422 gpointer value) |
|
423 { |
|
424 GScannerKey *key; |
|
425 |
|
426 g_return_if_fail (scanner != NULL); |
|
427 g_return_if_fail (symbol != NULL); |
|
428 |
|
429 key = g_scanner_lookup_internal (scanner, scope_id, symbol); |
|
430 |
|
431 if (!key) |
|
432 { |
|
433 key = g_new (GScannerKey, 1); |
|
434 key->scope_id = scope_id; |
|
435 key->symbol = g_strdup (symbol); |
|
436 key->value = value; |
|
437 if (!scanner->config->case_sensitive) |
|
438 { |
|
439 gchar *c; |
|
440 |
|
441 c = key->symbol; |
|
442 while (*c != 0) |
|
443 { |
|
444 *c = to_lower (*c); |
|
445 c++; |
|
446 } |
|
447 } |
|
448 g_hash_table_insert (scanner->symbol_table, key, key); |
|
449 } |
|
450 else |
|
451 key->value = value; |
|
452 } |
|
453 |
|
454 EXPORT_C void |
|
455 g_scanner_scope_remove_symbol (GScanner *scanner, |
|
456 guint scope_id, |
|
457 const gchar *symbol) |
|
458 { |
|
459 GScannerKey *key; |
|
460 |
|
461 g_return_if_fail (scanner != NULL); |
|
462 g_return_if_fail (symbol != NULL); |
|
463 |
|
464 key = g_scanner_lookup_internal (scanner, scope_id, symbol); |
|
465 |
|
466 if (key) |
|
467 { |
|
468 g_hash_table_remove (scanner->symbol_table, key); |
|
469 g_free (key->symbol); |
|
470 g_free (key); |
|
471 } |
|
472 } |
|
473 |
|
474 EXPORT_C gpointer |
|
475 g_scanner_lookup_symbol (GScanner *scanner, |
|
476 const gchar *symbol) |
|
477 { |
|
478 GScannerKey *key; |
|
479 guint scope_id; |
|
480 |
|
481 g_return_val_if_fail (scanner != NULL, NULL); |
|
482 |
|
483 if (!symbol) |
|
484 return NULL; |
|
485 |
|
486 scope_id = scanner->scope_id; |
|
487 key = g_scanner_lookup_internal (scanner, scope_id, symbol); |
|
488 if (!key && scope_id && scanner->config->scope_0_fallback) |
|
489 key = g_scanner_lookup_internal (scanner, 0, symbol); |
|
490 |
|
491 if (key) |
|
492 return key->value; |
|
493 else |
|
494 return NULL; |
|
495 } |
|
496 |
|
497 EXPORT_C gpointer |
|
498 g_scanner_scope_lookup_symbol (GScanner *scanner, |
|
499 guint scope_id, |
|
500 const gchar *symbol) |
|
501 { |
|
502 GScannerKey *key; |
|
503 |
|
504 g_return_val_if_fail (scanner != NULL, NULL); |
|
505 |
|
506 if (!symbol) |
|
507 return NULL; |
|
508 |
|
509 key = g_scanner_lookup_internal (scanner, scope_id, symbol); |
|
510 |
|
511 if (key) |
|
512 return key->value; |
|
513 else |
|
514 return NULL; |
|
515 } |
|
516 |
|
517 EXPORT_C guint |
|
518 g_scanner_set_scope (GScanner *scanner, |
|
519 guint scope_id) |
|
520 { |
|
521 guint old_scope_id; |
|
522 |
|
523 g_return_val_if_fail (scanner != NULL, 0); |
|
524 |
|
525 old_scope_id = scanner->scope_id; |
|
526 scanner->scope_id = scope_id; |
|
527 |
|
528 return old_scope_id; |
|
529 } |
|
530 |
|
531 static void |
|
532 g_scanner_foreach_internal (gpointer _key, |
|
533 gpointer _value, |
|
534 gpointer _user_data) |
|
535 { |
|
536 GScannerKey *key; |
|
537 gpointer *d; |
|
538 GHFunc func; |
|
539 gpointer user_data; |
|
540 guint *scope_id; |
|
541 |
|
542 d = _user_data; |
|
543 func = (GHFunc) d[0]; |
|
544 user_data = d[1]; |
|
545 scope_id = d[2]; |
|
546 key = _value; |
|
547 |
|
548 if (key->scope_id == *scope_id) |
|
549 func (key->symbol, key->value, user_data); |
|
550 } |
|
551 |
|
552 EXPORT_C void |
|
553 g_scanner_scope_foreach_symbol (GScanner *scanner, |
|
554 guint scope_id, |
|
555 GHFunc func, |
|
556 gpointer user_data) |
|
557 { |
|
558 gpointer d[3]; |
|
559 |
|
560 g_return_if_fail (scanner != NULL); |
|
561 |
|
562 d[0] = (gpointer) func; |
|
563 d[1] = user_data; |
|
564 d[2] = &scope_id; |
|
565 |
|
566 g_hash_table_foreach (scanner->symbol_table, g_scanner_foreach_internal, d); |
|
567 } |
|
568 |
|
569 EXPORT_C GTokenType |
|
570 g_scanner_peek_next_token (GScanner *scanner) |
|
571 { |
|
572 g_return_val_if_fail (scanner != NULL, G_TOKEN_EOF); |
|
573 |
|
574 if (scanner->next_token == G_TOKEN_NONE) |
|
575 { |
|
576 scanner->next_line = scanner->line; |
|
577 scanner->next_position = scanner->position; |
|
578 g_scanner_get_token_i (scanner, |
|
579 &scanner->next_token, |
|
580 &scanner->next_value, |
|
581 &scanner->next_line, |
|
582 &scanner->next_position); |
|
583 } |
|
584 |
|
585 return scanner->next_token; |
|
586 } |
|
587 |
|
588 EXPORT_C GTokenType |
|
589 g_scanner_get_next_token (GScanner *scanner) |
|
590 { |
|
591 g_return_val_if_fail (scanner != NULL, G_TOKEN_EOF); |
|
592 |
|
593 if (scanner->next_token != G_TOKEN_NONE) |
|
594 { |
|
595 g_scanner_free_value (&scanner->token, &scanner->value); |
|
596 |
|
597 scanner->token = scanner->next_token; |
|
598 scanner->value = scanner->next_value; |
|
599 scanner->line = scanner->next_line; |
|
600 scanner->position = scanner->next_position; |
|
601 scanner->next_token = G_TOKEN_NONE; |
|
602 } |
|
603 else |
|
604 g_scanner_get_token_i (scanner, |
|
605 &scanner->token, |
|
606 &scanner->value, |
|
607 &scanner->line, |
|
608 &scanner->position); |
|
609 |
|
610 return scanner->token; |
|
611 } |
|
612 |
|
613 EXPORT_C GTokenType |
|
614 g_scanner_cur_token (GScanner *scanner) |
|
615 { |
|
616 g_return_val_if_fail (scanner != NULL, G_TOKEN_EOF); |
|
617 |
|
618 return scanner->token; |
|
619 } |
|
620 |
|
621 EXPORT_C GTokenValue |
|
622 g_scanner_cur_value (GScanner *scanner) |
|
623 { |
|
624 GTokenValue v; |
|
625 |
|
626 v.v_int64 = 0; |
|
627 |
|
628 g_return_val_if_fail (scanner != NULL, v); |
|
629 |
|
630 /* MSC isn't capable of handling return scanner->value; ? */ |
|
631 |
|
632 v = scanner->value; |
|
633 |
|
634 return v; |
|
635 } |
|
636 |
|
637 EXPORT_C guint |
|
638 g_scanner_cur_line (GScanner *scanner) |
|
639 { |
|
640 g_return_val_if_fail (scanner != NULL, 0); |
|
641 |
|
642 return scanner->line; |
|
643 } |
|
644 |
|
645 EXPORT_C guint |
|
646 g_scanner_cur_position (GScanner *scanner) |
|
647 { |
|
648 g_return_val_if_fail (scanner != NULL, 0); |
|
649 |
|
650 return scanner->position; |
|
651 } |
|
652 |
|
653 EXPORT_C gboolean |
|
654 g_scanner_eof (GScanner *scanner) |
|
655 { |
|
656 g_return_val_if_fail (scanner != NULL, TRUE); |
|
657 |
|
658 return scanner->token == G_TOKEN_EOF || scanner->token == G_TOKEN_ERROR; |
|
659 } |
|
660 |
|
661 EXPORT_C void |
|
662 g_scanner_input_file (GScanner *scanner, |
|
663 gint input_fd) |
|
664 { |
|
665 g_return_if_fail (scanner != NULL); |
|
666 g_return_if_fail (input_fd >= 0); |
|
667 |
|
668 if (scanner->input_fd >= 0) |
|
669 g_scanner_sync_file_offset (scanner); |
|
670 |
|
671 scanner->token = G_TOKEN_NONE; |
|
672 scanner->value.v_int64 = 0; |
|
673 scanner->line = 1; |
|
674 scanner->position = 0; |
|
675 scanner->next_token = G_TOKEN_NONE; |
|
676 |
|
677 scanner->input_fd = input_fd; |
|
678 scanner->text = NULL; |
|
679 scanner->text_end = NULL; |
|
680 |
|
681 if (!scanner->buffer) |
|
682 scanner->buffer = g_new (gchar, READ_BUFFER_SIZE + 1); |
|
683 } |
|
684 |
|
685 EXPORT_C void |
|
686 g_scanner_input_text (GScanner *scanner, |
|
687 const gchar *text, |
|
688 guint text_len) |
|
689 { |
|
690 g_return_if_fail (scanner != NULL); |
|
691 if (text_len) |
|
692 g_return_if_fail (text != NULL); |
|
693 else |
|
694 text = NULL; |
|
695 |
|
696 if (scanner->input_fd >= 0) |
|
697 g_scanner_sync_file_offset (scanner); |
|
698 |
|
699 scanner->token = G_TOKEN_NONE; |
|
700 scanner->value.v_int64 = 0; |
|
701 scanner->line = 1; |
|
702 scanner->position = 0; |
|
703 scanner->next_token = G_TOKEN_NONE; |
|
704 |
|
705 scanner->input_fd = -1; |
|
706 scanner->text = text; |
|
707 scanner->text_end = text + text_len; |
|
708 |
|
709 if (scanner->buffer) |
|
710 { |
|
711 g_free (scanner->buffer); |
|
712 scanner->buffer = NULL; |
|
713 } |
|
714 } |
|
715 |
|
716 static guchar |
|
717 g_scanner_peek_next_char (GScanner *scanner) |
|
718 { |
|
719 if (scanner->text < scanner->text_end) |
|
720 { |
|
721 return *scanner->text; |
|
722 } |
|
723 else if (scanner->input_fd >= 0) |
|
724 { |
|
725 gint count; |
|
726 gchar *buffer; |
|
727 |
|
728 buffer = scanner->buffer; |
|
729 do |
|
730 { |
|
731 count = read (scanner->input_fd, buffer, READ_BUFFER_SIZE); |
|
732 } |
|
733 while (count == -1 && (errno == EINTR || errno == EAGAIN)); |
|
734 |
|
735 if (count < 1) |
|
736 { |
|
737 scanner->input_fd = -1; |
|
738 |
|
739 return 0; |
|
740 } |
|
741 else |
|
742 { |
|
743 scanner->text = buffer; |
|
744 scanner->text_end = buffer + count; |
|
745 |
|
746 return *buffer; |
|
747 } |
|
748 } |
|
749 else |
|
750 return 0; |
|
751 } |
|
752 |
|
753 EXPORT_C void |
|
754 g_scanner_sync_file_offset (GScanner *scanner) |
|
755 { |
|
756 g_return_if_fail (scanner != NULL); |
|
757 |
|
758 /* for file input, rewind the filedescriptor to the current |
|
759 * buffer position and blow the file read ahead buffer. usefull for |
|
760 * third party uses of our filedescriptor, which hooks onto the current |
|
761 * scanning position. |
|
762 */ |
|
763 |
|
764 if (scanner->input_fd >= 0 && scanner->text_end > scanner->text) |
|
765 { |
|
766 gint buffered; |
|
767 |
|
768 buffered = scanner->text_end - scanner->text; |
|
769 if (lseek (scanner->input_fd, - buffered, SEEK_CUR) >= 0) |
|
770 { |
|
771 /* we succeeded, blow our buffer's contents now */ |
|
772 scanner->text = NULL; |
|
773 scanner->text_end = NULL; |
|
774 } |
|
775 else |
|
776 errno = 0; |
|
777 } |
|
778 } |
|
779 |
|
780 static guchar |
|
781 g_scanner_get_char (GScanner *scanner, |
|
782 guint *line_p, |
|
783 guint *position_p) |
|
784 { |
|
785 guchar fchar; |
|
786 |
|
787 if (scanner->text < scanner->text_end) |
|
788 fchar = *(scanner->text++); |
|
789 else if (scanner->input_fd >= 0) |
|
790 { |
|
791 gint count; |
|
792 gchar *buffer; |
|
793 |
|
794 buffer = scanner->buffer; |
|
795 do |
|
796 { |
|
797 count = read (scanner->input_fd, buffer, READ_BUFFER_SIZE); |
|
798 } |
|
799 while (count == -1 && (errno == EINTR || errno == EAGAIN)); |
|
800 |
|
801 if (count < 1) |
|
802 { |
|
803 scanner->input_fd = -1; |
|
804 fchar = 0; |
|
805 } |
|
806 else |
|
807 { |
|
808 scanner->text = buffer + 1; |
|
809 scanner->text_end = buffer + count; |
|
810 fchar = *buffer; |
|
811 if (!fchar) |
|
812 { |
|
813 g_scanner_sync_file_offset (scanner); |
|
814 scanner->text_end = scanner->text; |
|
815 scanner->input_fd = -1; |
|
816 } |
|
817 } |
|
818 } |
|
819 else |
|
820 fchar = 0; |
|
821 |
|
822 if (fchar == '\n') |
|
823 { |
|
824 (*position_p) = 0; |
|
825 (*line_p)++; |
|
826 } |
|
827 else if (fchar) |
|
828 { |
|
829 (*position_p)++; |
|
830 } |
|
831 |
|
832 return fchar; |
|
833 } |
|
834 |
|
835 EXPORT_C void |
|
836 g_scanner_unexp_token (GScanner *scanner, |
|
837 GTokenType expected_token, |
|
838 const gchar *identifier_spec, |
|
839 const gchar *symbol_spec, |
|
840 const gchar *symbol_name, |
|
841 const gchar *message, |
|
842 gint is_error) |
|
843 { |
|
844 gchar *token_string; |
|
845 guint token_string_len; |
|
846 gchar *expected_string; |
|
847 guint expected_string_len; |
|
848 gchar *message_prefix; |
|
849 gboolean print_unexp; |
|
850 void (*msg_handler) (GScanner*, const gchar*, ...); |
|
851 |
|
852 g_return_if_fail (scanner != NULL); |
|
853 |
|
854 if (is_error) |
|
855 msg_handler = g_scanner_error; |
|
856 else |
|
857 msg_handler = g_scanner_warn; |
|
858 |
|
859 if (!identifier_spec) |
|
860 identifier_spec = "identifier"; |
|
861 if (!symbol_spec) |
|
862 symbol_spec = "symbol"; |
|
863 |
|
864 token_string_len = 56; |
|
865 token_string = g_new (gchar, token_string_len + 1); |
|
866 expected_string_len = 64; |
|
867 expected_string = g_new (gchar, expected_string_len + 1); |
|
868 print_unexp = TRUE; |
|
869 |
|
870 switch (scanner->token) |
|
871 { |
|
872 case G_TOKEN_EOF: |
|
873 _g_snprintf (token_string, token_string_len, "end of file"); |
|
874 break; |
|
875 |
|
876 default: |
|
877 if (scanner->token >= 1 && scanner->token <= 255) |
|
878 { |
|
879 if ((scanner->token >= ' ' && scanner->token <= '~') || |
|
880 strchr (scanner->config->cset_identifier_first, scanner->token) || |
|
881 strchr (scanner->config->cset_identifier_nth, scanner->token)) |
|
882 _g_snprintf (token_string, token_string_len, "character `%c'", scanner->token); |
|
883 else |
|
884 _g_snprintf (token_string, token_string_len, "character `\\%o'", scanner->token); |
|
885 break; |
|
886 } |
|
887 else if (!scanner->config->symbol_2_token) |
|
888 { |
|
889 _g_snprintf (token_string, token_string_len, "(unknown) token <%d>", scanner->token); |
|
890 break; |
|
891 } |
|
892 /* fall through */ |
|
893 case G_TOKEN_SYMBOL: |
|
894 if (expected_token == G_TOKEN_SYMBOL || |
|
895 (scanner->config->symbol_2_token && |
|
896 expected_token > G_TOKEN_LAST)) |
|
897 print_unexp = FALSE; |
|
898 if (symbol_name) |
|
899 _g_snprintf (token_string, |
|
900 token_string_len, |
|
901 "%s%s `%s'", |
|
902 print_unexp ? "" : "invalid ", |
|
903 symbol_spec, |
|
904 symbol_name); |
|
905 else |
|
906 _g_snprintf (token_string, |
|
907 token_string_len, |
|
908 "%s%s", |
|
909 print_unexp ? "" : "invalid ", |
|
910 symbol_spec); |
|
911 break; |
|
912 |
|
913 case G_TOKEN_ERROR: |
|
914 print_unexp = FALSE; |
|
915 expected_token = G_TOKEN_NONE; |
|
916 switch (scanner->value.v_error) |
|
917 { |
|
918 case G_ERR_UNEXP_EOF: |
|
919 _g_snprintf (token_string, token_string_len, "scanner: unexpected end of file"); |
|
920 break; |
|
921 |
|
922 case G_ERR_UNEXP_EOF_IN_STRING: |
|
923 _g_snprintf (token_string, token_string_len, "scanner: unterminated string constant"); |
|
924 break; |
|
925 |
|
926 case G_ERR_UNEXP_EOF_IN_COMMENT: |
|
927 _g_snprintf (token_string, token_string_len, "scanner: unterminated comment"); |
|
928 break; |
|
929 |
|
930 case G_ERR_NON_DIGIT_IN_CONST: |
|
931 _g_snprintf (token_string, token_string_len, "scanner: non digit in constant"); |
|
932 break; |
|
933 |
|
934 case G_ERR_FLOAT_RADIX: |
|
935 _g_snprintf (token_string, token_string_len, "scanner: invalid radix for floating constant"); |
|
936 break; |
|
937 |
|
938 case G_ERR_FLOAT_MALFORMED: |
|
939 _g_snprintf (token_string, token_string_len, "scanner: malformed floating constant"); |
|
940 break; |
|
941 |
|
942 case G_ERR_DIGIT_RADIX: |
|
943 _g_snprintf (token_string, token_string_len, "scanner: digit is beyond radix"); |
|
944 break; |
|
945 |
|
946 case G_ERR_UNKNOWN: |
|
947 default: |
|
948 _g_snprintf (token_string, token_string_len, "scanner: unknown error"); |
|
949 break; |
|
950 } |
|
951 break; |
|
952 |
|
953 case G_TOKEN_CHAR: |
|
954 _g_snprintf (token_string, token_string_len, "character `%c'", scanner->value.v_char); |
|
955 break; |
|
956 |
|
957 case G_TOKEN_IDENTIFIER: |
|
958 case G_TOKEN_IDENTIFIER_NULL: |
|
959 if (expected_token == G_TOKEN_IDENTIFIER || |
|
960 expected_token == G_TOKEN_IDENTIFIER_NULL) |
|
961 print_unexp = FALSE; |
|
962 _g_snprintf (token_string, |
|
963 token_string_len, |
|
964 "%s%s `%s'", |
|
965 print_unexp ? "" : "invalid ", |
|
966 identifier_spec, |
|
967 scanner->token == G_TOKEN_IDENTIFIER ? scanner->value.v_string : "null"); |
|
968 break; |
|
969 |
|
970 case G_TOKEN_BINARY: |
|
971 case G_TOKEN_OCTAL: |
|
972 case G_TOKEN_INT: |
|
973 case G_TOKEN_HEX: |
|
974 if (scanner->config->store_int64) |
|
975 _g_snprintf (token_string, token_string_len, "number `%" G_GUINT64_FORMAT "'", scanner->value.v_int64); |
|
976 else |
|
977 _g_snprintf (token_string, token_string_len, "number `%lu'", scanner->value.v_int); |
|
978 break; |
|
979 |
|
980 case G_TOKEN_FLOAT: |
|
981 _g_snprintf (token_string, token_string_len, "number `%.3f'", scanner->value.v_float); |
|
982 break; |
|
983 |
|
984 case G_TOKEN_STRING: |
|
985 if (expected_token == G_TOKEN_STRING) |
|
986 print_unexp = FALSE; |
|
987 _g_snprintf (token_string, |
|
988 token_string_len, |
|
989 "%s%sstring constant \"%s\"", |
|
990 print_unexp ? "" : "invalid ", |
|
991 scanner->value.v_string[0] == 0 ? "empty " : "", |
|
992 scanner->value.v_string); |
|
993 token_string[token_string_len - 2] = '"'; |
|
994 token_string[token_string_len - 1] = 0; |
|
995 break; |
|
996 |
|
997 case G_TOKEN_COMMENT_SINGLE: |
|
998 case G_TOKEN_COMMENT_MULTI: |
|
999 _g_snprintf (token_string, token_string_len, "comment"); |
|
1000 break; |
|
1001 |
|
1002 case G_TOKEN_NONE: |
|
1003 /* somehow the user's parsing code is screwed, there isn't much |
|
1004 * we can do about it. |
|
1005 * Note, a common case to trigger this is |
|
1006 * g_scanner_peek_next_token(); g_scanner_unexp_token(); |
|
1007 * without an intermediate g_scanner_get_next_token(). |
|
1008 */ |
|
1009 g_assert_not_reached (); |
|
1010 break; |
|
1011 } |
|
1012 |
|
1013 |
|
1014 switch (expected_token) |
|
1015 { |
|
1016 gboolean need_valid; |
|
1017 gchar *tstring; |
|
1018 case G_TOKEN_EOF: |
|
1019 _g_snprintf (expected_string, expected_string_len, "end of file"); |
|
1020 break; |
|
1021 default: |
|
1022 if (expected_token >= 1 && expected_token <= 255) |
|
1023 { |
|
1024 if ((expected_token >= ' ' && expected_token <= '~') || |
|
1025 strchr (scanner->config->cset_identifier_first, expected_token) || |
|
1026 strchr (scanner->config->cset_identifier_nth, expected_token)) |
|
1027 _g_snprintf (expected_string, expected_string_len, "character `%c'", expected_token); |
|
1028 else |
|
1029 _g_snprintf (expected_string, expected_string_len, "character `\\%o'", expected_token); |
|
1030 break; |
|
1031 } |
|
1032 else if (!scanner->config->symbol_2_token) |
|
1033 { |
|
1034 _g_snprintf (expected_string, expected_string_len, "(unknown) token <%d>", expected_token); |
|
1035 break; |
|
1036 } |
|
1037 /* fall through */ |
|
1038 case G_TOKEN_SYMBOL: |
|
1039 need_valid = (scanner->token == G_TOKEN_SYMBOL || |
|
1040 (scanner->config->symbol_2_token && |
|
1041 scanner->token > G_TOKEN_LAST)); |
|
1042 _g_snprintf (expected_string, |
|
1043 expected_string_len, |
|
1044 "%s%s", |
|
1045 need_valid ? "valid " : "", |
|
1046 symbol_spec); |
|
1047 /* FIXME: should we attempt to lookup the symbol_name for symbol_2_token? */ |
|
1048 break; |
|
1049 case G_TOKEN_CHAR: |
|
1050 _g_snprintf (expected_string, expected_string_len, "%scharacter", |
|
1051 scanner->token == G_TOKEN_CHAR ? "valid " : ""); |
|
1052 break; |
|
1053 case G_TOKEN_BINARY: |
|
1054 tstring = "binary"; |
|
1055 _g_snprintf (expected_string, expected_string_len, "%snumber (%s)", |
|
1056 scanner->token == expected_token ? "valid " : "", tstring); |
|
1057 break; |
|
1058 case G_TOKEN_OCTAL: |
|
1059 tstring = "octal"; |
|
1060 _g_snprintf (expected_string, expected_string_len, "%snumber (%s)", |
|
1061 scanner->token == expected_token ? "valid " : "", tstring); |
|
1062 break; |
|
1063 case G_TOKEN_INT: |
|
1064 tstring = "integer"; |
|
1065 _g_snprintf (expected_string, expected_string_len, "%snumber (%s)", |
|
1066 scanner->token == expected_token ? "valid " : "", tstring); |
|
1067 break; |
|
1068 case G_TOKEN_HEX: |
|
1069 tstring = "hexadecimal"; |
|
1070 _g_snprintf (expected_string, expected_string_len, "%snumber (%s)", |
|
1071 scanner->token == expected_token ? "valid " : "", tstring); |
|
1072 break; |
|
1073 case G_TOKEN_FLOAT: |
|
1074 tstring = "float"; |
|
1075 _g_snprintf (expected_string, expected_string_len, "%snumber (%s)", |
|
1076 scanner->token == expected_token ? "valid " : "", tstring); |
|
1077 break; |
|
1078 case G_TOKEN_STRING: |
|
1079 _g_snprintf (expected_string, |
|
1080 expected_string_len, |
|
1081 "%sstring constant", |
|
1082 scanner->token == G_TOKEN_STRING ? "valid " : ""); |
|
1083 break; |
|
1084 case G_TOKEN_IDENTIFIER: |
|
1085 case G_TOKEN_IDENTIFIER_NULL: |
|
1086 need_valid = (scanner->token == G_TOKEN_IDENTIFIER_NULL || |
|
1087 scanner->token == G_TOKEN_IDENTIFIER); |
|
1088 _g_snprintf (expected_string, |
|
1089 expected_string_len, |
|
1090 "%s%s", |
|
1091 need_valid ? "valid " : "", |
|
1092 identifier_spec); |
|
1093 break; |
|
1094 case G_TOKEN_COMMENT_SINGLE: |
|
1095 tstring = "single-line"; |
|
1096 _g_snprintf (expected_string, expected_string_len, "%scomment (%s)", |
|
1097 scanner->token == expected_token ? "valid " : "", tstring); |
|
1098 break; |
|
1099 case G_TOKEN_COMMENT_MULTI: |
|
1100 tstring = "multi-line"; |
|
1101 _g_snprintf (expected_string, expected_string_len, "%scomment (%s)", |
|
1102 scanner->token == expected_token ? "valid " : "", tstring); |
|
1103 break; |
|
1104 case G_TOKEN_NONE: |
|
1105 case G_TOKEN_ERROR: |
|
1106 /* this is handled upon printout */ |
|
1107 break; |
|
1108 } |
|
1109 |
|
1110 if (message && message[0] != 0) |
|
1111 message_prefix = " - "; |
|
1112 else |
|
1113 { |
|
1114 message_prefix = ""; |
|
1115 message = ""; |
|
1116 } |
|
1117 if (expected_token == G_TOKEN_ERROR) |
|
1118 { |
|
1119 msg_handler (scanner, |
|
1120 "failure around %s%s%s", |
|
1121 token_string, |
|
1122 message_prefix, |
|
1123 message); |
|
1124 } |
|
1125 else if (expected_token == G_TOKEN_NONE) |
|
1126 { |
|
1127 if (print_unexp) |
|
1128 msg_handler (scanner, |
|
1129 "unexpected %s%s%s", |
|
1130 token_string, |
|
1131 message_prefix, |
|
1132 message); |
|
1133 else |
|
1134 msg_handler (scanner, |
|
1135 "%s%s%s", |
|
1136 token_string, |
|
1137 message_prefix, |
|
1138 message); |
|
1139 } |
|
1140 else |
|
1141 { |
|
1142 if (print_unexp) |
|
1143 msg_handler (scanner, |
|
1144 "unexpected %s, expected %s%s%s", |
|
1145 token_string, |
|
1146 expected_string, |
|
1147 message_prefix, |
|
1148 message); |
|
1149 else |
|
1150 msg_handler (scanner, |
|
1151 "%s, expected %s%s%s", |
|
1152 token_string, |
|
1153 expected_string, |
|
1154 message_prefix, |
|
1155 message); |
|
1156 } |
|
1157 |
|
1158 g_free (token_string); |
|
1159 g_free (expected_string); |
|
1160 } |
|
1161 |
|
1162 static void |
|
1163 g_scanner_get_token_i (GScanner *scanner, |
|
1164 GTokenType *token_p, |
|
1165 GTokenValue *value_p, |
|
1166 guint *line_p, |
|
1167 guint *position_p) |
|
1168 { |
|
1169 do |
|
1170 { |
|
1171 g_scanner_free_value (token_p, value_p); |
|
1172 g_scanner_get_token_ll (scanner, token_p, value_p, line_p, position_p); |
|
1173 } |
|
1174 while (((*token_p > 0 && *token_p < 256) && |
|
1175 strchr (scanner->config->cset_skip_characters, *token_p)) || |
|
1176 (*token_p == G_TOKEN_CHAR && |
|
1177 strchr (scanner->config->cset_skip_characters, value_p->v_char)) || |
|
1178 (*token_p == G_TOKEN_COMMENT_MULTI && |
|
1179 scanner->config->skip_comment_multi) || |
|
1180 (*token_p == G_TOKEN_COMMENT_SINGLE && |
|
1181 scanner->config->skip_comment_single)); |
|
1182 |
|
1183 switch (*token_p) |
|
1184 { |
|
1185 case G_TOKEN_IDENTIFIER: |
|
1186 if (scanner->config->identifier_2_string) |
|
1187 *token_p = G_TOKEN_STRING; |
|
1188 break; |
|
1189 |
|
1190 case G_TOKEN_SYMBOL: |
|
1191 if (scanner->config->symbol_2_token) |
|
1192 *token_p = (GTokenType) value_p->v_symbol; |
|
1193 break; |
|
1194 |
|
1195 case G_TOKEN_BINARY: |
|
1196 case G_TOKEN_OCTAL: |
|
1197 case G_TOKEN_HEX: |
|
1198 if (scanner->config->numbers_2_int) |
|
1199 *token_p = G_TOKEN_INT; |
|
1200 break; |
|
1201 |
|
1202 default: |
|
1203 break; |
|
1204 } |
|
1205 |
|
1206 if (*token_p == G_TOKEN_INT && |
|
1207 scanner->config->int_2_float) |
|
1208 { |
|
1209 *token_p = G_TOKEN_FLOAT; |
|
1210 if (scanner->config->store_int64) |
|
1211 { |
|
1212 #ifdef _MSC_VER |
|
1213 /* work around error C2520, see gvaluetransform.c */ |
|
1214 value_p->v_float = (__int64)value_p->v_int64; |
|
1215 #else |
|
1216 value_p->v_float = value_p->v_int64; |
|
1217 #endif |
|
1218 } |
|
1219 else |
|
1220 value_p->v_float = value_p->v_int; |
|
1221 } |
|
1222 |
|
1223 errno = 0; |
|
1224 } |
|
1225 |
|
1226 static void |
|
1227 g_scanner_get_token_ll (GScanner *scanner, |
|
1228 GTokenType *token_p, |
|
1229 GTokenValue *value_p, |
|
1230 guint *line_p, |
|
1231 guint *position_p) |
|
1232 { |
|
1233 GScannerConfig *config; |
|
1234 GTokenType token; |
|
1235 gboolean in_comment_multi; |
|
1236 gboolean in_comment_single; |
|
1237 gboolean in_string_sq; |
|
1238 gboolean in_string_dq; |
|
1239 GString *gstring; |
|
1240 GTokenValue value; |
|
1241 guchar ch; |
|
1242 |
|
1243 config = scanner->config; |
|
1244 (*value_p).v_int64 = 0; |
|
1245 |
|
1246 if ((scanner->text >= scanner->text_end && scanner->input_fd < 0) || |
|
1247 scanner->token == G_TOKEN_EOF) |
|
1248 { |
|
1249 *token_p = G_TOKEN_EOF; |
|
1250 return; |
|
1251 } |
|
1252 |
|
1253 in_comment_multi = FALSE; |
|
1254 in_comment_single = FALSE; |
|
1255 in_string_sq = FALSE; |
|
1256 in_string_dq = FALSE; |
|
1257 gstring = NULL; |
|
1258 |
|
1259 do /* while (ch != 0) */ |
|
1260 { |
|
1261 gboolean dotted_float = FALSE; |
|
1262 |
|
1263 ch = g_scanner_get_char (scanner, line_p, position_p); |
|
1264 |
|
1265 value.v_int64 = 0; |
|
1266 token = G_TOKEN_NONE; |
|
1267 |
|
1268 /* this is *evil*, but needed ;( |
|
1269 * we first check for identifier first character, because it |
|
1270 * might interfere with other key chars like slashes or numbers |
|
1271 */ |
|
1272 if (config->scan_identifier && |
|
1273 ch && strchr (config->cset_identifier_first, ch)) |
|
1274 goto identifier_precedence; |
|
1275 |
|
1276 switch (ch) |
|
1277 { |
|
1278 case 0: |
|
1279 token = G_TOKEN_EOF; |
|
1280 (*position_p)++; |
|
1281 /* ch = 0; */ |
|
1282 break; |
|
1283 |
|
1284 case '/': |
|
1285 if (!config->scan_comment_multi || |
|
1286 g_scanner_peek_next_char (scanner) != '*') |
|
1287 goto default_case; |
|
1288 g_scanner_get_char (scanner, line_p, position_p); |
|
1289 token = G_TOKEN_COMMENT_MULTI; |
|
1290 in_comment_multi = TRUE; |
|
1291 gstring = g_string_new (NULL); |
|
1292 while ((ch = g_scanner_get_char (scanner, line_p, position_p)) != 0) |
|
1293 { |
|
1294 if (ch == '*' && g_scanner_peek_next_char (scanner) == '/') |
|
1295 { |
|
1296 g_scanner_get_char (scanner, line_p, position_p); |
|
1297 in_comment_multi = FALSE; |
|
1298 break; |
|
1299 } |
|
1300 else |
|
1301 gstring = g_string_append_c (gstring, ch); |
|
1302 } |
|
1303 ch = 0; |
|
1304 break; |
|
1305 |
|
1306 case '\'': |
|
1307 if (!config->scan_string_sq) |
|
1308 goto default_case; |
|
1309 token = G_TOKEN_STRING; |
|
1310 in_string_sq = TRUE; |
|
1311 gstring = g_string_new (NULL); |
|
1312 while ((ch = g_scanner_get_char (scanner, line_p, position_p)) != 0) |
|
1313 { |
|
1314 if (ch == '\'') |
|
1315 { |
|
1316 in_string_sq = FALSE; |
|
1317 break; |
|
1318 } |
|
1319 else |
|
1320 gstring = g_string_append_c (gstring, ch); |
|
1321 } |
|
1322 ch = 0; |
|
1323 break; |
|
1324 |
|
1325 case '"': |
|
1326 if (!config->scan_string_dq) |
|
1327 goto default_case; |
|
1328 token = G_TOKEN_STRING; |
|
1329 in_string_dq = TRUE; |
|
1330 gstring = g_string_new (NULL); |
|
1331 while ((ch = g_scanner_get_char (scanner, line_p, position_p)) != 0) |
|
1332 { |
|
1333 if (ch == '"') |
|
1334 { |
|
1335 in_string_dq = FALSE; |
|
1336 break; |
|
1337 } |
|
1338 else |
|
1339 { |
|
1340 if (ch == '\\') |
|
1341 { |
|
1342 ch = g_scanner_get_char (scanner, line_p, position_p); |
|
1343 switch (ch) |
|
1344 { |
|
1345 guint i; |
|
1346 guint fchar; |
|
1347 |
|
1348 case 0: |
|
1349 break; |
|
1350 |
|
1351 case '\\': |
|
1352 gstring = g_string_append_c (gstring, '\\'); |
|
1353 break; |
|
1354 |
|
1355 case 'n': |
|
1356 gstring = g_string_append_c (gstring, '\n'); |
|
1357 break; |
|
1358 |
|
1359 case 't': |
|
1360 gstring = g_string_append_c (gstring, '\t'); |
|
1361 break; |
|
1362 |
|
1363 case 'r': |
|
1364 gstring = g_string_append_c (gstring, '\r'); |
|
1365 break; |
|
1366 |
|
1367 case 'b': |
|
1368 gstring = g_string_append_c (gstring, '\b'); |
|
1369 break; |
|
1370 |
|
1371 case 'f': |
|
1372 gstring = g_string_append_c (gstring, '\f'); |
|
1373 break; |
|
1374 |
|
1375 case '0': |
|
1376 case '1': |
|
1377 case '2': |
|
1378 case '3': |
|
1379 case '4': |
|
1380 case '5': |
|
1381 case '6': |
|
1382 case '7': |
|
1383 i = ch - '0'; |
|
1384 fchar = g_scanner_peek_next_char (scanner); |
|
1385 if (fchar >= '0' && fchar <= '7') |
|
1386 { |
|
1387 ch = g_scanner_get_char (scanner, line_p, position_p); |
|
1388 i = i * 8 + ch - '0'; |
|
1389 fchar = g_scanner_peek_next_char (scanner); |
|
1390 if (fchar >= '0' && fchar <= '7') |
|
1391 { |
|
1392 ch = g_scanner_get_char (scanner, line_p, position_p); |
|
1393 i = i * 8 + ch - '0'; |
|
1394 } |
|
1395 } |
|
1396 gstring = g_string_append_c (gstring, i); |
|
1397 break; |
|
1398 |
|
1399 default: |
|
1400 gstring = g_string_append_c (gstring, ch); |
|
1401 break; |
|
1402 } |
|
1403 } |
|
1404 else |
|
1405 gstring = g_string_append_c (gstring, ch); |
|
1406 } |
|
1407 } |
|
1408 ch = 0; |
|
1409 break; |
|
1410 |
|
1411 case '.': |
|
1412 if (!config->scan_float) |
|
1413 goto default_case; |
|
1414 token = G_TOKEN_FLOAT; |
|
1415 dotted_float = TRUE; |
|
1416 ch = g_scanner_get_char (scanner, line_p, position_p); |
|
1417 goto number_parsing; |
|
1418 |
|
1419 case '$': |
|
1420 if (!config->scan_hex_dollar) |
|
1421 goto default_case; |
|
1422 token = G_TOKEN_HEX; |
|
1423 ch = g_scanner_get_char (scanner, line_p, position_p); |
|
1424 goto number_parsing; |
|
1425 |
|
1426 case '0': |
|
1427 if (config->scan_octal) |
|
1428 token = G_TOKEN_OCTAL; |
|
1429 else |
|
1430 token = G_TOKEN_INT; |
|
1431 ch = g_scanner_peek_next_char (scanner); |
|
1432 if (config->scan_hex && (ch == 'x' || ch == 'X')) |
|
1433 { |
|
1434 token = G_TOKEN_HEX; |
|
1435 g_scanner_get_char (scanner, line_p, position_p); |
|
1436 ch = g_scanner_get_char (scanner, line_p, position_p); |
|
1437 if (ch == 0) |
|
1438 { |
|
1439 token = G_TOKEN_ERROR; |
|
1440 value.v_error = G_ERR_UNEXP_EOF; |
|
1441 (*position_p)++; |
|
1442 break; |
|
1443 } |
|
1444 if (g_scanner_char_2_num (ch, 16) < 0) |
|
1445 { |
|
1446 token = G_TOKEN_ERROR; |
|
1447 value.v_error = G_ERR_DIGIT_RADIX; |
|
1448 ch = 0; |
|
1449 break; |
|
1450 } |
|
1451 } |
|
1452 else if (config->scan_binary && (ch == 'b' || ch == 'B')) |
|
1453 { |
|
1454 token = G_TOKEN_BINARY; |
|
1455 g_scanner_get_char (scanner, line_p, position_p); |
|
1456 ch = g_scanner_get_char (scanner, line_p, position_p); |
|
1457 if (ch == 0) |
|
1458 { |
|
1459 token = G_TOKEN_ERROR; |
|
1460 value.v_error = G_ERR_UNEXP_EOF; |
|
1461 (*position_p)++; |
|
1462 break; |
|
1463 } |
|
1464 if (g_scanner_char_2_num (ch, 10) < 0) |
|
1465 { |
|
1466 token = G_TOKEN_ERROR; |
|
1467 value.v_error = G_ERR_NON_DIGIT_IN_CONST; |
|
1468 ch = 0; |
|
1469 break; |
|
1470 } |
|
1471 } |
|
1472 else |
|
1473 ch = '0'; |
|
1474 /* fall through */ |
|
1475 case '1': |
|
1476 case '2': |
|
1477 case '3': |
|
1478 case '4': |
|
1479 case '5': |
|
1480 case '6': |
|
1481 case '7': |
|
1482 case '8': |
|
1483 case '9': |
|
1484 number_parsing: |
|
1485 { |
|
1486 gboolean in_number = TRUE; |
|
1487 gchar *endptr; |
|
1488 |
|
1489 if (token == G_TOKEN_NONE) |
|
1490 token = G_TOKEN_INT; |
|
1491 |
|
1492 gstring = g_string_new (dotted_float ? "0." : ""); |
|
1493 gstring = g_string_append_c (gstring, ch); |
|
1494 |
|
1495 do /* while (in_number) */ |
|
1496 { |
|
1497 gboolean is_E; |
|
1498 |
|
1499 is_E = token == G_TOKEN_FLOAT && (ch == 'e' || ch == 'E'); |
|
1500 |
|
1501 ch = g_scanner_peek_next_char (scanner); |
|
1502 |
|
1503 if (g_scanner_char_2_num (ch, 36) >= 0 || |
|
1504 (config->scan_float && ch == '.') || |
|
1505 (is_E && (ch == '+' || ch == '-'))) |
|
1506 { |
|
1507 ch = g_scanner_get_char (scanner, line_p, position_p); |
|
1508 |
|
1509 switch (ch) |
|
1510 { |
|
1511 case '.': |
|
1512 if (token != G_TOKEN_INT && token != G_TOKEN_OCTAL) |
|
1513 { |
|
1514 value.v_error = token == G_TOKEN_FLOAT ? G_ERR_FLOAT_MALFORMED : G_ERR_FLOAT_RADIX; |
|
1515 token = G_TOKEN_ERROR; |
|
1516 in_number = FALSE; |
|
1517 } |
|
1518 else |
|
1519 { |
|
1520 token = G_TOKEN_FLOAT; |
|
1521 gstring = g_string_append_c (gstring, ch); |
|
1522 } |
|
1523 break; |
|
1524 |
|
1525 case '0': |
|
1526 case '1': |
|
1527 case '2': |
|
1528 case '3': |
|
1529 case '4': |
|
1530 case '5': |
|
1531 case '6': |
|
1532 case '7': |
|
1533 case '8': |
|
1534 case '9': |
|
1535 gstring = g_string_append_c (gstring, ch); |
|
1536 break; |
|
1537 |
|
1538 case '-': |
|
1539 case '+': |
|
1540 if (token != G_TOKEN_FLOAT) |
|
1541 { |
|
1542 token = G_TOKEN_ERROR; |
|
1543 value.v_error = G_ERR_NON_DIGIT_IN_CONST; |
|
1544 in_number = FALSE; |
|
1545 } |
|
1546 else |
|
1547 gstring = g_string_append_c (gstring, ch); |
|
1548 break; |
|
1549 |
|
1550 case 'e': |
|
1551 case 'E': |
|
1552 if ((token != G_TOKEN_HEX && !config->scan_float) || |
|
1553 (token != G_TOKEN_HEX && |
|
1554 token != G_TOKEN_OCTAL && |
|
1555 token != G_TOKEN_FLOAT && |
|
1556 token != G_TOKEN_INT)) |
|
1557 { |
|
1558 token = G_TOKEN_ERROR; |
|
1559 value.v_error = G_ERR_NON_DIGIT_IN_CONST; |
|
1560 in_number = FALSE; |
|
1561 } |
|
1562 else |
|
1563 { |
|
1564 if (token != G_TOKEN_HEX) |
|
1565 token = G_TOKEN_FLOAT; |
|
1566 gstring = g_string_append_c (gstring, ch); |
|
1567 } |
|
1568 break; |
|
1569 |
|
1570 default: |
|
1571 if (token != G_TOKEN_HEX) |
|
1572 { |
|
1573 token = G_TOKEN_ERROR; |
|
1574 value.v_error = G_ERR_NON_DIGIT_IN_CONST; |
|
1575 in_number = FALSE; |
|
1576 } |
|
1577 else |
|
1578 gstring = g_string_append_c (gstring, ch); |
|
1579 break; |
|
1580 } |
|
1581 } |
|
1582 else |
|
1583 in_number = FALSE; |
|
1584 } |
|
1585 while (in_number); |
|
1586 |
|
1587 endptr = NULL; |
|
1588 if (token == G_TOKEN_FLOAT) |
|
1589 value.v_float = g_strtod (gstring->str, &endptr); |
|
1590 else |
|
1591 { |
|
1592 guint64 ui64 = 0; |
|
1593 switch (token) |
|
1594 { |
|
1595 case G_TOKEN_BINARY: |
|
1596 ui64 = g_ascii_strtoull (gstring->str, &endptr, 2); |
|
1597 break; |
|
1598 case G_TOKEN_OCTAL: |
|
1599 ui64 = g_ascii_strtoull (gstring->str, &endptr, 8); |
|
1600 break; |
|
1601 case G_TOKEN_INT: |
|
1602 ui64 = g_ascii_strtoull (gstring->str, &endptr, 10); |
|
1603 break; |
|
1604 case G_TOKEN_HEX: |
|
1605 ui64 = g_ascii_strtoull (gstring->str, &endptr, 16); |
|
1606 break; |
|
1607 default: ; |
|
1608 } |
|
1609 if (scanner->config->store_int64) |
|
1610 value.v_int64 = ui64; |
|
1611 else |
|
1612 value.v_int = ui64; |
|
1613 } |
|
1614 if (endptr && *endptr) |
|
1615 { |
|
1616 token = G_TOKEN_ERROR; |
|
1617 if (*endptr == 'e' || *endptr == 'E') |
|
1618 value.v_error = G_ERR_NON_DIGIT_IN_CONST; |
|
1619 else |
|
1620 value.v_error = G_ERR_DIGIT_RADIX; |
|
1621 } |
|
1622 g_string_free (gstring, TRUE); |
|
1623 gstring = NULL; |
|
1624 ch = 0; |
|
1625 } /* number_parsing:... */ |
|
1626 break; |
|
1627 |
|
1628 default: |
|
1629 default_case: |
|
1630 { |
|
1631 if (config->cpair_comment_single && |
|
1632 ch == config->cpair_comment_single[0]) |
|
1633 { |
|
1634 token = G_TOKEN_COMMENT_SINGLE; |
|
1635 in_comment_single = TRUE; |
|
1636 gstring = g_string_new (NULL); |
|
1637 ch = g_scanner_get_char (scanner, line_p, position_p); |
|
1638 while (ch != 0) |
|
1639 { |
|
1640 if (ch == config->cpair_comment_single[1]) |
|
1641 { |
|
1642 in_comment_single = FALSE; |
|
1643 ch = 0; |
|
1644 break; |
|
1645 } |
|
1646 |
|
1647 gstring = g_string_append_c (gstring, ch); |
|
1648 ch = g_scanner_get_char (scanner, line_p, position_p); |
|
1649 } |
|
1650 /* ignore a missing newline at EOF for single line comments */ |
|
1651 if (in_comment_single && |
|
1652 config->cpair_comment_single[1] == '\n') |
|
1653 in_comment_single = FALSE; |
|
1654 } |
|
1655 else if (config->scan_identifier && ch && |
|
1656 strchr (config->cset_identifier_first, ch)) |
|
1657 { |
|
1658 identifier_precedence: |
|
1659 |
|
1660 if (config->cset_identifier_nth && ch && |
|
1661 strchr (config->cset_identifier_nth, |
|
1662 g_scanner_peek_next_char (scanner))) |
|
1663 { |
|
1664 token = G_TOKEN_IDENTIFIER; |
|
1665 gstring = g_string_new (NULL); |
|
1666 gstring = g_string_append_c (gstring, ch); |
|
1667 do |
|
1668 { |
|
1669 ch = g_scanner_get_char (scanner, line_p, position_p); |
|
1670 gstring = g_string_append_c (gstring, ch); |
|
1671 ch = g_scanner_peek_next_char (scanner); |
|
1672 } |
|
1673 while (ch && strchr (config->cset_identifier_nth, ch)); |
|
1674 ch = 0; |
|
1675 } |
|
1676 else if (config->scan_identifier_1char) |
|
1677 { |
|
1678 token = G_TOKEN_IDENTIFIER; |
|
1679 value.v_identifier = g_new0 (gchar, 2); |
|
1680 value.v_identifier[0] = ch; |
|
1681 ch = 0; |
|
1682 } |
|
1683 } |
|
1684 if (ch) |
|
1685 { |
|
1686 if (config->char_2_token) |
|
1687 token = ch; |
|
1688 else |
|
1689 { |
|
1690 token = G_TOKEN_CHAR; |
|
1691 value.v_char = ch; |
|
1692 } |
|
1693 ch = 0; |
|
1694 } |
|
1695 } /* default_case:... */ |
|
1696 break; |
|
1697 } |
|
1698 g_assert (ch == 0 && token != G_TOKEN_NONE); /* paranoid */ |
|
1699 } |
|
1700 while (ch != 0); |
|
1701 |
|
1702 if (in_comment_multi || in_comment_single || |
|
1703 in_string_sq || in_string_dq) |
|
1704 { |
|
1705 token = G_TOKEN_ERROR; |
|
1706 if (gstring) |
|
1707 { |
|
1708 g_string_free (gstring, TRUE); |
|
1709 gstring = NULL; |
|
1710 } |
|
1711 (*position_p)++; |
|
1712 if (in_comment_multi || in_comment_single) |
|
1713 value.v_error = G_ERR_UNEXP_EOF_IN_COMMENT; |
|
1714 else /* (in_string_sq || in_string_dq) */ |
|
1715 value.v_error = G_ERR_UNEXP_EOF_IN_STRING; |
|
1716 } |
|
1717 |
|
1718 if (gstring) |
|
1719 { |
|
1720 value.v_string = gstring->str; |
|
1721 g_string_free (gstring, FALSE); |
|
1722 gstring = NULL; |
|
1723 } |
|
1724 |
|
1725 if (token == G_TOKEN_IDENTIFIER) |
|
1726 { |
|
1727 if (config->scan_symbols) |
|
1728 { |
|
1729 GScannerKey *key; |
|
1730 guint scope_id; |
|
1731 |
|
1732 scope_id = scanner->scope_id; |
|
1733 key = g_scanner_lookup_internal (scanner, scope_id, value.v_identifier); |
|
1734 if (!key && scope_id && scanner->config->scope_0_fallback) |
|
1735 key = g_scanner_lookup_internal (scanner, 0, value.v_identifier); |
|
1736 |
|
1737 if (key) |
|
1738 { |
|
1739 g_free (value.v_identifier); |
|
1740 token = G_TOKEN_SYMBOL; |
|
1741 value.v_symbol = key->value; |
|
1742 } |
|
1743 } |
|
1744 |
|
1745 if (token == G_TOKEN_IDENTIFIER && |
|
1746 config->scan_identifier_NULL && |
|
1747 strlen (value.v_identifier) == 4) |
|
1748 { |
|
1749 gchar *null_upper = "NULL"; |
|
1750 gchar *null_lower = "null"; |
|
1751 |
|
1752 if (scanner->config->case_sensitive) |
|
1753 { |
|
1754 if (value.v_identifier[0] == null_upper[0] && |
|
1755 value.v_identifier[1] == null_upper[1] && |
|
1756 value.v_identifier[2] == null_upper[2] && |
|
1757 value.v_identifier[3] == null_upper[3]) |
|
1758 token = G_TOKEN_IDENTIFIER_NULL; |
|
1759 } |
|
1760 else |
|
1761 { |
|
1762 if ((value.v_identifier[0] == null_upper[0] || |
|
1763 value.v_identifier[0] == null_lower[0]) && |
|
1764 (value.v_identifier[1] == null_upper[1] || |
|
1765 value.v_identifier[1] == null_lower[1]) && |
|
1766 (value.v_identifier[2] == null_upper[2] || |
|
1767 value.v_identifier[2] == null_lower[2]) && |
|
1768 (value.v_identifier[3] == null_upper[3] || |
|
1769 value.v_identifier[3] == null_lower[3])) |
|
1770 token = G_TOKEN_IDENTIFIER_NULL; |
|
1771 } |
|
1772 } |
|
1773 } |
|
1774 |
|
1775 *token_p = token; |
|
1776 *value_p = value; |
|
1777 } |
|
1778 |
|
1779 #define __G_SCANNER_C__ |
|
1780 #include "galiasdef.c" |