import source from 1.3.40
[external/swig.git] / Source / Swig / scanner.c
1 /* ----------------------------------------------------------------------------- 
2  * See the LICENSE file for information on copyright, usage and redistribution
3  * of SWIG, and the README file for authors - http://www.swig.org/release.html.
4  *
5  * scanner.c
6  *
7  * This file implements a general purpose C/C++ compatible lexical scanner.
8  * This scanner isn't intended to be plugged directly into a parser built
9  * with yacc. Rather, it contains a lot of generic code that could be used
10  * to easily construct yacc-compatible scanners.
11  * ----------------------------------------------------------------------------- */
12
13 char cvsroot_scanner_c[] = "$Id: scanner.c 11470 2009-07-29 20:50:39Z wsfulton $";
14
15 #include "swig.h"
16 #include <ctype.h>
17
18 extern String *cparse_file;
19 extern int     cparse_start_line;
20
21 struct Scanner {
22   String *text;                 /* Current token value */
23   List   *scanobjs;             /* Objects being scanned */
24   String *str;                  /* Current object being scanned */
25   char   *idstart;              /* Optional identifier start characters */
26   int     nexttoken;            /* Next token to be returned */
27   int     start_line;           /* Starting line of certain declarations */
28   int     line;
29   int     yylen;                /* Length of text pushed into text */
30   String *file;
31   String *error;                /* Last error message (if any) */
32   int     error_line;           /* Error line number */
33   int     freeze_line;          /* Suspend line number updates */
34 };
35
36 /* -----------------------------------------------------------------------------
37  * NewScanner()
38  *
39  * Create a new scanner object
40  * ----------------------------------------------------------------------------- */
41
42 Scanner *NewScanner(void) {
43   Scanner *s;
44   s = (Scanner *) malloc(sizeof(Scanner));
45   s->line = 1;
46   s->file = 0;
47   s->nexttoken = -1;
48   s->start_line = 1;
49   s->yylen = 0;
50   s->idstart = NULL;
51   s->scanobjs = NewList();
52   s->text = NewStringEmpty();
53   s->str = 0;
54   s->error = 0;
55   s->freeze_line = 0;
56   return s;
57 }
58
59 /* -----------------------------------------------------------------------------
60  * DelScanner()
61  *
62  * Delete a scanner object.
63  * ----------------------------------------------------------------------------- */
64
65 void DelScanner(Scanner * s) {
66   assert(s);
67   Delete(s->scanobjs);
68   Delete(s->text);
69   Delete(s->file);
70   Delete(s->error);
71   Delete(s->str);
72   free(s->idstart);
73   free(s);
74 }
75
76 /* -----------------------------------------------------------------------------
77  * Scanner_clear()
78  *
79  * Clear the contents of a scanner object.
80  * ----------------------------------------------------------------------------- */
81
82 void Scanner_clear(Scanner * s) {
83   assert(s);
84   Delete(s->str);
85   Clear(s->text);
86   Clear(s->scanobjs);
87   Delete(s->error);
88   s->str = 0;
89   s->error = 0;
90   s->line = 1;
91   s->nexttoken = -1;
92   s->start_line = 0;
93   s->yylen = 0;
94 }
95
96 /* -----------------------------------------------------------------------------
97  * Scanner_push()
98  *
99  * Push some new text into the scanner.  The scanner will start parsing this text
100  * immediately before returning to the old text.
101  * ----------------------------------------------------------------------------- */
102
103 void Scanner_push(Scanner * s, String *txt) {
104   assert(s && txt);
105   Push(s->scanobjs, txt);
106   if (s->str) {
107     Setline(s->str,s->line);
108     Delete(s->str);
109   }
110   s->str = txt;
111   DohIncref(s->str);
112   s->line = Getline(txt);
113 }
114
115 /* -----------------------------------------------------------------------------
116  * Scanner_pushtoken()
117  *
118  * Push a token into the scanner.  This token will be returned on the next
119  * call to Scanner_token().
120  * ----------------------------------------------------------------------------- */
121
122 void Scanner_pushtoken(Scanner * s, int nt, const_String_or_char_ptr val) {
123   assert(s);
124   assert((nt >= 0) && (nt < SWIG_MAXTOKENS));
125   s->nexttoken = nt;
126   if ( Char(val) != Char(s->text) ) {
127     Clear(s->text);
128     Append(s->text,val);
129   }
130 }
131
132 /* -----------------------------------------------------------------------------
133  * Scanner_set_location()
134  *
135  * Set the file and line number location of the scanner.
136  * ----------------------------------------------------------------------------- */
137
138 void Scanner_set_location(Scanner * s, String *file, int line) {
139   Setline(s->str, line);
140   Setfile(s->str, file);
141   s->line = line;
142 }
143
144 /* -----------------------------------------------------------------------------
145  * Scanner_file()
146  *
147  * Get the current file.
148  * ----------------------------------------------------------------------------- */
149
150 String *Scanner_file(Scanner * s) {
151   return Getfile(s->str);
152 }
153
154 /* -----------------------------------------------------------------------------
155  * Scanner_line()
156  *
157  * Get the current line number
158  * ----------------------------------------------------------------------------- */
159 int Scanner_line(Scanner * s) {
160   return s->line;
161 }
162
163 /* -----------------------------------------------------------------------------
164  * Scanner_start_line()
165  *
166  * Get the line number on which the current token starts
167  * ----------------------------------------------------------------------------- */
168 int Scanner_start_line(Scanner * s) {
169   return s->start_line;
170 }
171
172 /* -----------------------------------------------------------------------------
173  * Scanner_idstart()
174  *
175  * Change the set of additional characters that can be used to start an identifier.
176  * ----------------------------------------------------------------------------- */
177
178 void Scanner_idstart(Scanner * s, const char *id) {
179   free(s->idstart);
180   s->idstart = Swig_copy_string(id);
181 }
182
183 /* -----------------------------------------------------------------------------
184  * nextchar()
185  * 
186  * Returns the next character from the scanner or 0 if end of the string.
187  * ----------------------------------------------------------------------------- */
188 static char nextchar(Scanner * s) {
189   int nc;
190   if (!s->str)
191     return 0;
192   while ((nc = Getc(s->str)) == EOF) {
193     Delete(s->str);
194     s->str = 0;
195     Delitem(s->scanobjs, 0);
196     if (Len(s->scanobjs) == 0)
197       return 0;
198     s->str = Getitem(s->scanobjs, 0);
199     if (s->str) {
200       s->line = Getline(s->str);
201       DohIncref(s->str);
202     }
203   }
204   if ((nc == '\n') && (!s->freeze_line)) 
205     s->line++;
206   Putc(nc,s->text);
207   return (char)nc;
208 }
209
210 /* -----------------------------------------------------------------------------
211  * set_error() 
212  *
213  * Sets error information on the scanner.
214  * ----------------------------------------------------------------------------- */
215
216 static void set_error(Scanner *s, int line, const_String_or_char_ptr msg) {
217   s->error_line = line;
218   s->error = NewString(msg);
219 }
220
221 /* -----------------------------------------------------------------------------
222  * Scanner_errmsg()
223  * Scanner_errline()
224  *
225  * Returns error information (if any)
226  * ----------------------------------------------------------------------------- */
227
228 String *
229 Scanner_errmsg(Scanner *s) {
230   return s->error;
231 }
232
233 int
234 Scanner_errline(Scanner *s) {
235   return s->error_line;
236 }
237
238 /* -----------------------------------------------------------------------------
239  * Scanner_freeze_line()
240  *
241  * Freezes the current line number.
242  * ----------------------------------------------------------------------------- */
243
244 void
245 Scanner_freeze_line(Scanner *s, int val) {
246   s->freeze_line = val;
247 }
248
249 /* -----------------------------------------------------------------------------
250  * retract()
251  *
252  * Retract n characters
253  * ----------------------------------------------------------------------------- */
254 static void retract(Scanner * s, int n) {
255   int i, l;
256   char *str;
257
258   str = Char(s->text);
259   l = Len(s->text);
260   assert(n <= l);
261   for (i = 0; i < n; i++) {
262     if (str[l - 1] == '\n') {
263       if (!s->freeze_line) s->line--;
264     }
265     Seek(s->str, -1, SEEK_CUR);
266     Delitem(s->text, DOH_END);
267   }
268 }
269
270 /* -----------------------------------------------------------------------------
271  * get_escape()
272  * 
273  * Get escape sequence.  Called when a backslash is found in a string
274  * ----------------------------------------------------------------------------- */
275
276 static void get_escape(Scanner *s) {
277   int result = 0;
278   int state = 0;
279   int c;
280
281   while (1) {
282     c = nextchar(s);
283     if (c == 0)
284       break;
285     switch (state) {
286     case 0:
287       if (c == 'n') {
288         Delitem(s->text, DOH_END);
289         Append(s->text,"\n");
290         return;
291       }
292       if (c == 'r') {
293         Delitem(s->text, DOH_END);
294         Append(s->text,"\r");
295         return;
296       }
297       if (c == 't') {
298         Delitem(s->text, DOH_END);
299         Append(s->text,"\t");
300         return;
301       }
302       if (c == 'a') {
303         Delitem(s->text, DOH_END);
304         Append(s->text,"\a");
305         return;
306       }
307       if (c == 'b') {
308         Delitem(s->text, DOH_END);
309         Append(s->text,"\b");
310         return;
311       }
312       if (c == 'f') {
313         Delitem(s->text, DOH_END);
314         Append(s->text,"\f");
315         return;
316       }
317       if (c == '\\') {
318         Delitem(s->text, DOH_END);
319         Append(s->text,"\\");
320         return;
321       }
322       if (c == 'v') {
323         Delitem(s->text, DOH_END);
324         Append(s->text,"\v");
325         return;
326       }
327       if (c == 'e') {
328         Delitem(s->text, DOH_END);
329         Append(s->text,"\033");
330         return;
331       }
332       if (c == '\'') {
333         Delitem(s->text, DOH_END);
334         Append(s->text,"\'");
335         return;
336       }
337       if (c == '\"') {
338         Delitem(s->text, DOH_END);      
339         Append(s->text,"\"");
340         return;
341       }
342       if (c == '\n') {
343         Delitem(s->text, DOH_END);
344         return;
345       }
346       if (isdigit(c)) {
347         state = 10;
348         result = (c - '0');
349         Delitem(s->text, DOH_END);
350       } else if (c == 'x') {
351         state = 20;
352         Delitem(s->text, DOH_END);
353       } else {
354         char tmp[3];
355         tmp[0] = '\\';
356         tmp[1] = (char)c;
357         tmp[2] = 0;
358         Delitem(s->text, DOH_END);
359         Append(s->text, tmp);
360         return;
361       }
362       break;
363     case 10:
364       if (!isdigit(c)) {
365         retract(s,1);
366         Putc((char)result,s->text);
367         return;
368       }
369       result = (result << 3) + (c - '0');
370       Delitem(s->text, DOH_END);
371       break;
372     case 20:
373       if (!isxdigit(c)) {
374         retract(s,1);
375         Putc((char)result, s->text);
376         return;
377       }
378       if (isdigit(c))
379         result = (result << 4) + (c - '0');
380       else
381         result = (result << 4) + (10 + tolower(c) - 'a');
382       Delitem(s->text, DOH_END);
383       break;
384     }
385   }
386   return;
387 }
388
389 /* -----------------------------------------------------------------------------
390  * look()
391  *
392  * Return the raw value of the next token.
393  * ----------------------------------------------------------------------------- */
394
395 static int look(Scanner * s) {
396   int state;
397   int c = 0;
398
399   state = 0;
400   Clear(s->text);
401   s->start_line = s->line;
402   Setfile(s->text, Getfile(s->str));
403   while (1) {
404     switch (state) {
405     case 0:
406       if ((c = nextchar(s)) == 0)
407         return (0);
408
409       /* Process delimiters */
410
411       if (c == '\n') {
412         return SWIG_TOKEN_ENDLINE;
413       } else if (!isspace(c)) {
414         retract(s, 1);
415         state = 1000;
416         Clear(s->text);
417         Setline(s->text, s->line);
418         Setfile(s->text, Getfile(s->str));
419       }
420       break;
421
422     case 1000:
423       if ((c = nextchar(s)) == 0)
424         return (0);
425       if (c == '%')
426         state = 4;              /* Possibly a SWIG directive */
427
428       /* Look for possible identifiers */
429
430       else if ((isalpha(c)) || (c == '_') ||
431                (s->idstart && strchr(s->idstart, c)))
432         state = 7;
433
434       /* Look for single character symbols */
435
436       else if (c == '(')
437         return SWIG_TOKEN_LPAREN;
438       else if (c == ')')
439         return SWIG_TOKEN_RPAREN;
440       else if (c == ';')
441         return SWIG_TOKEN_SEMI;
442       else if (c == ',')
443         return SWIG_TOKEN_COMMA;
444       else if (c == '*')
445         state = 220;
446       else if (c == '}')
447         return SWIG_TOKEN_RBRACE;
448       else if (c == '{')
449         return SWIG_TOKEN_LBRACE;
450       else if (c == '=')
451         state = 33;
452       else if (c == '+')
453         state = 200;
454       else if (c == '-')
455         state = 210;
456       else if (c == '&')
457         state = 31;
458       else if (c == '|')
459         state = 32;
460       else if (c == '^')
461         state = 230;
462       else if (c == '<')
463         state = 60;
464       else if (c == '>')
465         state = 61;
466       else if (c == '~')
467         return SWIG_TOKEN_NOT;
468       else if (c == '!')
469         state = 3;
470       else if (c == '\\')
471         return SWIG_TOKEN_BACKSLASH;
472       else if (c == '[')
473         return SWIG_TOKEN_LBRACKET;
474       else if (c == ']')
475         return SWIG_TOKEN_RBRACKET;
476       else if (c == '@')
477         return SWIG_TOKEN_AT;
478       else if (c == '$')
479         state = 75;
480       else if (c == '#')
481         return SWIG_TOKEN_POUND;
482       else if (c == '?')
483         return SWIG_TOKEN_QUESTION;
484
485       /* Look for multi-character sequences */
486
487       else if (c == '/') {
488         state = 1;              /* Comment (maybe)  */
489         s->start_line = s->line;
490       }
491       else if (c == '\"') {
492         state = 2;              /* Possibly a string */
493         s->start_line = s->line;
494         Clear(s->text);
495       }
496
497       else if (c == ':')
498         state = 5;              /* maybe double colon */
499       else if (c == '0')
500         state = 83;             /* An octal or hex value */
501       else if (c == '\'') {
502         s->start_line = s->line;
503         Clear(s->text);
504         state = 9;              /* A character constant */
505       } else if (c == '`') {
506         s->start_line = s->line;
507         Clear(s->text);
508         state = 900;
509       }
510
511       else if (c == '.')
512         state = 100;            /* Maybe a number, maybe just a period */
513       else if (isdigit(c))
514         state = 8;              /* A numerical value */
515       else
516         state = 99;             /* An error */
517       break;
518
519     case 1:                     /*  Comment block */
520       if ((c = nextchar(s)) == 0)
521         return (0);
522       if (c == '/') {
523         state = 10;             /* C++ style comment */
524         Clear(s->text);
525         Setline(s->text, Getline(s->str));
526         Setfile(s->text, Getfile(s->str));
527         Append(s->text, "//");
528       } else if (c == '*') {
529         state = 11;             /* C style comment */
530         Clear(s->text);
531         Setline(s->text, Getline(s->str));
532         Setfile(s->text, Getfile(s->str));
533         Append(s->text, "/*");
534       } else if (c == '=') {
535         return SWIG_TOKEN_DIVEQUAL;
536       } else {
537         retract(s, 1);
538         return SWIG_TOKEN_SLASH;
539       }
540       break;
541     case 10:                    /* C++ style comment */
542       if ((c = nextchar(s)) == 0) {
543         Swig_error(cparse_file, cparse_start_line, "Unterminated comment\n");
544         return SWIG_TOKEN_ERROR;
545       }
546       if (c == '\n') {
547         retract(s,1);
548         return SWIG_TOKEN_COMMENT;
549       } else {
550         state = 10;
551       }
552       break;
553     case 11:                    /* C style comment block */
554       if ((c = nextchar(s)) == 0) {
555         Swig_error(cparse_file, cparse_start_line, "Unterminated comment\n");
556         return SWIG_TOKEN_ERROR;
557       }
558       if (c == '*') {
559         state = 12;
560       } else {
561         state = 11;
562       }
563       break;
564     case 12:                    /* Still in C style comment */
565       if ((c = nextchar(s)) == 0) {
566         Swig_error(cparse_file, cparse_start_line, "Unterminated comment\n");
567         return SWIG_TOKEN_ERROR;
568       }
569       if (c == '*') {
570         state = 12;
571       } else if (c == '/') {
572         return SWIG_TOKEN_COMMENT;
573       } else {
574         state = 11;
575       }
576       break;
577
578     case 2:                     /* Processing a string */
579       if ((c = nextchar(s)) == 0) {
580         Swig_error(cparse_file, cparse_start_line, "Unterminated string\n");
581         return SWIG_TOKEN_ERROR;
582       }
583       if (c == '\"') {
584         Delitem(s->text, DOH_END);
585         return SWIG_TOKEN_STRING;
586       } else if (c == '\\') {
587         Delitem(s->text, DOH_END);
588         get_escape(s);
589       } else
590         state = 2;
591       break;
592
593     case 3:                     /* Maybe a not equals */
594       if ((c = nextchar(s)) == 0)
595         return SWIG_TOKEN_LNOT;
596       else if (c == '=')
597         return SWIG_TOKEN_NOTEQUAL;
598       else {
599         retract(s, 1);
600         return SWIG_TOKEN_LNOT;
601       }
602       break;
603
604     case 31:                    /* AND or Logical AND or ANDEQUAL */
605       if ((c = nextchar(s)) == 0)
606         return SWIG_TOKEN_AND;
607       else if (c == '&')
608         return SWIG_TOKEN_LAND;
609       else if (c == '=')
610         return SWIG_TOKEN_ANDEQUAL;
611       else {
612         retract(s, 1);
613         return SWIG_TOKEN_AND;
614       }
615       break;
616
617     case 32:                    /* OR or Logical OR */
618       if ((c = nextchar(s)) == 0)
619         return SWIG_TOKEN_OR;
620       else if (c == '|')
621         return SWIG_TOKEN_LOR;
622       else if (c == '=')
623         return SWIG_TOKEN_OREQUAL;
624       else {
625         retract(s, 1);
626         return SWIG_TOKEN_OR;
627       }
628       break;
629
630     case 33:                    /* EQUAL or EQUALTO */
631       if ((c = nextchar(s)) == 0)
632         return SWIG_TOKEN_EQUAL;
633       else if (c == '=')
634         return SWIG_TOKEN_EQUALTO;
635       else {
636         retract(s, 1);
637         return SWIG_TOKEN_EQUAL;
638       }
639       break;
640
641     case 4:                     /* A wrapper generator directive (maybe) */
642       if ((c = nextchar(s)) == 0)
643         return SWIG_TOKEN_PERCENT;
644       if (c == '{') {
645         state = 40;             /* Include block */
646         Clear(s->text);
647         Setline(s->text, Getline(s->str));
648         Setfile(s->text, Getfile(s->str));
649         s->start_line = s->line;
650       } else if (s->idstart && strchr(s->idstart, '%') &&
651                  ((isalpha(c)) || (c == '_'))) {
652         state = 7;
653       } else if (c == '=') {
654         return SWIG_TOKEN_MODEQUAL;
655       } else {
656         retract(s, 1);
657         return SWIG_TOKEN_PERCENT;
658       }
659       break;
660
661     case 40:                    /* Process an include block */
662       if ((c = nextchar(s)) == 0) {
663         Swig_error(cparse_file, cparse_start_line, "Unterminated block\n");
664         return SWIG_TOKEN_ERROR;
665       }
666       if (c == '%')
667         state = 41;
668       break;
669     case 41:                    /* Still processing include block */
670       if ((c = nextchar(s)) == 0) {
671         set_error(s,s->start_line,"Unterminated code block");
672         return 0;
673       }
674       if (c == '}') {
675         Delitem(s->text, DOH_END);
676         Delitem(s->text, DOH_END);
677         Seek(s->text,0,SEEK_SET);
678         return SWIG_TOKEN_CODEBLOCK;
679       } else {
680         state = 40;
681       }
682       break;
683
684     case 5:                     /* Maybe a double colon */
685
686       if ((c = nextchar(s)) == 0)
687         return SWIG_TOKEN_COLON;
688       if (c == ':')
689         state = 50;
690       else {
691         retract(s, 1);
692         return SWIG_TOKEN_COLON;
693       }
694       break;
695
696     case 50:                    /* DCOLON, DCOLONSTAR */
697       if ((c = nextchar(s)) == 0)
698         return SWIG_TOKEN_DCOLON;
699       else if (c == '*')
700         return SWIG_TOKEN_DCOLONSTAR;
701       else {
702         retract(s, 1);
703         return SWIG_TOKEN_DCOLON;
704       }
705       break;
706
707     case 60:                    /* shift operators */
708       if ((c = nextchar(s)) == 0)
709         return SWIG_TOKEN_LESSTHAN;
710       if (c == '<')
711         state = 240;
712       else if (c == '=')
713         return SWIG_TOKEN_LTEQUAL;
714       else {
715         retract(s, 1);
716         return SWIG_TOKEN_LESSTHAN;
717       }
718       break;
719     case 61:
720       if ((c = nextchar(s)) == 0)
721         return SWIG_TOKEN_GREATERTHAN;
722       if (c == '>')
723         state = 250;
724       else if (c == '=')
725         return SWIG_TOKEN_GTEQUAL;
726       else {
727         retract(s, 1);
728         return SWIG_TOKEN_GREATERTHAN;
729       }
730       break;
731     case 7:                     /* Identifier */
732       if ((c = nextchar(s)) == 0)
733         return SWIG_TOKEN_ID;
734       if (isalnum(c) || (c == '_') || (c == '$')) {
735         state = 7;
736       } else {
737         retract(s, 1);
738         return SWIG_TOKEN_ID;
739       }
740       break;
741
742     case 75:                    /* Special identifier $ */
743       if ((c = nextchar(s)) == 0)
744         return SWIG_TOKEN_DOLLAR;
745       if (isalnum(c) || (c == '_') || (c == '*') || (c == '&')) {
746         state = 7;
747       } else {
748         retract(s,1);
749         if (Len(s->text) == 1) return SWIG_TOKEN_DOLLAR;
750         return SWIG_TOKEN_ID;
751       }
752       break;
753
754     case 8:                     /* A numerical digit */
755       if ((c = nextchar(s)) == 0)
756         return SWIG_TOKEN_INT;
757       if (c == '.') {
758         state = 81;
759       } else if ((c == 'e') || (c == 'E')) {
760         state = 82;
761       } else if ((c == 'f') || (c == 'F')) {
762         Delitem(s->text, DOH_END);
763         return SWIG_TOKEN_FLOAT;
764       } else if (isdigit(c)) {
765         state = 8;
766       } else if ((c == 'l') || (c == 'L')) {
767         state = 87;
768       } else if ((c == 'u') || (c == 'U')) {
769         state = 88;
770       } else {
771         retract(s, 1);
772         return SWIG_TOKEN_INT;
773       }
774       break;
775     case 81:                    /* A floating pointer number of some sort */
776       if ((c = nextchar(s)) == 0)
777         return SWIG_TOKEN_DOUBLE;
778       if (isdigit(c))
779         state = 81;
780       else if ((c == 'e') || (c == 'E'))
781         state = 820;
782       else if ((c == 'f') || (c == 'F')) {
783         Delitem(s->text, DOH_END);
784         return SWIG_TOKEN_FLOAT;
785       } else if ((c == 'l') || (c == 'L')) {
786         Delitem(s->text, DOH_END);
787         return SWIG_TOKEN_DOUBLE;
788       } else {
789         retract(s, 1);
790         return (SWIG_TOKEN_DOUBLE);
791       }
792       break;
793     case 82:
794       if ((c = nextchar(s)) == 0) {
795         retract(s, 1);
796         return SWIG_TOKEN_INT;
797       }
798       if ((isdigit(c)) || (c == '-') || (c == '+'))
799         state = 86;
800       else {
801         retract(s, 2);
802         return (SWIG_TOKEN_INT);
803       }
804       break;
805     case 820:
806       /* Like case 82, but we've seen a decimal point. */
807       if ((c = nextchar(s)) == 0) {
808         retract(s, 1);
809         return SWIG_TOKEN_DOUBLE;
810       }
811       if ((isdigit(c)) || (c == '-') || (c == '+'))
812         state = 86;
813       else {
814         retract(s, 2);
815         return (SWIG_TOKEN_DOUBLE);
816       }
817       break;
818     case 83:
819       /* Might be a hexadecimal or octal number */
820       if ((c = nextchar(s)) == 0)
821         return SWIG_TOKEN_INT;
822       if (isdigit(c))
823         state = 84;
824       else if ((c == 'x') || (c == 'X'))
825         state = 85;
826       else if (c == '.')
827         state = 81;
828       else if ((c == 'l') || (c == 'L')) {
829         state = 87;
830       } else if ((c == 'u') || (c == 'U')) {
831         state = 88;
832       } else {
833         retract(s, 1);
834         return SWIG_TOKEN_INT;
835       }
836       break;
837     case 84:
838       /* This is an octal number */
839       if ((c = nextchar(s)) == 0)
840         return SWIG_TOKEN_INT;
841       if (isdigit(c))
842         state = 84;
843       else if ((c == 'l') || (c == 'L')) {
844         state = 87;
845       } else if ((c == 'u') || (c == 'U')) {
846         state = 88;
847       } else {
848         retract(s, 1);
849         return SWIG_TOKEN_INT;
850       }
851       break;
852     case 85:
853       /* This is an hex number */
854       if ((c = nextchar(s)) == 0)
855         return SWIG_TOKEN_INT;
856       if (isxdigit(c))
857         state = 85;
858       else if ((c == 'l') || (c == 'L')) {
859         state = 87;
860       } else if ((c == 'u') || (c == 'U')) {
861         state = 88;
862       } else {
863         retract(s, 1);
864         return SWIG_TOKEN_INT;
865       }
866       break;
867
868     case 86:
869       /* Rest of floating point number */
870
871       if ((c = nextchar(s)) == 0)
872         return SWIG_TOKEN_DOUBLE;
873       if (isdigit(c))
874         state = 86;
875       else if ((c == 'f') || (c == 'F')) {
876         Delitem(s->text, DOH_END);
877         return SWIG_TOKEN_FLOAT;
878       } else if ((c == 'l') || (c == 'L')) {
879         Delitem(s->text, DOH_END);
880         return SWIG_TOKEN_DOUBLE;
881       } else {
882         retract(s, 1);
883         return SWIG_TOKEN_DOUBLE;
884       }
885       break;
886
887     case 87:
888       /* A long integer of some sort */
889       if ((c = nextchar(s)) == 0)
890         return SWIG_TOKEN_LONG;
891       if ((c == 'u') || (c == 'U')) {
892         return SWIG_TOKEN_ULONG;
893       } else if ((c == 'l') || (c == 'L')) {
894         state = 870;
895       } else {
896         retract(s, 1);
897         return SWIG_TOKEN_LONG;
898       }
899       break;
900
901       /* A long long integer */
902
903     case 870:
904       if ((c = nextchar(s)) == 0)
905         return SWIG_TOKEN_LONGLONG;
906       if ((c == 'u') || (c == 'U')) {
907         return SWIG_TOKEN_ULONGLONG;
908       } else {
909         retract(s, 1);
910         return SWIG_TOKEN_LONGLONG;
911       }
912
913       /* An unsigned number */
914     case 88:
915
916       if ((c = nextchar(s)) == 0)
917         return SWIG_TOKEN_UINT;
918       if ((c == 'l') || (c == 'L')) {
919         state = 880;
920       } else {
921         retract(s, 1);
922         return SWIG_TOKEN_UINT;
923       }
924       break;
925
926       /* Possibly an unsigned long long or unsigned long */
927     case 880:
928       if ((c = nextchar(s)) == 0)
929         return SWIG_TOKEN_ULONG;
930       if ((c == 'l') || (c == 'L'))
931         return SWIG_TOKEN_ULONGLONG;
932       else {
933         retract(s, 1);
934         return SWIG_TOKEN_ULONG;
935       }
936
937       /* A character constant */
938     case 9:
939       if ((c = nextchar(s)) == 0) {
940         Swig_error(cparse_file, cparse_start_line, "Unterminated character constant\n");
941         return SWIG_TOKEN_ERROR;
942       }
943       if (c == '\'') {
944         Delitem(s->text, DOH_END);
945         return (SWIG_TOKEN_CHAR);
946       } else if (c == '\\') {
947         Delitem(s->text, DOH_END);
948         get_escape(s);
949       }
950       break;
951
952       /* A period or maybe a floating point number */
953
954     case 100:
955       if ((c = nextchar(s)) == 0)
956         return (0);
957       if (isdigit(c))
958         state = 81;
959       else {
960         retract(s, 1);
961         return SWIG_TOKEN_PERIOD;
962       }
963       break;
964
965     case 200:                   /* PLUS, PLUSPLUS, PLUSEQUAL */
966       if ((c = nextchar(s)) == 0)
967         return SWIG_TOKEN_PLUS;
968       else if (c == '+')
969         return SWIG_TOKEN_PLUSPLUS;
970       else if (c == '=')
971         return SWIG_TOKEN_PLUSEQUAL;
972       else {
973         retract(s, 1);
974         return SWIG_TOKEN_PLUS;
975       }
976       break;
977
978     case 210:                   /* MINUS, MINUSMINUS, MINUSEQUAL, ARROW */
979       if ((c = nextchar(s)) == 0)
980         return SWIG_TOKEN_MINUS;
981       else if (c == '-')
982         return SWIG_TOKEN_MINUSMINUS;
983       else if (c == '=')
984         return SWIG_TOKEN_MINUSEQUAL;
985       else if (c == '>')
986         state = 211;
987       else {
988         retract(s, 1);
989         return SWIG_TOKEN_MINUS;
990       }
991       break;
992
993     case 211:                   /* ARROW, ARROWSTAR */
994       if ((c = nextchar(s)) == 0)
995         return SWIG_TOKEN_ARROW;
996       else if (c == '*')
997         return SWIG_TOKEN_ARROWSTAR;
998       else {
999         retract(s, 1);
1000         return SWIG_TOKEN_ARROW;
1001       }
1002       break;
1003
1004
1005     case 220:                   /* STAR, TIMESEQUAL */
1006       if ((c = nextchar(s)) == 0)
1007         return SWIG_TOKEN_STAR;
1008       else if (c == '=')
1009         return SWIG_TOKEN_TIMESEQUAL;
1010       else {
1011         retract(s, 1);
1012         return SWIG_TOKEN_STAR;
1013       }
1014       break;
1015
1016     case 230:                   /* XOR, XOREQUAL */
1017       if ((c = nextchar(s)) == 0)
1018         return SWIG_TOKEN_XOR;
1019       else if (c == '=')
1020         return SWIG_TOKEN_XOREQUAL;
1021       else {
1022         retract(s, 1);
1023         return SWIG_TOKEN_XOR;
1024       }
1025       break;
1026
1027     case 240:                   /* LSHIFT, LSEQUAL */
1028       if ((c = nextchar(s)) == 0)
1029         return SWIG_TOKEN_LSHIFT;
1030       else if (c == '=')
1031         return SWIG_TOKEN_LSEQUAL;
1032       else {
1033         retract(s, 1);
1034         return SWIG_TOKEN_LSHIFT;
1035       }
1036       break;
1037
1038     case 250:                   /* RSHIFT, RSEQUAL */
1039       if ((c = nextchar(s)) == 0)
1040         return SWIG_TOKEN_RSHIFT;
1041       else if (c == '=')
1042         return SWIG_TOKEN_RSEQUAL;
1043       else {
1044         retract(s, 1);
1045         return SWIG_TOKEN_RSHIFT;
1046       }
1047       break;
1048
1049
1050       /* An illegal character */
1051
1052       /* Reverse string */
1053     case 900:
1054       if ((c = nextchar(s)) == 0) {
1055         Swig_error(cparse_file, cparse_start_line, "Unterminated character constant\n");
1056         return SWIG_TOKEN_ERROR;
1057       }
1058       if (c == '`') {
1059         Delitem(s->text, DOH_END);
1060         return (SWIG_TOKEN_RSTRING);
1061       }
1062       break;
1063
1064     default:
1065       return SWIG_TOKEN_ILLEGAL;
1066     }
1067   }
1068 }
1069
1070 /* -----------------------------------------------------------------------------
1071  * Scanner_token()
1072  *
1073  * Real entry point to return the next token. Returns 0 if at end of input.
1074  * ----------------------------------------------------------------------------- */
1075
1076 int Scanner_token(Scanner * s) {
1077   int t;
1078   Delete(s->error);
1079   if (s->nexttoken >= 0) {
1080     t = s->nexttoken;
1081     s->nexttoken = -1;
1082     return t;
1083   }
1084   s->start_line = 0;
1085   t = look(s);
1086   if (!s->start_line) {
1087     Setline(s->text,s->line);
1088   } else {
1089     Setline(s->text,s->start_line);
1090   }
1091   return t;
1092 }
1093
1094 /* -----------------------------------------------------------------------------
1095  * Scanner_text()
1096  *
1097  * Return the lexene associated with the last returned token.
1098  * ----------------------------------------------------------------------------- */
1099
1100 String *Scanner_text(Scanner * s) {
1101   return s->text;
1102 }
1103
1104 /* -----------------------------------------------------------------------------
1105  * Scanner_skip_line()
1106  *
1107  * Skips to the end of a line
1108  * ----------------------------------------------------------------------------- */
1109
1110 void Scanner_skip_line(Scanner * s) {
1111   char c;
1112   int done = 0;
1113   Clear(s->text);
1114   Setfile(s->text, Getfile(s->str));
1115   Setline(s->text, s->line);
1116   while (!done) {
1117     if ((c = nextchar(s)) == 0)
1118       return;
1119     if (c == '\\') {
1120       c = nextchar(s);
1121     } else if (c == '\n') {
1122       done = 1;
1123     }
1124   }
1125   return;
1126 }
1127
1128 /* -----------------------------------------------------------------------------
1129  * Scanner_skip_balanced()
1130  *
1131  * Skips a piece of code enclosed in begin/end symbols such as '{...}' or
1132  * (...).  Ignores symbols inside comments or strings.
1133  * ----------------------------------------------------------------------------- */
1134
1135 int Scanner_skip_balanced(Scanner * s, int startchar, int endchar) {
1136   char c;
1137   int num_levels = 1;
1138   int l;
1139   int state = 0;
1140   char temp[2] = { 0, 0 };
1141   l = s->line;
1142   temp[0] = (char) startchar;
1143   Clear(s->text);
1144   Setfile(s->text, Getfile(s->str));
1145   Setline(s->text, s->line);
1146
1147   Append(s->text, temp);
1148   while (num_levels > 0) {
1149     if ((c = nextchar(s)) == 0) {
1150       return -1;
1151     }
1152     switch (state) {
1153     case 0:
1154       if (c == startchar)
1155         num_levels++;
1156       else if (c == endchar)
1157         num_levels--;
1158       else if (c == '/')
1159         state = 10;
1160       else if (c == '\"')
1161         state = 20;
1162       else if (c == '\'')
1163         state = 30;
1164       break;
1165     case 10:
1166       if (c == '/')
1167         state = 11;
1168       else if (c == '*')
1169         state = 12;
1170       else
1171         state = 0;
1172       break;
1173     case 11:
1174       if (c == '\n')
1175         state = 0;
1176       else
1177         state = 11;
1178       break;
1179     case 12:
1180       if (c == '*')
1181         state = 13;
1182       break;
1183     case 13:
1184       if (c == '*')
1185         state = 13;
1186       else if (c == '/')
1187         state = 0;
1188       else
1189         state = 12;
1190       break;
1191     case 20:
1192       if (c == '\"')
1193         state = 0;
1194       else if (c == '\\')
1195         state = 21;
1196       break;
1197     case 21:
1198       state = 20;
1199       break;
1200     case 30:
1201       if (c == '\'')
1202         state = 0;
1203       else if (c == '\\')
1204         state = 31;
1205       break;
1206     case 31:
1207       state = 30;
1208       break;
1209     default:
1210       break;
1211     }
1212   }
1213   return 0;
1214 }
1215
1216 /* -----------------------------------------------------------------------------
1217  * Scanner_isoperator()
1218  *
1219  * Returns 0 or 1 depending on whether or not a token corresponds to a C/C++
1220  * operator.
1221  * ----------------------------------------------------------------------------- */
1222
1223 int
1224 Scanner_isoperator(int tokval) {
1225   if (tokval >= 100) return 1;
1226   return 0;
1227 }