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
13char cvsroot_scanner_c[] = "$Id: scanner.c 11470 2009-07-29 20:50:39Z wsfulton $";
14
15#include "swig.h"
16#include <ctype.h>
17
18extern String *cparse_file;
19extern int     cparse_start_line;
20
21struct 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
42Scanner *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
65void 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
82void 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
103void 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
122void 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
138void 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
150String *Scanner_file(Scanner * s) {
151  return Getfile(s->str);
152}
153
154/* -----------------------------------------------------------------------------
155 * Scanner_line()
156 *
157 * Get the current line number
158 * ----------------------------------------------------------------------------- */
159int 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 * ----------------------------------------------------------------------------- */
168int 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
178void 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 * ----------------------------------------------------------------------------- */
188static 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
216static 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
228String *
229Scanner_errmsg(Scanner *s) {
230  return s->error;
231}
232
233int
234Scanner_errline(Scanner *s) {
235  return s->error_line;
236}
237
238/* -----------------------------------------------------------------------------
239 * Scanner_freeze_line()
240 *
241 * Freezes the current line number.
242 * ----------------------------------------------------------------------------- */
243
244void
245Scanner_freeze_line(Scanner *s, int val) {
246  s->freeze_line = val;
247}
248
249/* -----------------------------------------------------------------------------
250 * retract()
251 *
252 * Retract n characters
253 * ----------------------------------------------------------------------------- */
254static 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
276static 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
395static 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
1076int 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
1100String *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
1110void 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
1135int 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
1223int
1224Scanner_isoperator(int tokval) {
1225  if (tokval >= 100) return 1;
1226  return 0;
1227}
1228