]> Pileus Git - ~andy/gtk/blob - glib/gscanner.c
f5cbbcf029e41e8baab3aaab63d3c538078ae867
[~andy/gtk] / glib / gscanner.c
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 Tim Janik
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library 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 GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the Free
19  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21 #define         __gscanner_c__
22
23 #include        <stdlib.h>
24 #include        <string.h>
25 #include        <unistd.h>
26 #include        <errno.h>
27 #include        "glib.h"
28
29
30
31 /* --- defines --- */
32 #define to_lower(c)                             ( \
33         (guchar) (                                                      \
34           ( (((guchar)(c))>='A' && ((guchar)(c))<='Z') * ('a'-'A') ) +  \
35           ( (((guchar)(c))>=192 && ((guchar)(c))<=214) * (224-192) ) +  \
36           ( (((guchar)(c))>=216 && ((guchar)(c))<=222) * (248-216) ) +  \
37           ((guchar)(c))                                                 \
38         )                                                               \
39 )
40
41
42 /* --- typedefs --- */
43 typedef struct  _GScannerHashVal        GScannerHashVal;
44
45 struct  _GScannerHashVal
46 {
47   gchar         *key;
48   gpointer      value;
49 };
50
51
52
53 /* --- variables --- */
54 static  GScannerConfig  g_scanner_config_template =
55 {
56   (
57    " \t\n"
58    )                    /* cset_skip_characters */,
59   (
60    G_CSET_a_2_z
61    "_"
62    G_CSET_A_2_Z
63    )                    /* cset_identifier_first */,
64   (
65    G_CSET_a_2_z
66    "_0123456789"
67    G_CSET_A_2_Z
68    G_CSET_LATINS
69    G_CSET_LATINC
70    )                    /* cset_identifier_nth */,
71   ( "#\n" )             /* cpair_comment_single */,
72   
73   FALSE                 /* case_sensitive */,
74   
75   TRUE                  /* skip_comment_multi */,
76   TRUE                  /* skip_comment_single */,
77   TRUE                  /* scan_comment_multi */,
78   TRUE                  /* scan_identifier */,
79   FALSE                 /* scan_identifier_1char */,
80   FALSE                 /* scan_identifier_NULL */,
81   TRUE                  /* scan_symbols */,
82   FALSE                 /* scan_binary */,
83   TRUE                  /* scan_octal */,
84   TRUE                  /* scan_float */,
85   TRUE                  /* scan_hex */,
86   FALSE                 /* scan_hex_dollar */,
87   TRUE                  /* scan_string_sq */,
88   TRUE                  /* scan_string_dq */,
89   TRUE                  /* numbers_2_int */,
90   FALSE                 /* int_2_float */,
91   FALSE                 /* identifier_2_string */,
92   TRUE                  /* char_2_token */,
93   FALSE                 /* symbol_2_token */,
94 };
95
96
97 /* --- prototypes --- */
98 static  GScannerHashVal* g_scanner_lookup_internal (GScanner    *scanner,
99                                                     const gchar *symbol);
100 static  void    g_scanner_get_token_ll  (GScanner       *scanner,
101                                          GTokenType     *token_p,
102                                          GValue         *value_p,
103                                          guint          *line_p,
104                                          guint          *position_p);
105 static  void    g_scanner_get_token_i   (GScanner       *scanner,
106                                          GTokenType     *token_p,
107                                          GValue         *value_p,
108                                          guint          *line_p,
109                                          guint          *position_p);
110 static  void    g_scanner_free_value    (GTokenType     *token_p,
111                                          GValue         *value_p);
112
113 static  inline
114 gint            g_scanner_char_2_num    (guchar         c,
115                                          guchar         base);
116 static  guchar  g_scanner_peek_next_char(GScanner       *scanner);
117 static  guchar  g_scanner_get_char      (GScanner       *scanner,
118                                          guint          *line_p,
119                                          guint          *position_p);
120
121
122 /* --- functions --- */
123 static gint
124 g_scanner_char_2_num (guchar    c,
125                       guchar    base)
126 {
127   if (c >= '0' && c <= '9')
128     c -= '0';
129   else if (c >= 'A' && c <= 'Z')
130     c -= 'A' - 10;
131   else if (c >= 'a' && c <= 'z')
132     c -= 'a' - 10;
133   else
134     return -1;
135   
136   if (c < base)
137     return c;
138   
139   return -1;
140 }
141
142 GScanner*
143 g_scanner_new (GScannerConfig   *config_templ)
144 {
145   register GScanner     *scanner;
146   
147   if (!config_templ)
148     config_templ = &g_scanner_config_template;
149   
150   scanner = g_new0 (GScanner, 1);
151   
152   scanner->user_data = NULL;
153   scanner->input_name = NULL;
154   scanner->parse_errors = 0;
155   scanner->max_parse_errors = 0;
156   
157   scanner->config = g_new0 (GScannerConfig, 1);
158   
159   scanner->config->case_sensitive       = config_templ->case_sensitive;
160   scanner->config->cset_skip_characters = config_templ->cset_skip_characters;
161   scanner->config->cset_identifier_first= config_templ->cset_identifier_first;
162   scanner->config->cset_identifier_nth  = config_templ->cset_identifier_nth;
163   scanner->config->cpair_comment_single = config_templ->cpair_comment_single;
164   scanner->config->skip_comment_multi   = config_templ->skip_comment_multi;
165   scanner->config->skip_comment_single  = config_templ->skip_comment_single;
166   scanner->config->scan_comment_multi   = config_templ->scan_comment_multi;
167   scanner->config->scan_identifier      = config_templ->scan_identifier;
168   scanner->config->scan_identifier_1char= config_templ->scan_identifier_1char;
169   scanner->config->scan_identifier_NULL = config_templ->scan_identifier_NULL;
170   scanner->config->scan_symbols         = config_templ->scan_symbols;
171   scanner->config->scan_binary          = config_templ->scan_binary;
172   scanner->config->scan_octal           = config_templ->scan_octal;
173   scanner->config->scan_float           = config_templ->scan_float;
174   scanner->config->scan_hex             = config_templ->scan_hex;
175   scanner->config->scan_hex_dollar      = config_templ->scan_hex_dollar;
176   scanner->config->scan_string_sq       = config_templ->scan_string_sq;
177   scanner->config->scan_string_dq       = config_templ->scan_string_dq;
178   scanner->config->numbers_2_int        = config_templ->numbers_2_int;
179   scanner->config->int_2_float          = config_templ->int_2_float;
180   scanner->config->identifier_2_string  = config_templ->identifier_2_string;
181   scanner->config->char_2_token         = config_templ->char_2_token;
182   scanner->config->symbol_2_token       = config_templ->symbol_2_token;
183   
184   scanner->token = G_TOKEN_NONE;
185   scanner->value.v_int = 0;
186   scanner->line = 1;
187   scanner->position = 0;
188   
189   scanner->next_token = G_TOKEN_NONE;
190   scanner->next_value.v_int = 0;
191   scanner->next_line = 1;
192   scanner->next_position = 0;
193   
194   scanner->symbol_table = g_hash_table_new (g_str_hash, g_str_equal);
195   scanner->text = NULL;
196   scanner->text_len = 0;
197   scanner->input_fd = -1;
198   scanner->peeked_char = -1;
199   
200   return scanner;
201 }
202
203 static void
204 g_scanner_destroy_symbol_table_entry (gpointer key,
205                                       gpointer value,
206                                       gpointer user_data)
207 {
208   g_free (key);
209   g_free (value);
210 }
211
212 void
213 g_scanner_destroy (GScanner     *scanner)
214 {
215   g_return_if_fail (scanner != NULL);
216   
217   g_hash_table_foreach (scanner->symbol_table, 
218                         g_scanner_destroy_symbol_table_entry, NULL);
219   g_hash_table_destroy (scanner->symbol_table);
220   g_scanner_free_value (&scanner->token, &scanner->value);
221   g_scanner_free_value (&scanner->next_token, &scanner->next_value);
222   g_free (scanner->config);
223   g_free (scanner);
224 }
225
226 void
227 g_scanner_input_file (GScanner  *scanner,
228                       gint      input_fd)
229 {
230   g_return_if_fail (input_fd >= 0);
231   
232   scanner->token = G_TOKEN_NONE;
233   scanner->value.v_int = 0;
234   scanner->line = 1;
235   scanner->position = 0;
236   scanner->next_token = G_TOKEN_NONE;
237   
238   scanner->text = NULL;
239   scanner->text_len = 0;
240   scanner->input_fd = input_fd;
241   scanner->peeked_char = -1;
242 }
243
244 void
245 g_scanner_input_text (GScanner       *scanner,
246                       const  gchar   *text,
247                       guint          text_len)
248 {
249   g_return_if_fail (text != NULL);
250   
251   scanner->token = G_TOKEN_NONE;
252   scanner->value.v_int = 0;
253   scanner->line = 1;
254   scanner->position = 0;
255   scanner->next_token = G_TOKEN_NONE;
256   
257   scanner->text = text;
258   scanner->text_len = text_len;
259   scanner->input_fd = -1;
260   scanner->peeked_char = -1;
261 }
262
263 void
264 g_scanner_add_symbol (GScanner          *scanner,
265                       const gchar       *symbol,
266                       gpointer          value)
267 {
268   register GScannerHashVal      *hash_val;
269   
270   g_return_if_fail (symbol != NULL);
271   g_return_if_fail (scanner != NULL);
272   
273   hash_val = g_scanner_lookup_internal (scanner, symbol);
274   
275   if (!hash_val)
276     {
277       hash_val = g_new (GScannerHashVal, 1);
278       hash_val->key = g_strdup (symbol);
279       hash_val->value = value;
280       if (!scanner->config->case_sensitive)
281         {
282           register guint        i, l;
283           
284           l = strlen (hash_val->key);
285           for (i = 0; i < l; i++)
286             hash_val->key[i] = to_lower (hash_val->key[i]);
287         }
288       g_hash_table_insert (scanner->symbol_table, hash_val->key, hash_val);
289     }
290   else
291     hash_val->value = value;
292 }
293
294 gpointer
295 g_scanner_lookup_symbol (GScanner       *scanner,
296                          const gchar    *symbol)
297 {
298   register GScannerHashVal      *hash_val;
299   
300   g_return_val_if_fail (scanner != NULL, NULL);
301   
302   if (!symbol)
303     return NULL;
304   
305   hash_val = g_scanner_lookup_internal (scanner, symbol);
306   
307   if (hash_val)
308     return hash_val->value;
309   else
310     return NULL;
311 }
312
313 void
314 g_scanner_remove_symbol (GScanner       *scanner,
315                          const gchar    *symbol)
316 {
317   register GScannerHashVal      *hash_val;
318   
319   hash_val = g_scanner_lookup_internal (scanner, symbol);
320   
321   if (hash_val)
322     {
323       g_hash_table_remove (scanner->symbol_table, hash_val->key);
324       g_free (hash_val->key);
325       g_free (hash_val);
326     }
327 }
328
329 GTokenType
330 g_scanner_peek_next_token (GScanner     *scanner)
331 {
332   g_return_val_if_fail (scanner != NULL, G_TOKEN_EOF);
333   
334   if (scanner->next_token == G_TOKEN_NONE)
335     {
336       scanner->next_line = scanner->line;
337       scanner->next_position = scanner->position;
338       g_scanner_get_token_i (scanner,
339                              &scanner->next_token,
340                              &scanner->next_value,
341                              &scanner->next_line,
342                              &scanner->next_position);
343     }
344   
345   return scanner->next_token;
346 }
347
348 GTokenType
349 g_scanner_get_next_token (GScanner      *scanner)
350 {
351   g_return_val_if_fail (scanner != NULL, G_TOKEN_EOF);
352   
353   if (scanner->next_token != G_TOKEN_NONE)
354     {
355       g_scanner_free_value (&scanner->token, &scanner->value);
356       
357       scanner->token = scanner->next_token;
358       scanner->value = scanner->next_value;
359       scanner->line = scanner->next_line;
360       scanner->position = scanner->next_position;
361       scanner->next_token = G_TOKEN_NONE;
362     }
363   else
364     g_scanner_get_token_i (scanner,
365                            &scanner->token,
366                            &scanner->value,
367                            &scanner->line,
368                            &scanner->position);
369   
370   return scanner->token;
371 }
372
373 GTokenType
374 g_scanner_cur_token (GScanner *scanner)
375 {
376   g_return_val_if_fail (scanner != NULL, G_TOKEN_EOF);
377   
378   return scanner->token;
379 }
380
381 GValue
382 g_scanner_cur_value (GScanner *scanner)
383 {
384   register GValue v;
385   
386   v.v_int = 0;
387   g_return_val_if_fail (scanner != NULL, v);
388   
389   return scanner->value;
390 }
391
392 guint
393 g_scanner_cur_line (GScanner *scanner)
394 {
395   g_return_val_if_fail (scanner != NULL, 0);
396   
397   return scanner->line;
398 }
399
400 guint
401 g_scanner_cur_position (GScanner *scanner)
402 {
403   g_return_val_if_fail (scanner != NULL, 0);
404   
405   return scanner->position;
406 }
407
408 gboolean
409 g_scanner_eof (GScanner *scanner)
410 {
411   g_return_val_if_fail (scanner != NULL, TRUE);
412   
413   return scanner->token == G_TOKEN_EOF;
414 }
415
416 static GScannerHashVal*
417 g_scanner_lookup_internal (GScanner     *scanner,
418                            const gchar  *symbol)
419 {
420   register GScannerHashVal      *hash_val;
421   
422   if (!scanner->config->case_sensitive)
423     {
424       register gchar *buffer;
425       register guint i, l;
426       
427       l = strlen (symbol);
428       buffer = g_new (gchar, l + 1);
429       for (i = 0; i < l; i++)
430         buffer[i] = to_lower (symbol[i]);
431       buffer[i] = 0;
432       hash_val = g_hash_table_lookup (scanner->symbol_table, buffer);
433       g_free (buffer);
434     }
435   else
436     hash_val = g_hash_table_lookup (scanner->symbol_table, (gchar*) symbol);
437   
438   return hash_val;
439 }
440
441 static guchar
442 g_scanner_peek_next_char (GScanner *scanner)
443 {
444   guchar fchar;
445   
446   if (scanner->text_len)
447     {
448       fchar = scanner->text[0];
449     }
450   else if (scanner->input_fd >= 0)
451     {
452       if (scanner->peeked_char < 0)
453         {
454           register gint count;
455           
456           do
457             {
458               count = read (scanner->input_fd, &fchar, 1);
459             }
460           while (count == -1 &&
461                  (errno == EINTR ||
462                   errno == EAGAIN));
463           
464           if (count != 1)
465             fchar = 0;
466           
467           scanner->peeked_char = fchar;
468         }
469       else
470         fchar = scanner->peeked_char;
471     }
472   else
473     fchar = 0;
474   
475   return fchar;
476 }
477
478 static guchar
479 g_scanner_get_char (GScanner    *scanner,
480                     guint       *line_p,
481                     guint       *position_p)
482 {
483   guchar fchar;
484   
485   if (scanner->text_len)
486     {
487       fchar = *(scanner->text++);
488       scanner->text_len--;
489     }
490   else if (scanner->input_fd >= 0)
491     {
492       if (scanner->peeked_char < 0)
493         {
494           register gint count;
495           
496           do
497             {
498               count = read (scanner->input_fd, &fchar, 1);
499             }
500           while (count == -1 &&
501                  (errno == EINTR ||
502                   errno == EAGAIN));
503           if (count != 1 || fchar == 0)
504             {
505               fchar = 0;
506               scanner->peeked_char = 0;
507             }
508         }
509       else
510         {
511           fchar = scanner->peeked_char;
512           if (fchar)
513             scanner->peeked_char = -1;
514         }
515     }
516   else
517     fchar = 0;
518   
519   if (fchar == '\n')
520     {
521       (*position_p) = 0;
522       (*line_p)++;
523     }
524   else if (fchar)
525     {
526       (*position_p)++;
527     }
528   
529   return fchar;
530 }
531
532 static void
533 g_scanner_free_value (GTokenType     *token_p,
534                       GValue         *value_p)
535 {
536   switch (*token_p)
537     {
538     case  G_TOKEN_STRING:
539     case  G_TOKEN_IDENTIFIER:
540     case  G_TOKEN_IDENTIFIER_NULL:
541     case  G_TOKEN_COMMENT_SINGLE:
542     case  G_TOKEN_COMMENT_MULTI:
543       g_free (value_p->v_string);
544       break;
545       
546     default:
547       break;
548     }
549   
550   *token_p = G_TOKEN_NONE;
551 }
552
553 static void
554 g_scanner_get_token_i (GScanner *scanner,
555                        GTokenType       *token_p,
556                        GValue           *value_p,
557                        guint            *line_p,
558                        guint            *position_p)
559 {
560   do
561     {
562       g_scanner_free_value (token_p, value_p);
563       g_scanner_get_token_ll (scanner, token_p, value_p, line_p, position_p);
564     }
565   while (((*token_p > 0 && *token_p < 256) &&
566           strchr (scanner->config->cset_skip_characters, *token_p)) ||
567          (*token_p == G_TOKEN_CHAR &&
568           strchr (scanner->config->cset_skip_characters, value_p->v_char)) ||
569          (*token_p == G_TOKEN_COMMENT_MULTI &&
570           scanner->config->skip_comment_multi) ||
571          (*token_p == G_TOKEN_COMMENT_SINGLE &&
572           scanner->config->skip_comment_single));
573   
574   switch (*token_p)
575     {
576     case        G_TOKEN_IDENTIFIER:
577       if (scanner->config->identifier_2_string)
578         *token_p = G_TOKEN_STRING;
579       break;
580       
581     case        G_TOKEN_SYMBOL:
582       if (scanner->config->symbol_2_token)
583         *token_p = (GTokenType) value_p->v_symbol;
584       break;
585       
586     case        G_TOKEN_BINARY:
587     case        G_TOKEN_OCTAL:
588     case        G_TOKEN_HEX:
589       if (scanner->config->numbers_2_int)
590         *token_p = G_TOKEN_INT;
591       break;
592       
593     default:
594       break;
595     }
596   
597   if (*token_p == G_TOKEN_INT &&
598       scanner->config->int_2_float)
599     {
600       *token_p = G_TOKEN_FLOAT;
601       value_p->v_float = value_p->v_int;
602     }
603   
604   errno = 0;
605 }
606
607 static void
608 g_scanner_get_token_ll  (GScanner       *scanner,
609                          GTokenType     *token_p,
610                          GValue         *value_p,
611                          guint          *line_p,
612                          guint          *position_p)
613 {
614   register GScannerConfig       *config;
615   register gboolean             in_comment_multi;
616   register gboolean             in_comment_single;
617   register gboolean             in_string_sq;
618   register gboolean             in_string_dq;
619   static   guchar               ch;
620   register GTokenType           token;
621   register GValue               value;
622   register GString              *gstring;
623   
624   config = scanner->config;
625   (*value_p).v_int = 0;
626   
627   if (scanner->token == G_TOKEN_EOF ||
628       (!scanner->text_len &&
629        (scanner->input_fd < 0 ||
630         scanner->peeked_char == 0)))
631     {
632       *token_p = G_TOKEN_EOF;
633       return;
634     }
635   
636   in_comment_multi = FALSE;
637   in_comment_single = FALSE;
638   in_string_sq = FALSE;
639   in_string_dq = FALSE;
640   gstring = NULL;
641   
642   do
643     {
644       register gboolean         dotted_float = FALSE;
645       
646       ch = g_scanner_get_char (scanner, line_p, position_p);
647       
648       value.v_int = 0;
649       token = G_TOKEN_NONE;
650       
651       /* this is *evil*, but needed ;(
652        * we first check for identifier first character, because  it
653        * might interfere with other key chars like slashes or numbers
654        */
655       if (config->scan_identifier &&
656           ch && strchr (config->cset_identifier_first, ch))
657         goto identifier_precedence;
658       
659       switch (ch)
660         {
661           register gboolean     in_number;
662           static         gchar          *endptr;
663           
664         case  0:
665           token = G_TOKEN_EOF;
666           (*position_p)++;
667           ch = 0;
668           break;
669           
670         case  '/':
671           if (!config->scan_comment_multi ||
672               g_scanner_peek_next_char (scanner) != '*')
673             goto default_case;
674           g_scanner_get_char (scanner, line_p, position_p);
675           token = G_TOKEN_COMMENT_MULTI;
676           in_comment_multi = TRUE;
677           gstring = g_string_new ("");
678           while ((ch = g_scanner_get_char (scanner, line_p, position_p)) != 0)
679             {
680               if (ch == '*' && g_scanner_peek_next_char (scanner) == '/')
681                 {
682                   g_scanner_get_char (scanner, line_p, position_p);
683                   in_comment_multi = FALSE;
684                   break;
685                 }
686               else
687                 gstring = g_string_append_c (gstring, ch);
688             }
689           ch = 0;
690           break;
691           
692         case  '\'':
693           if (!config->scan_string_sq)
694             goto default_case;
695           token = G_TOKEN_STRING;
696           in_string_sq = TRUE;
697           gstring = g_string_new ("");
698           while ((ch = g_scanner_get_char (scanner, line_p, position_p)) != 0)
699             {
700               if (ch == '\'')
701                 {
702                   in_string_sq = FALSE;
703                   break;
704                 }
705               else
706                 gstring = g_string_append_c (gstring, ch);
707             }
708           ch = 0;
709           break;
710           
711         case  '"':
712           if (!config->scan_string_dq)
713             goto default_case;
714           token = G_TOKEN_STRING;
715           in_string_dq = TRUE;
716           gstring = g_string_new ("");
717           while ((ch = g_scanner_get_char (scanner, line_p, position_p)) != 0)
718             {
719               if (ch == '"')
720                 {
721                   in_string_dq = FALSE;
722                   break;
723                 }
724               else
725                 {
726                   if (ch == '\\')
727                     {
728                       ch = g_scanner_get_char (scanner, line_p, position_p);
729                       switch (ch)
730                         {
731                           register guint        i;
732                           register guint        fchar;
733                           
734                         case  0:
735                           break;
736                           
737                         case  '\\':
738                           gstring = g_string_append_c (gstring, '\\');
739                           break;
740                           
741                         case  'n':
742                           gstring = g_string_append_c (gstring, '\n');
743                           break;
744                           
745                         case  't':
746                           gstring = g_string_append_c (gstring, '\t');
747                           break;
748                           
749                         case  'r':
750                           gstring = g_string_append_c (gstring, '\r');
751                           break;
752                           
753                         case  'b':
754                           gstring = g_string_append_c (gstring, '\b');
755                           break;
756                           
757                         case  'f':
758                           gstring = g_string_append_c (gstring, '\f');
759                           break;
760                           
761                         case  '0':
762                         case  '1':
763                         case  '2':
764                         case  '3':
765                         case  '4':
766                         case  '5':
767                         case  '6':
768                         case  '7':
769                           i = ch - '0';
770                           fchar = g_scanner_peek_next_char (scanner);
771                           if (fchar >= '0' && fchar <= '7')
772                             {
773                               ch = g_scanner_get_char (scanner, line_p, position_p);
774                               i= i * 8 + ch - '0';
775                               fchar = g_scanner_peek_next_char (scanner);
776                               if (fchar >= '0' && fchar <= '7')
777                                 {
778                                   ch = g_scanner_get_char (scanner, line_p, position_p);
779                                   i = i * 8 + ch - '0';
780                                 }
781                             }
782                           gstring = g_string_append_c (gstring, i);
783                           break;
784                           
785                         default:
786                           gstring = g_string_append_c (gstring, ch);
787                           break;
788                         }
789                     }
790                   else
791                     gstring = g_string_append_c (gstring, ch);
792                 }
793             }
794           ch = 0;
795           break;
796           
797         case  '.':
798           if (!config->scan_float)
799             goto default_case;
800           token = G_TOKEN_FLOAT;
801           dotted_float = TRUE;
802           ch = g_scanner_get_char (scanner, line_p, position_p);
803           goto number_parsing;
804           
805         case  '$':
806           if (!config->scan_hex_dollar)
807             goto default_case;
808           token = G_TOKEN_HEX;
809           ch = g_scanner_get_char (scanner, line_p, position_p);
810           goto number_parsing;
811           
812         case  '0':
813           if (config->scan_octal)
814             token = G_TOKEN_OCTAL;
815           else
816             token = G_TOKEN_INT;
817           ch = g_scanner_peek_next_char (scanner);
818           if (config->scan_hex && (ch == 'x' || ch == 'X'))
819             {
820               token = G_TOKEN_HEX;
821               g_scanner_get_char (scanner, line_p, position_p);
822               ch = g_scanner_get_char (scanner, line_p, position_p);
823               if (ch == 0)
824                 {
825                   token = G_TOKEN_ERROR;
826                   value.v_error = G_ERR_UNEXP_EOF;
827                   (*position_p)++;
828                   break;
829                 }
830               if (g_scanner_char_2_num (ch, 16) < 0)
831                 {
832                   token = G_TOKEN_ERROR;
833                   value.v_error = G_ERR_DIGIT_RADIX;
834                   ch = 0;
835                   break;
836                 }
837             }
838           else if (config->scan_binary && (ch == 'b' || ch == 'B'))
839             {
840               token = G_TOKEN_BINARY;
841               g_scanner_get_char (scanner, line_p, position_p);
842               ch = g_scanner_get_char (scanner, line_p, position_p);
843               if (ch == 0)
844                 {
845                   token = G_TOKEN_ERROR;
846                   value.v_error = G_ERR_UNEXP_EOF;
847                   (*position_p)++;
848                   break;
849                 }
850               if (g_scanner_char_2_num (ch, 10) < 0)
851                 {
852                   token = G_TOKEN_ERROR;
853                   value.v_error = G_ERR_NON_DIGIT_IN_CONST;
854                   ch = 0;
855                   break;
856                 }
857             }
858           else
859             ch = '0';
860           /* fall through */
861         case  '1':
862         case  '2':
863         case  '3':
864         case  '4':
865         case  '5':
866         case  '6':
867         case  '7':
868         case  '8':
869         case  '9':
870         number_parsing:
871         if (token == G_TOKEN_NONE)
872           token = G_TOKEN_INT;
873         
874         gstring = g_string_new (dotted_float ? "0." : "");
875         gstring = g_string_append_c (gstring, ch);
876         in_number = TRUE;
877         while (in_number)
878           {
879             register gboolean is_E;
880             
881             is_E = (ch == 'e' || ch == 'E') && token == G_TOKEN_FLOAT;
882             ch = g_scanner_peek_next_char (scanner);
883             
884             if (g_scanner_char_2_num (ch, 36) >= 0 ||
885                 (config->scan_float && ch == '.') ||
886                 (is_E && ch == '+') ||
887                 (is_E && ch == '-') )
888               ch = g_scanner_get_char (scanner, line_p, position_p);
889             else
890               in_number = FALSE;
891             
892             if (in_number)
893               switch (ch)
894                 {
895                 case  '.':
896                   if (token != G_TOKEN_INT &&
897                       token != G_TOKEN_OCTAL)
898                     {
899                       token = G_TOKEN_ERROR;
900                       if (token == G_TOKEN_FLOAT)
901                         value.v_error = G_ERR_FLOAT_MALFORMED;
902                       else
903                         value.v_error = G_ERR_FLOAT_RADIX;
904                       in_number = FALSE;
905                     }
906                   else
907                     {
908                       token = G_TOKEN_FLOAT;
909                       gstring = g_string_append_c (gstring, ch);
910                     }
911                   break;
912                   
913                 case    '0':
914                 case  '1':
915                 case  '2':
916                 case  '3':
917                 case  '4':
918                 case  '5':
919                 case  '6':
920                 case  '7':
921                 case  '8':
922                 case  '9':
923                   gstring = g_string_append_c (gstring, ch);
924                   break;
925                   
926                 case    '-':
927                 case    '+':
928                   if (token != G_TOKEN_FLOAT)
929                     {
930                       token = G_TOKEN_ERROR;
931                       value.v_error = G_ERR_NON_DIGIT_IN_CONST;
932                       in_number = FALSE;
933                     }
934                   else
935                     gstring = g_string_append_c (gstring, ch);
936                   break;
937                   
938                 case    'e':
939                 case    'E':
940                   if ((token != G_TOKEN_HEX && !config->scan_float) ||
941                       (token != G_TOKEN_HEX &&
942                        token != G_TOKEN_OCTAL &&
943                        token != G_TOKEN_FLOAT &&
944                        token != G_TOKEN_INT))
945                     {
946                       token = G_TOKEN_ERROR;
947                       value.v_error = G_ERR_NON_DIGIT_IN_CONST;
948                       in_number = FALSE;
949                     }
950                   else
951                     {
952                       if (token != G_TOKEN_HEX)
953                         token = G_TOKEN_FLOAT;
954                       gstring = g_string_append_c (gstring, ch);
955                     }
956                   break;
957                   
958                 default:
959                   if (token != G_TOKEN_HEX)
960                     {
961                       token = G_TOKEN_ERROR;
962                       value.v_error = G_ERR_NON_DIGIT_IN_CONST;
963                       in_number = FALSE;
964                     }
965                   else
966                     gstring = g_string_append_c (gstring, ch);
967                   break;
968                 }
969           }
970         endptr = NULL;
971         switch (token)
972           {
973           case  G_TOKEN_BINARY:
974             value.v_binary = strtol (gstring->str, &endptr, 2);
975             break;
976             
977           case  G_TOKEN_OCTAL:
978             value.v_octal = strtol (gstring->str, &endptr, 8);
979             break;
980             
981           case  G_TOKEN_INT:
982             value.v_int = strtol (gstring->str, &endptr, 10);
983             break;
984             
985           case  G_TOKEN_FLOAT:
986             value.v_float = g_strtod (gstring->str, &endptr);
987             break;
988             
989           case  G_TOKEN_HEX:
990             value.v_hex = strtol (gstring->str, &endptr, 16);
991             break;
992             
993           default:
994             break;
995           }
996         if (endptr && *endptr)
997           {
998             token = G_TOKEN_ERROR;
999             if (*endptr == 'e' || *endptr == 'E')
1000               value.v_error = G_ERR_NON_DIGIT_IN_CONST;
1001             else
1002               value.v_error = G_ERR_DIGIT_RADIX;
1003           }
1004         g_string_free (gstring, TRUE);
1005         gstring = NULL;
1006         ch = 0;
1007         break;
1008         
1009         default:
1010         default_case:
1011         if (config->cpair_comment_single &&
1012             ch == config->cpair_comment_single[0])
1013           {
1014             token = G_TOKEN_COMMENT_SINGLE;
1015             in_comment_single = TRUE;
1016             gstring = g_string_new ("");
1017             while ((ch = g_scanner_get_char (scanner,
1018                                              line_p,
1019                                              position_p)) != 0)
1020               {
1021                 if (ch == config->cpair_comment_single[1])
1022                   {
1023                     in_comment_single = FALSE;
1024                     ch = 0;
1025                     break;
1026                   }
1027                 
1028                 gstring = g_string_append_c (gstring, ch);
1029                 ch = 0;
1030               }
1031           }
1032         else if (config->scan_identifier && ch &&
1033                  strchr (config->cset_identifier_first, ch))
1034           {
1035           identifier_precedence:
1036             
1037             if (config->cset_identifier_nth && ch &&
1038                 strchr (config->cset_identifier_nth,
1039                         g_scanner_peek_next_char (scanner)))
1040               {
1041                 token = G_TOKEN_IDENTIFIER;
1042                 gstring = g_string_new ("");
1043                 gstring = g_string_append_c (gstring, ch);
1044                 do
1045                   {
1046                     ch = g_scanner_get_char (scanner, line_p, position_p);
1047                     gstring = g_string_append_c (gstring, ch);
1048                     ch = g_scanner_peek_next_char (scanner);
1049                   }
1050                 while (ch && strchr (config->cset_identifier_nth, ch));
1051                 ch = 0;
1052               }
1053             else if (config->scan_identifier_1char)
1054               {
1055                 token = G_TOKEN_IDENTIFIER;
1056                 value.v_identifier = g_new0 (gchar, 2);
1057                 value.v_identifier[0] = ch;
1058                 ch = 0;
1059               }
1060           }
1061         if (ch)
1062           {
1063             if (config->char_2_token)
1064               token = ch;
1065             else
1066               {
1067                 token = G_TOKEN_CHAR;
1068                 value.v_char = ch;
1069               }
1070             ch = 0;
1071           }
1072         break;
1073         }
1074       g_assert (ch == 0 && token != G_TOKEN_NONE);
1075     }
1076   while (ch != 0);
1077   
1078   if (in_comment_multi ||
1079       in_comment_single ||
1080       in_string_sq ||
1081       in_string_dq)
1082     {
1083       token = G_TOKEN_ERROR;
1084       if (gstring)
1085         {
1086           g_string_free (gstring, TRUE);
1087           gstring = NULL;
1088         }
1089       (*position_p)++;
1090       if (in_comment_multi || in_comment_single)
1091         value.v_error = G_ERR_UNEXP_EOF_IN_COMMENT;
1092       else if (in_string_sq || in_string_dq)
1093         value.v_error = G_ERR_UNEXP_EOF_IN_STRING;
1094     }
1095   
1096   if (gstring)
1097     {
1098       value.v_string = gstring->str;
1099       g_string_free (gstring, FALSE);
1100       gstring = NULL;
1101     }
1102   
1103   if (token == G_TOKEN_IDENTIFIER &&
1104       config->scan_symbols)
1105     {
1106       register GScannerHashVal  *hash_val;
1107       
1108       hash_val = g_scanner_lookup_internal (scanner, value.v_identifier);
1109       
1110       if (hash_val)
1111         {
1112           g_free (value.v_identifier);
1113           token = G_TOKEN_SYMBOL;
1114           value.v_symbol = hash_val->value;
1115         }
1116     }
1117
1118   if (token == G_TOKEN_IDENTIFIER &&
1119       config->scan_identifier_NULL &&
1120       strlen (value.v_identifier) == 4)
1121     {
1122       gchar *null_upper = "NULL";
1123       gchar *null_lower = "null";
1124       
1125       if (scanner->config->case_sensitive)
1126         {
1127           if (value.v_identifier[0] == null_upper[0] &&
1128               value.v_identifier[1] == null_upper[1] &&
1129               value.v_identifier[2] == null_upper[2] &&
1130               value.v_identifier[3] == null_upper[3])
1131             token = G_TOKEN_IDENTIFIER_NULL;
1132         }
1133       else
1134         {
1135           if ((value.v_identifier[0] == null_upper[0] ||
1136                value.v_identifier[0] == null_lower[0]) &&
1137               (value.v_identifier[1] == null_upper[1] ||
1138                value.v_identifier[1] == null_lower[1]) &&
1139               (value.v_identifier[2] == null_upper[2] ||
1140                value.v_identifier[2] == null_lower[2]) &&
1141               (value.v_identifier[3] == null_upper[3] ||
1142                value.v_identifier[3] == null_lower[3]))
1143             token = G_TOKEN_IDENTIFIER_NULL;
1144         }
1145     }
1146   
1147   *token_p = token;
1148   *value_p = value;
1149 }