1 /* -----------------------------------------------------------------------------
2  * This file is part of SWIG, which is licensed as a whole under version 3
3  * (or any later version) of the GNU General Public License. Some additional
4  * terms also apply to certain portions of SWIG. The full details of the SWIG
5  * license and copyrights can be found in the LICENSE and COPYRIGHT files
6  * included with the SWIG source code as distributed by the SWIG developers
7  * and at http://www.swig.org/legal.html.
8  *
9  * scanner.c
10  *
11  * This file implements a general purpose C/C++ compatible lexical scanner.
12  * This scanner isn't intended to be plugged directly into a parser built
13  * with yacc. Rather, it contains a lot of generic code that could be used
14  * to easily construct yacc-compatible scanners.
15  * ----------------------------------------------------------------------------- */
16 
17 #include "swig.h"
18 #include <ctype.h>
19 
20 extern String *cparse_file;
21 extern int cparse_line;
22 extern int cparse_cplusplus;
23 extern int cparse_start_line;
24 
25 struct Scanner {
26   String *text;			/* Current token value */
27   List   *scanobjs;		/* Objects being scanned */
28   String *str;			/* Current object being scanned */
29   char   *idstart;		/* Optional identifier start characters */
30   int     nexttoken;		/* Next token to be returned */
31   int     start_line;		/* Starting line of certain declarations */
32   int     line;
33   int     yylen;	        /* Length of text pushed into text */
34   String *file;
35   String *error;                /* Last error message (if any) */
36   int     error_line;           /* Error line number */
37   int     freeze_line;          /* Suspend line number updates */
38   List   *brackets;             /* Current level of < > brackets on each level */
39 };
40 
41 typedef struct Locator {
42   String         *filename;
43   int             line_number;
44   struct Locator *next;
45 } Locator;
46 static int follow_locators = 0;
47 
48 static void brackets_push(Scanner *);
49 static void brackets_clear(Scanner *);
50 
51 /* -----------------------------------------------------------------------------
52  * NewScanner()
53  *
54  * Create a new scanner object
55  * ----------------------------------------------------------------------------- */
56 
NewScanner(void)57 Scanner *NewScanner(void) {
58   Scanner *s;
59   s = (Scanner *) malloc(sizeof(Scanner));
60   s->line = 1;
61   s->file = 0;
62   s->nexttoken = -1;
63   s->start_line = 1;
64   s->yylen = 0;
65   s->idstart = NULL;
66   s->scanobjs = NewList();
67   s->text = NewStringEmpty();
68   s->str = 0;
69   s->error = 0;
70   s->error_line = 0;
71   s->freeze_line = 0;
72   s->brackets = NewList();
73   brackets_push(s);
74   return s;
75 }
76 
77 /* -----------------------------------------------------------------------------
78  * DelScanner()
79  *
80  * Delete a scanner object.
81  * ----------------------------------------------------------------------------- */
82 
DelScanner(Scanner * s)83 void DelScanner(Scanner *s) {
84   assert(s);
85   Delete(s->scanobjs);
86   Delete(s->brackets);
87   Delete(s->text);
88   Delete(s->file);
89   Delete(s->error);
90   Delete(s->str);
91   free(s->idstart);
92   free(s);
93 }
94 
95 /* -----------------------------------------------------------------------------
96  * Scanner_clear()
97  *
98  * Clear the contents of a scanner object.
99  * ----------------------------------------------------------------------------- */
100 
Scanner_clear(Scanner * s)101 void Scanner_clear(Scanner *s) {
102   assert(s);
103   Delete(s->str);
104   Clear(s->text);
105   Clear(s->scanobjs);
106   brackets_clear(s);
107   Delete(s->error);
108   s->str = 0;
109   s->error = 0;
110   s->line = 1;
111   s->nexttoken = -1;
112   s->start_line = 0;
113   s->yylen = 0;
114   /* Should these be cleared too?
115   s->idstart;
116   s->file;
117   s->error_line;
118   s->freeze_line;
119   */
120 }
121 
122 /* -----------------------------------------------------------------------------
123  * Scanner_push()
124  *
125  * Push some new text into the scanner.  The scanner will start parsing this text
126  * immediately before returning to the old text.
127  * ----------------------------------------------------------------------------- */
128 
Scanner_push(Scanner * s,String * txt)129 void Scanner_push(Scanner *s, String *txt) {
130   assert(s && txt);
131   Push(s->scanobjs, txt);
132   if (s->str) {
133     Setline(s->str,s->line);
134     Delete(s->str);
135   }
136   s->str = txt;
137   DohIncref(s->str);
138   s->line = Getline(txt);
139 }
140 
141 /* -----------------------------------------------------------------------------
142  * Scanner_pushtoken()
143  *
144  * Push a token into the scanner.  This token will be returned on the next
145  * call to Scanner_token().
146  * ----------------------------------------------------------------------------- */
147 
Scanner_pushtoken(Scanner * s,int nt,const_String_or_char_ptr val)148 void Scanner_pushtoken(Scanner *s, int nt, const_String_or_char_ptr val) {
149   assert(s);
150   assert((nt >= 0) && (nt < SWIG_MAXTOKENS));
151   s->nexttoken = nt;
152   if ( Char(val) != Char(s->text) ) {
153     Clear(s->text);
154     Append(s->text,val);
155   }
156 }
157 
158 /* -----------------------------------------------------------------------------
159  * Scanner_set_location()
160  *
161  * Set the file and line number location of the scanner.
162  * ----------------------------------------------------------------------------- */
163 
Scanner_set_location(Scanner * s,String * file,int line)164 void Scanner_set_location(Scanner *s, String *file, int line) {
165   Setline(s->str, line);
166   Setfile(s->str, file);
167   s->line = line;
168 }
169 
170 /* -----------------------------------------------------------------------------
171  * Scanner_file()
172  *
173  * Get the current file.
174  * ----------------------------------------------------------------------------- */
175 
Scanner_file(Scanner * s)176 String *Scanner_file(Scanner *s) {
177   return Getfile(s->str);
178 }
179 
180 /* -----------------------------------------------------------------------------
181  * Scanner_line()
182  *
183  * Get the current line number
184  * ----------------------------------------------------------------------------- */
Scanner_line(Scanner * s)185 int Scanner_line(Scanner *s) {
186   return s->line;
187 }
188 
189 /* -----------------------------------------------------------------------------
190  * Scanner_start_line()
191  *
192  * Get the line number on which the current token starts
193  * ----------------------------------------------------------------------------- */
Scanner_start_line(Scanner * s)194 int Scanner_start_line(Scanner *s) {
195   return s->start_line;
196 }
197 
198 /* -----------------------------------------------------------------------------
199  * Scanner_idstart()
200  *
201  * Change the set of additional characters that can be used to start an identifier.
202  * ----------------------------------------------------------------------------- */
203 
Scanner_idstart(Scanner * s,const char * id)204 void Scanner_idstart(Scanner *s, const char *id) {
205   free(s->idstart);
206   s->idstart = Swig_copy_string(id);
207 }
208 
209 /* -----------------------------------------------------------------------------
210  * nextchar()
211  *
212  * Returns the next character from the scanner or 0 if end of the string.
213  * ----------------------------------------------------------------------------- */
nextchar(Scanner * s)214 static char nextchar(Scanner *s) {
215   int nc;
216   if (!s->str)
217     return 0;
218   while ((nc = Getc(s->str)) == EOF) {
219     Delete(s->str);
220     s->str = 0;
221     Delitem(s->scanobjs, 0);
222     if (Len(s->scanobjs) == 0)
223       return 0;
224     s->str = Getitem(s->scanobjs, 0);
225     s->line = Getline(s->str);
226     DohIncref(s->str);
227   }
228   if ((nc == '\n') && (!s->freeze_line))
229     s->line++;
230   Putc(nc,s->text);
231   return (char)nc;
232 }
233 
234 /* -----------------------------------------------------------------------------
235  * set_error()
236  *
237  * Sets error information on the scanner.
238  * ----------------------------------------------------------------------------- */
239 
set_error(Scanner * s,int line,const_String_or_char_ptr msg)240 static void set_error(Scanner *s, int line, const_String_or_char_ptr msg) {
241   s->error_line = line;
242   s->error = NewString(msg);
243 }
244 
245 /* -----------------------------------------------------------------------------
246  * Scanner_errmsg()
247  * Scanner_errline()
248  *
249  * Returns error information (if any)
250  * ----------------------------------------------------------------------------- */
251 
Scanner_errmsg(Scanner * s)252 String *Scanner_errmsg(Scanner *s) {
253   return s->error;
254 }
255 
Scanner_errline(Scanner * s)256 int Scanner_errline(Scanner *s) {
257   return s->error_line;
258 }
259 
260 /* -----------------------------------------------------------------------------
261  * freeze_line()
262  *
263  * Freezes the current line number.
264  * ----------------------------------------------------------------------------- */
265 
freeze_line(Scanner * s,int val)266 static void freeze_line(Scanner *s, int val) {
267   s->freeze_line = val;
268 }
269 
270 /* -----------------------------------------------------------------------------
271  * brackets_count()
272  *
273  * Returns the number of brackets at the current depth.
274  * A syntax error with unbalanced ) brackets will result in a NULL pointer return.
275  * ----------------------------------------------------------------------------- */
brackets_count(Scanner * s)276 static int *brackets_count(Scanner *s) {
277   int *count;
278   if (Len(s->brackets) > 0)
279     count = (int *)Data(Getitem(s->brackets, 0));
280   else
281     count = 0;
282   return count;
283 }
284 
285 /* -----------------------------------------------------------------------------
286  * brackets_clear()
287  *
288  * Resets the current depth and clears all brackets.
289  * Usually called at the end of statements;
290  * ----------------------------------------------------------------------------- */
brackets_clear(Scanner * s)291 static void brackets_clear(Scanner *s) {
292   Clear(s->brackets);
293   brackets_push(s); /* base bracket count should always be created */
294 }
295 
296 /* -----------------------------------------------------------------------------
297  * brackets_increment()
298  *
299  * Increases the number of brackets at the current depth.
300  * Usually called when a single '<' is found.
301  * ----------------------------------------------------------------------------- */
brackets_increment(Scanner * s)302 static void brackets_increment(Scanner *s) {
303   int *count = brackets_count(s);
304   if (count)
305     (*count)++;
306 }
307 
308 /* -----------------------------------------------------------------------------
309  * brackets_decrement()
310  *
311  * Decreases the number of brackets at the current depth.
312  * Usually called when a single '>' is found.
313  * ----------------------------------------------------------------------------- */
brackets_decrement(Scanner * s)314 static void brackets_decrement(Scanner *s) {
315   int *count = brackets_count(s);
316   if (count)
317     (*count)--;
318 }
319 
320 /* -----------------------------------------------------------------------------
321  * brackets_reset()
322  *
323  * Sets the number of '<' brackets back to zero. Called at the point where
324  * it is no longer possible to have a matching closing >> pair for a template.
325  * ----------------------------------------------------------------------------- */
brackets_reset(Scanner * s)326 static void brackets_reset(Scanner *s) {
327   int *count = brackets_count(s);
328   if (count)
329     *count = 0;
330 }
331 
332 /* -----------------------------------------------------------------------------
333  * brackets_push()
334  *
335  * Increases the depth of brackets.
336  * Usually called when '(' is found.
337  * ----------------------------------------------------------------------------- */
brackets_push(Scanner * s)338 static void brackets_push(Scanner *s) {
339   int *newInt = (int *)malloc(sizeof(int));
340   *newInt = 0;
341   Push(s->brackets, NewVoid(newInt, free));
342 }
343 
344 /* -----------------------------------------------------------------------------
345  * brackets_pop()
346  *
347  * Decreases the depth of brackets.
348  * Usually called when ')' is found.
349  * ----------------------------------------------------------------------------- */
brackets_pop(Scanner * s)350 static void brackets_pop(Scanner *s) {
351   if (Len(s->brackets) > 0) /* protect against unbalanced ')' brackets */
352     Delitem(s->brackets, 0);
353 }
354 
355 /* -----------------------------------------------------------------------------
356  * brackets_allow_shift()
357  *
358  * Return 1 to allow shift (>>), or 0 if (>>) should be split into (> >).
359  * This is for C++11 template syntax for closing templates.
360  * ----------------------------------------------------------------------------- */
brackets_allow_shift(Scanner * s)361 static int brackets_allow_shift(Scanner *s) {
362   int *count = brackets_count(s);
363   return !count || (*count <= 0);
364 }
365 
366 /* -----------------------------------------------------------------------------
367  * retract()
368  *
369  * Retract n characters
370  * ----------------------------------------------------------------------------- */
retract(Scanner * s,int n)371 static void retract(Scanner *s, int n) {
372   int i, l;
373   char *str;
374 
375   str = Char(s->text);
376   l = Len(s->text);
377   assert(n <= l);
378   for (i = 0; i < n; i++) {
379     if (str[l - 1] == '\n') {
380       if (!s->freeze_line) s->line--;
381     }
382     (void)Seek(s->str, -1, SEEK_CUR);
383     Delitem(s->text, DOH_END);
384   }
385 }
386 
387 /* -----------------------------------------------------------------------------
388  * get_escape()
389  *
390  * Get escape sequence.  Called when a backslash is found in a string
391  * ----------------------------------------------------------------------------- */
392 
get_escape(Scanner * s)393 static void get_escape(Scanner *s) {
394   int result = 0;
395   int state = 0;
396   int c;
397 
398   while (1) {
399     c = nextchar(s);
400     if (c == 0)
401       break;
402     switch (state) {
403     case 0:
404       if (c == 'n') {
405 	Delitem(s->text, DOH_END);
406 	Append(s->text,"\n");
407 	return;
408       }
409       if (c == 'r') {
410 	Delitem(s->text, DOH_END);
411 	Append(s->text,"\r");
412 	return;
413       }
414       if (c == 't') {
415 	Delitem(s->text, DOH_END);
416 	Append(s->text,"\t");
417 	return;
418       }
419       if (c == 'a') {
420 	Delitem(s->text, DOH_END);
421 	Append(s->text,"\a");
422 	return;
423       }
424       if (c == 'b') {
425 	Delitem(s->text, DOH_END);
426 	Append(s->text,"\b");
427 	return;
428       }
429       if (c == 'f') {
430 	Delitem(s->text, DOH_END);
431 	Append(s->text,"\f");
432 	return;
433       }
434       if (c == '\\') {
435 	Delitem(s->text, DOH_END);
436 	Append(s->text,"\\");
437 	return;
438       }
439       if (c == 'v') {
440 	Delitem(s->text, DOH_END);
441 	Append(s->text,"\v");
442 	return;
443       }
444       if (c == 'e') {
445 	Delitem(s->text, DOH_END);
446 	Append(s->text,"\033");
447 	return;
448       }
449       if (c == '\'') {
450 	Delitem(s->text, DOH_END);
451 	Append(s->text,"\'");
452 	return;
453       }
454       if (c == '\"') {
455 	Delitem(s->text, DOH_END);
456 	Append(s->text,"\"");
457 	return;
458       }
459       if (c == '\n') {
460 	Delitem(s->text, DOH_END);
461 	return;
462       }
463       if (isdigit(c)) {
464 	state = 10;
465 	result = (c - '0');
466 	Delitem(s->text, DOH_END);
467       } else if (c == 'x') {
468 	state = 20;
469 	Delitem(s->text, DOH_END);
470       } else {
471 	char tmp[3];
472 	tmp[0] = '\\';
473 	tmp[1] = (char)c;
474 	tmp[2] = 0;
475 	Delitem(s->text, DOH_END);
476 	Append(s->text, tmp);
477 	return;
478       }
479       break;
480     case 10:
481       if (!isdigit(c)) {
482 	retract(s,1);
483 	Putc((char)result,s->text);
484 	return;
485       }
486       result = (result << 3) + (c - '0');
487       Delitem(s->text, DOH_END);
488       break;
489     case 20:
490       if (!isxdigit(c)) {
491 	retract(s,1);
492 	Putc((char)result, s->text);
493 	return;
494       }
495       if (isdigit(c))
496 	result = (result << 4) + (c - '0');
497       else
498 	result = (result << 4) + (10 + tolower(c) - 'a');
499       Delitem(s->text, DOH_END);
500       break;
501     }
502   }
503   return;
504 }
505 
506 /* -----------------------------------------------------------------------------
507  * look()
508  *
509  * Return the raw value of the next token.
510  * ----------------------------------------------------------------------------- */
511 
look(Scanner * s)512 static int look(Scanner *s) {
513   int state = 0;
514   int c = 0;
515   String *str_delimiter = 0;
516 
517   Clear(s->text);
518   s->start_line = s->line;
519   Setfile(s->text, Getfile(s->str));
520 
521 
522   while (1) {
523     switch (state) {
524     case 0:
525       if ((c = nextchar(s)) == 0)
526 	return (0);
527 
528       /* Process delimiters */
529 
530       if (c == '\n') {
531 	return SWIG_TOKEN_ENDLINE;
532       } else if (!isspace(c)) {
533 	retract(s, 1);
534 	state = 1000;
535 	Clear(s->text);
536 	Setline(s->text, s->line);
537 	Setfile(s->text, Getfile(s->str));
538       }
539       break;
540 
541     case 1000:
542       if ((c = nextchar(s)) == 0)
543         return (0);
544       if (c == '%')
545 	state = 4;		/* Possibly a SWIG directive */
546 
547       /* Look for possible identifiers or unicode/delimiter strings */
548       else if ((isalpha(c)) || (c == '_') ||
549 	       (s->idstart && strchr(s->idstart, c))) {
550 	state = 7;
551       }
552 
553       /* Look for single character symbols */
554 
555       else if (c == '(') {
556         brackets_push(s);
557 	return SWIG_TOKEN_LPAREN;
558       }
559       else if (c == ')') {
560         brackets_pop(s);
561 	return SWIG_TOKEN_RPAREN;
562       }
563       else if (c == ';') {
564         brackets_clear(s);
565 	return SWIG_TOKEN_SEMI;
566       }
567       else if (c == ',')
568 	return SWIG_TOKEN_COMMA;
569       else if (c == '*')
570 	state = 220;
571       else if (c == '}')
572 	return SWIG_TOKEN_RBRACE;
573       else if (c == '{') {
574         brackets_reset(s);
575 	return SWIG_TOKEN_LBRACE;
576       }
577       else if (c == '=')
578 	state = 33;
579       else if (c == '+')
580 	state = 200;
581       else if (c == '-')
582 	state = 210;
583       else if (c == '&')
584 	state = 31;
585       else if (c == '|')
586 	state = 32;
587       else if (c == '^')
588 	state = 230;
589       else if (c == '<')
590 	state = 60;
591       else if (c == '>')
592 	state = 61;
593       else if (c == '~')
594 	return SWIG_TOKEN_NOT;
595       else if (c == '!')
596 	state = 3;
597       else if (c == '\\')
598 	return SWIG_TOKEN_BACKSLASH;
599       else if (c == '[')
600 	return SWIG_TOKEN_LBRACKET;
601       else if (c == ']')
602 	return SWIG_TOKEN_RBRACKET;
603       else if (c == '@')
604 	return SWIG_TOKEN_AT;
605       else if (c == '$')
606 	state = 75;
607       else if (c == '#')
608 	return SWIG_TOKEN_POUND;
609       else if (c == '?')
610 	return SWIG_TOKEN_QUESTION;
611 
612       /* Look for multi-character sequences */
613 
614       else if (c == '/') {
615 	state = 1;		/* Comment (maybe)  */
616 	s->start_line = s->line;
617       }
618 
619       else if (c == ':')
620 	state = 5;		/* maybe double colon */
621       else if (c == '0')
622 	state = 83;		/* An octal or hex value */
623       else if (c == '\"') {
624 	state = 2;              /* A string constant */
625 	s->start_line = s->line;
626 	Clear(s->text);
627       }
628       else if (c == '\'') {
629 	s->start_line = s->line;
630 	Clear(s->text);
631 	state = 9;		/* A character constant */
632       } else if (c == '`') {
633 	s->start_line = s->line;
634 	Clear(s->text);
635 	state = 900;
636       }
637 
638       else if (c == '.')
639 	state = 100;		/* Maybe a number, maybe just a period */
640       else if (isdigit(c))
641 	state = 8;		/* A numerical value */
642       else
643 	state = 99;		/* An error */
644       break;
645 
646     case 1:			/*  Comment block */
647       if ((c = nextchar(s)) == 0)
648 	return (0);
649       if (c == '/') {
650 	state = 10;		/* C++ style comment */
651 	Clear(s->text);
652 	Setline(s->text, Getline(s->str));
653 	Setfile(s->text, Getfile(s->str));
654 	Append(s->text, "//");
655       } else if (c == '*') {
656 	state = 11;		/* C style comment */
657 	Clear(s->text);
658 	Setline(s->text, Getline(s->str));
659 	Setfile(s->text, Getfile(s->str));
660 	Append(s->text, "/*");
661       } else if (c == '=') {
662 	return SWIG_TOKEN_DIVEQUAL;
663       } else {
664 	retract(s, 1);
665 	return SWIG_TOKEN_SLASH;
666       }
667       break;
668     case 10:			/* C++ style comment */
669       if ((c = nextchar(s)) == 0) {
670 	Swig_error(cparse_file, cparse_start_line, "Unterminated comment\n");
671 	return SWIG_TOKEN_ERROR;
672       }
673       if (c == '\n') {
674 	retract(s,1);
675 	return SWIG_TOKEN_COMMENT;
676       } else {
677 	state = 10;
678       }
679       break;
680     case 11:			/* C style comment block */
681       if ((c = nextchar(s)) == 0) {
682 	Swig_error(cparse_file, cparse_start_line, "Unterminated comment\n");
683 	return SWIG_TOKEN_ERROR;
684       }
685       if (c == '*') {
686 	state = 12;
687       } else {
688 	state = 11;
689       }
690       break;
691     case 12:			/* Still in C style comment */
692       if ((c = nextchar(s)) == 0) {
693 	Swig_error(cparse_file, cparse_start_line, "Unterminated comment\n");
694 	return SWIG_TOKEN_ERROR;
695       }
696       if (c == '*') {
697 	state = 12;
698       } else if (c == '/') {
699 	return SWIG_TOKEN_COMMENT;
700       } else {
701 	state = 11;
702       }
703       break;
704 
705     case 2:			/* Processing a string */
706       if (!str_delimiter) {
707 	state=20;
708 	break;
709       }
710 
711       if ((c = nextchar(s)) == 0) {
712 	Swig_error(cparse_file, cparse_start_line, "Unterminated string\n");
713 	return SWIG_TOKEN_ERROR;
714       }
715       else if (c == '(') {
716 	state = 20;
717       }
718       else {
719 	char temp[2] = { 0, 0 };
720 	temp[0] = c;
721 	Append( str_delimiter, temp );
722       }
723 
724       break;
725 
726     case 20:			/* Inside the string */
727       if ((c = nextchar(s)) == 0) {
728 	Swig_error(cparse_file, cparse_start_line, "Unterminated string\n");
729 	return SWIG_TOKEN_ERROR;
730       }
731 
732       if (!str_delimiter) { /* Ordinary string: "value" */
733 	if (c == '\"') {
734 	  Delitem(s->text, DOH_END);
735 	  return SWIG_TOKEN_STRING;
736 	} else if (c == '\\') {
737 	  Delitem(s->text, DOH_END);
738 	  get_escape(s);
739 	}
740       } else {             /* Custom delimiter string: R"XXXX(value)XXXX" */
741 	if (c==')') {
742 	  int i=0;
743 	  String *end_delimiter = NewStringEmpty();
744 	  while ((c = nextchar(s)) != 0 && c!='\"') {
745 	    char temp[2] = { 0, 0 };
746 	    temp[0] = c;
747 	    Append( end_delimiter, temp );
748 	    i++;
749 	  }
750 
751 	  if (Strcmp( str_delimiter, end_delimiter )==0) {
752 	    int len = Len(s->text);
753 	    Delslice(s->text, len - 2 - Len(str_delimiter), len); /* Delete ending )XXXX" */
754 	    Delslice(s->text, 0, Len(str_delimiter) + 1); /* Delete starting XXXX( */
755 	    Delete( end_delimiter ); /* Correct end delimiter )XXXX" occurred */
756 	    Delete( str_delimiter );
757 	    str_delimiter = 0;
758 	    return SWIG_TOKEN_STRING;
759 	  } else {                   /* Incorrect end delimiter occurred */
760 	    if (c == 0) {
761 	      Swig_error(cparse_file, cparse_start_line, "Unterminated raw string, started with R\"%s( is not terminated by )%s\"\n", str_delimiter, str_delimiter);
762 	      return SWIG_TOKEN_ERROR;
763 	    }
764 	    retract( s, i );
765 	    Delete( end_delimiter );
766 	  }
767 	}
768       }
769 
770       break;
771 
772     case 3:			/* Maybe a not equals */
773       if ((c = nextchar(s)) == 0)
774 	return SWIG_TOKEN_LNOT;
775       else if (c == '=')
776 	return SWIG_TOKEN_NOTEQUAL;
777       else {
778 	retract(s, 1);
779 	return SWIG_TOKEN_LNOT;
780       }
781       break;
782 
783     case 31:			/* AND or Logical AND or ANDEQUAL */
784       if ((c = nextchar(s)) == 0)
785 	return SWIG_TOKEN_AND;
786       else if (c == '&')
787 	return SWIG_TOKEN_LAND;
788       else if (c == '=')
789 	return SWIG_TOKEN_ANDEQUAL;
790       else {
791 	retract(s, 1);
792 	return SWIG_TOKEN_AND;
793       }
794       break;
795 
796     case 32:			/* OR or Logical OR */
797       if ((c = nextchar(s)) == 0)
798 	return SWIG_TOKEN_OR;
799       else if (c == '|')
800 	return SWIG_TOKEN_LOR;
801       else if (c == '=')
802 	return SWIG_TOKEN_OREQUAL;
803       else {
804 	retract(s, 1);
805 	return SWIG_TOKEN_OR;
806       }
807       break;
808 
809     case 33:			/* EQUAL or EQUALTO */
810       if ((c = nextchar(s)) == 0)
811 	return SWIG_TOKEN_EQUAL;
812       else if (c == '=')
813 	return SWIG_TOKEN_EQUALTO;
814       else {
815 	retract(s, 1);
816 	return SWIG_TOKEN_EQUAL;
817       }
818       break;
819 
820     case 4:			/* A wrapper generator directive (maybe) */
821       if ((c = nextchar(s)) == 0)
822 	return SWIG_TOKEN_PERCENT;
823       if (c == '{') {
824 	state = 40;		/* Include block */
825 	Clear(s->text);
826 	Setline(s->text, Getline(s->str));
827 	Setfile(s->text, Getfile(s->str));
828 	s->start_line = s->line;
829       } else if (s->idstart && strchr(s->idstart, '%') &&
830 	         ((isalpha(c)) || (c == '_'))) {
831 	state = 7;
832       } else if (c == '=') {
833 	return SWIG_TOKEN_MODEQUAL;
834       } else if (c == '}') {
835 	Swig_error(cparse_file, cparse_line, "Syntax error. Extraneous '%%}'\n");
836 	SWIG_exit(EXIT_FAILURE);
837       } else {
838 	retract(s, 1);
839 	return SWIG_TOKEN_PERCENT;
840       }
841       break;
842 
843     case 40:			/* Process an include block */
844       if ((c = nextchar(s)) == 0) {
845 	Swig_error(cparse_file, cparse_start_line, "Unterminated block\n");
846 	return SWIG_TOKEN_ERROR;
847       }
848       if (c == '%')
849 	state = 41;
850       break;
851     case 41:			/* Still processing include block */
852       if ((c = nextchar(s)) == 0) {
853 	set_error(s,s->start_line,"Unterminated code block");
854 	return 0;
855       }
856       if (c == '}') {
857 	Delitem(s->text, DOH_END);
858 	Delitem(s->text, DOH_END);
859 	Seek(s->text,0,SEEK_SET);
860 	return SWIG_TOKEN_CODEBLOCK;
861       } else {
862 	state = 40;
863       }
864       break;
865 
866     case 5:			/* Maybe a double colon */
867 
868       if ((c = nextchar(s)) == 0)
869 	return SWIG_TOKEN_COLON;
870       if (c == ':')
871 	state = 50;
872       else {
873 	retract(s, 1);
874 	return SWIG_TOKEN_COLON;
875       }
876       break;
877 
878     case 50:			/* DCOLON, DCOLONSTAR */
879       if ((c = nextchar(s)) == 0)
880 	return SWIG_TOKEN_DCOLON;
881       else if (c == '*')
882 	return SWIG_TOKEN_DCOLONSTAR;
883       else {
884 	retract(s, 1);
885 	return SWIG_TOKEN_DCOLON;
886       }
887       break;
888 
889     case 60:			/* shift operators */
890       if ((c = nextchar(s)) == 0) {
891 	brackets_increment(s);
892 	return SWIG_TOKEN_LESSTHAN;
893       }
894       if (c == '<')
895 	state = 240;
896       else if (c == '=')
897 	return SWIG_TOKEN_LTEQUAL;
898       else {
899 	retract(s, 1);
900 	brackets_increment(s);
901 	return SWIG_TOKEN_LESSTHAN;
902       }
903       break;
904     case 61:
905       if ((c = nextchar(s)) == 0) {
906         brackets_decrement(s);
907 	return SWIG_TOKEN_GREATERTHAN;
908       }
909       if (c == '>' && brackets_allow_shift(s))
910 	state = 250;
911       else if (c == '=')
912 	return SWIG_TOKEN_GTEQUAL;
913       else {
914 	retract(s, 1);
915         brackets_decrement(s);
916 	return SWIG_TOKEN_GREATERTHAN;
917       }
918       break;
919 
920     case 7:			/* Identifier or true/false or unicode/custom delimiter string */
921       if (c == 'R') { /* Possibly CUSTOM DELIMITER string */
922 	state = 72;
923 	break;
924       }
925       else if (c == 'L') { /* Probably identifier but may be a wide string literal */
926 	state = 77;
927 	break;
928       }
929       else if (c != 'u' && c != 'U') { /* Definitely an identifier */
930 	state = 70;
931 	break;
932       }
933 
934       if ((c = nextchar(s)) == 0) {
935 	state = 76;
936       }
937       else if (c == '\"') { /* Definitely u, U or L string */
938 	retract(s, 1);
939 	state = 1000;
940       }
941       else if (c == '\'') { /* Definitely u, U or L char */
942 	retract(s, 1);
943 	state = 77;
944       }
945       else if (c == 'R') { /* Possibly CUSTOM DELIMITER u, U, L string */
946 	state = 73;
947       }
948       else if (c == '8') { /* Possibly u8 string/char */
949 	state = 71;
950       }
951       else {
952 	retract(s, 1);   /* Definitely an identifier */
953 	state = 70;
954       }
955       break;
956 
957     case 70:			/* Identifier */
958       if ((c = nextchar(s)) == 0)
959 	state = 76;
960       else if (isalnum(c) || (c == '_') || (c == '$')) {
961 	state = 70;
962       } else {
963 	retract(s, 1);
964 	state = 76;
965       }
966       break;
967 
968     case 71:			/* Possibly u8 string/char */
969       if ((c = nextchar(s)) == 0) {
970 	state = 76;
971       }
972       else if (c=='\"') {
973 	retract(s, 1); /* Definitely u8 string */
974 	state = 1000;
975       }
976       else if (c=='\'') {
977 	retract(s, 1); /* Definitely u8 char */
978 	state = 77;
979       }
980       else if (c=='R') {
981 	state = 74; /* Possibly CUSTOM DELIMITER u8 string */
982       }
983       else {
984 	retract(s, 2); /* Definitely an identifier. Retract 8" */
985 	state = 70;
986       }
987 
988       break;
989 
990     case 72:			/* Possibly CUSTOM DELIMITER string */
991     case 73:
992     case 74:
993       if ((c = nextchar(s)) == 0) {
994 	state = 76;
995       }
996       else if (c=='\"') {
997 	retract(s, 1); /* Definitely custom delimiter u, U or L string */
998 	str_delimiter = NewStringEmpty();
999 	state = 1000;
1000       }
1001       else {
1002 	if (state==72) {
1003 	  retract(s, 1); /* Definitely an identifier. Retract ? */
1004 	}
1005 	else if (state==73) {
1006 	  retract(s, 2); /* Definitely an identifier. Retract R? */
1007 	}
1008 	else if (state==74) {
1009 	  retract(s, 3); /* Definitely an identifier. Retract 8R? */
1010 	}
1011 	state = 70;
1012       }
1013 
1014       break;
1015 
1016     case 75:			/* Special identifier $ */
1017       if ((c = nextchar(s)) == 0)
1018 	return SWIG_TOKEN_DOLLAR;
1019       if (isalnum(c) || (c == '_') || (c == '*') || (c == '&')) {
1020 	state = 70;
1021       } else {
1022 	retract(s,1);
1023 	if (Len(s->text) == 1) return SWIG_TOKEN_DOLLAR;
1024 	state = 76;
1025       }
1026       break;
1027 
1028     case 76:			/* Identifier or true/false */
1029       if (cparse_cplusplus) {
1030 	if (Strcmp(s->text, "true") == 0)
1031 	  return SWIG_TOKEN_BOOL;
1032 	else if (Strcmp(s->text, "false") == 0)
1033 	  return SWIG_TOKEN_BOOL;
1034 	}
1035       return SWIG_TOKEN_ID;
1036       break;
1037 
1038     case 77: /*identifier or wide string literal*/
1039       if ((c = nextchar(s)) == 0)
1040 	return SWIG_TOKEN_ID;
1041       else if (c == '\"') {
1042 	s->start_line = s->line;
1043 	Clear(s->text);
1044 	state = 78;
1045       }
1046       else if (c == '\'') {
1047 	s->start_line = s->line;
1048 	Clear(s->text);
1049 	state = 79;
1050       }
1051       else if (isalnum(c) || (c == '_') || (c == '$'))
1052 	state = 7;
1053       else {
1054 	retract(s, 1);
1055 	return SWIG_TOKEN_ID;
1056       }
1057     break;
1058 
1059     case 78:			/* Processing a wide string literal*/
1060       if ((c = nextchar(s)) == 0) {
1061 	Swig_error(cparse_file, cparse_start_line, "Unterminated wide string\n");
1062 	return SWIG_TOKEN_ERROR;
1063       }
1064       if (c == '\"') {
1065 	Delitem(s->text, DOH_END);
1066 	return SWIG_TOKEN_WSTRING;
1067       } else if (c == '\\') {
1068 	if ((c = nextchar(s)) == 0) {
1069 	  Swig_error(cparse_file, cparse_start_line, "Unterminated wide string\n");
1070 	  return SWIG_TOKEN_ERROR;
1071 	}
1072       }
1073       break;
1074 
1075     case 79:			/* Processing a wide char literal */
1076       if ((c = nextchar(s)) == 0) {
1077 	Swig_error(cparse_file, cparse_start_line, "Unterminated wide character constant\n");
1078 	return SWIG_TOKEN_ERROR;
1079       }
1080       if (c == '\'') {
1081 	Delitem(s->text, DOH_END);
1082 	return (SWIG_TOKEN_WCHAR);
1083       } else if (c == '\\') {
1084 	if ((c = nextchar(s)) == 0) {
1085 	  Swig_error(cparse_file, cparse_start_line, "Unterminated wide character literal\n");
1086 	  return SWIG_TOKEN_ERROR;
1087 	}
1088       }
1089       break;
1090 
1091     case 8:			/* A numerical digit */
1092       if ((c = nextchar(s)) == 0)
1093 	return SWIG_TOKEN_INT;
1094       if (c == '.') {
1095 	state = 81;
1096       } else if ((c == 'e') || (c == 'E')) {
1097 	state = 82;
1098       } else if ((c == 'f') || (c == 'F')) {
1099 	Delitem(s->text, DOH_END);
1100 	return SWIG_TOKEN_FLOAT;
1101       } else if (isdigit(c)) {
1102 	state = 8;
1103       } else if ((c == 'l') || (c == 'L')) {
1104 	state = 87;
1105       } else if ((c == 'u') || (c == 'U')) {
1106 	state = 88;
1107       } else {
1108 	retract(s, 1);
1109 	return SWIG_TOKEN_INT;
1110       }
1111       break;
1112     case 81:			/* A floating pointer number of some sort */
1113       if ((c = nextchar(s)) == 0)
1114 	return SWIG_TOKEN_DOUBLE;
1115       if (isdigit(c))
1116 	state = 81;
1117       else if ((c == 'e') || (c == 'E'))
1118 	state = 820;
1119       else if ((c == 'f') || (c == 'F')) {
1120 	Delitem(s->text, DOH_END);
1121 	return SWIG_TOKEN_FLOAT;
1122       } else if ((c == 'l') || (c == 'L')) {
1123 	Delitem(s->text, DOH_END);
1124 	return SWIG_TOKEN_DOUBLE;
1125       } else {
1126 	retract(s, 1);
1127 	return (SWIG_TOKEN_DOUBLE);
1128       }
1129       break;
1130     case 82:
1131       if ((c = nextchar(s)) == 0) {
1132 	Swig_error(cparse_file, cparse_start_line, "Exponent does not have any digits\n");
1133 	return SWIG_TOKEN_ERROR;
1134       }
1135       if ((isdigit(c)) || (c == '-') || (c == '+'))
1136 	state = 86;
1137       else {
1138 	retract(s, 2);
1139 	Swig_error(cparse_file, cparse_start_line, "Exponent does not have any digits\n");
1140 	return SWIG_TOKEN_ERROR;
1141       }
1142       break;
1143     case 820:
1144       /* Like case 82, but we've seen a decimal point. */
1145       if ((c = nextchar(s)) == 0) {
1146 	Swig_error(cparse_file, cparse_start_line, "Exponent does not have any digits\n");
1147 	return SWIG_TOKEN_ERROR;
1148       }
1149       if ((isdigit(c)) || (c == '-') || (c == '+'))
1150 	state = 86;
1151       else {
1152 	retract(s, 2);
1153 	Swig_error(cparse_file, cparse_start_line, "Exponent does not have any digits\n");
1154 	return SWIG_TOKEN_ERROR;
1155       }
1156       break;
1157     case 83:
1158       /* Might be a hexadecimal or octal number */
1159       if ((c = nextchar(s)) == 0)
1160 	return SWIG_TOKEN_INT;
1161       if (isdigit(c))
1162 	state = 84;
1163       else if ((c == 'e') || (c == 'E'))
1164 	state = 82;
1165       else if ((c == 'x') || (c == 'X'))
1166 	state = 85;
1167       else if ((c == 'b') || (c == 'B'))
1168 	state = 850;
1169       else if (c == '.')
1170 	state = 81;
1171       else if ((c == 'l') || (c == 'L')) {
1172 	state = 87;
1173       } else if ((c == 'u') || (c == 'U')) {
1174 	state = 88;
1175       } else {
1176 	retract(s, 1);
1177 	return SWIG_TOKEN_INT;
1178       }
1179       break;
1180     case 84:
1181       /* This is an octal number */
1182       if ((c = nextchar(s)) == 0)
1183 	return SWIG_TOKEN_INT;
1184       if (isdigit(c))
1185 	state = 84;
1186       else if (c == '.')
1187 	state = 81;
1188       else if ((c == 'e') || (c == 'E'))
1189 	state = 82;
1190       else if ((c == 'l') || (c == 'L')) {
1191 	state = 87;
1192       } else if ((c == 'u') || (c == 'U')) {
1193 	state = 88;
1194       } else {
1195 	retract(s, 1);
1196 	return SWIG_TOKEN_INT;
1197       }
1198       break;
1199     case 85:
1200       /* This is an hex number */
1201       if ((c = nextchar(s)) == 0)
1202 	return SWIG_TOKEN_INT;
1203       if (isxdigit(c))
1204 	state = 85;
1205       else if (c == '.') /* hexadecimal float */
1206 	state = 860;
1207       else if ((c == 'p') || (c == 'P')) /* hexadecimal float */
1208 	state = 820;
1209       else if ((c == 'l') || (c == 'L')) {
1210 	state = 87;
1211       } else if ((c == 'u') || (c == 'U')) {
1212 	state = 88;
1213       } else {
1214 	retract(s, 1);
1215 	return SWIG_TOKEN_INT;
1216       }
1217       break;
1218     case 850:
1219       /* This is a binary number */
1220       if ((c = nextchar(s)) == 0)
1221 	return SWIG_TOKEN_INT;
1222       if ((c == '0') || (c == '1'))
1223 	state = 850;
1224       else if ((c == 'l') || (c == 'L')) {
1225 	state = 87;
1226       } else if ((c == 'u') || (c == 'U')) {
1227 	state = 88;
1228       } else {
1229 	retract(s, 1);
1230 	return SWIG_TOKEN_INT;
1231       }
1232       break;
1233     case 860:
1234       /* hexadecimal float */
1235       if ((c = nextchar(s)) == 0) {
1236 	Swig_error(cparse_file, cparse_start_line, "Hexadecimal floating literals require an exponent\n");
1237 	return SWIG_TOKEN_ERROR;
1238       }
1239       if (isxdigit(c))
1240 	state = 860;
1241       else if ((c == 'p') || (c == 'P'))
1242 	state = 820;
1243       else {
1244 	retract(s, 2);
1245 	Swig_error(cparse_file, cparse_start_line, "Hexadecimal floating literals require an exponent\n");
1246 	return SWIG_TOKEN_ERROR;
1247       }
1248       break;
1249     case 86:
1250       /* Rest of floating point number */
1251 
1252       if ((c = nextchar(s)) == 0)
1253 	return SWIG_TOKEN_DOUBLE;
1254       if (isdigit(c))
1255 	state = 86;
1256       else if ((c == 'f') || (c == 'F')) {
1257 	Delitem(s->text, DOH_END);
1258 	return SWIG_TOKEN_FLOAT;
1259       } else if ((c == 'l') || (c == 'L')) {
1260 	Delitem(s->text, DOH_END);
1261 	return SWIG_TOKEN_DOUBLE;
1262       } else {
1263 	retract(s, 1);
1264 	return SWIG_TOKEN_DOUBLE;
1265       }
1266       break;
1267 
1268     case 87:
1269       /* A long integer of some sort */
1270       if ((c = nextchar(s)) == 0)
1271 	return SWIG_TOKEN_LONG;
1272       if ((c == 'u') || (c == 'U')) {
1273 	return SWIG_TOKEN_ULONG;
1274       } else if ((c == 'l') || (c == 'L')) {
1275 	state = 870;
1276       } else {
1277 	retract(s, 1);
1278 	return SWIG_TOKEN_LONG;
1279       }
1280       break;
1281 
1282       /* A long long integer */
1283 
1284     case 870:
1285       if ((c = nextchar(s)) == 0)
1286 	return SWIG_TOKEN_LONGLONG;
1287       if ((c == 'u') || (c == 'U')) {
1288 	return SWIG_TOKEN_ULONGLONG;
1289       } else {
1290 	retract(s, 1);
1291 	return SWIG_TOKEN_LONGLONG;
1292       }
1293 
1294       /* An unsigned number */
1295     case 88:
1296 
1297       if ((c = nextchar(s)) == 0)
1298 	return SWIG_TOKEN_UINT;
1299       if ((c == 'l') || (c == 'L')) {
1300 	state = 880;
1301       } else {
1302 	retract(s, 1);
1303 	return SWIG_TOKEN_UINT;
1304       }
1305       break;
1306 
1307       /* Possibly an unsigned long long or unsigned long */
1308     case 880:
1309       if ((c = nextchar(s)) == 0)
1310 	return SWIG_TOKEN_ULONG;
1311       if ((c == 'l') || (c == 'L'))
1312 	return SWIG_TOKEN_ULONGLONG;
1313       else {
1314 	retract(s, 1);
1315 	return SWIG_TOKEN_ULONG;
1316       }
1317 
1318       /* A character constant */
1319     case 9:
1320       if ((c = nextchar(s)) == 0) {
1321 	Swig_error(cparse_file, cparse_start_line, "Unterminated character constant\n");
1322 	return SWIG_TOKEN_ERROR;
1323       }
1324       if (c == '\'') {
1325 	Delitem(s->text, DOH_END);
1326 	return (SWIG_TOKEN_CHAR);
1327       } else if (c == '\\') {
1328 	Delitem(s->text, DOH_END);
1329 	get_escape(s);
1330       }
1331       break;
1332 
1333       /* A period or maybe a floating point number */
1334 
1335     case 100:
1336       if ((c = nextchar(s)) == 0)
1337 	return (0);
1338       if (isdigit(c))
1339 	state = 81;
1340       else {
1341 	retract(s, 1);
1342 	return SWIG_TOKEN_PERIOD;
1343       }
1344       break;
1345 
1346     case 200:			/* PLUS, PLUSPLUS, PLUSEQUAL */
1347       if ((c = nextchar(s)) == 0)
1348 	return SWIG_TOKEN_PLUS;
1349       else if (c == '+')
1350 	return SWIG_TOKEN_PLUSPLUS;
1351       else if (c == '=')
1352 	return SWIG_TOKEN_PLUSEQUAL;
1353       else {
1354 	retract(s, 1);
1355 	return SWIG_TOKEN_PLUS;
1356       }
1357       break;
1358 
1359     case 210:			/* MINUS, MINUSMINUS, MINUSEQUAL, ARROW */
1360       if ((c = nextchar(s)) == 0)
1361 	return SWIG_TOKEN_MINUS;
1362       else if (c == '-')
1363 	return SWIG_TOKEN_MINUSMINUS;
1364       else if (c == '=')
1365 	return SWIG_TOKEN_MINUSEQUAL;
1366       else if (c == '>')
1367 	state = 211;
1368       else {
1369 	retract(s, 1);
1370 	return SWIG_TOKEN_MINUS;
1371       }
1372       break;
1373 
1374     case 211:			/* ARROW, ARROWSTAR */
1375       if ((c = nextchar(s)) == 0)
1376 	return SWIG_TOKEN_ARROW;
1377       else if (c == '*')
1378 	return SWIG_TOKEN_ARROWSTAR;
1379       else {
1380 	retract(s, 1);
1381 	return SWIG_TOKEN_ARROW;
1382       }
1383       break;
1384 
1385 
1386     case 220:			/* STAR, TIMESEQUAL */
1387       if ((c = nextchar(s)) == 0)
1388 	return SWIG_TOKEN_STAR;
1389       else if (c == '=')
1390 	return SWIG_TOKEN_TIMESEQUAL;
1391       else {
1392 	retract(s, 1);
1393 	return SWIG_TOKEN_STAR;
1394       }
1395       break;
1396 
1397     case 230:			/* XOR, XOREQUAL */
1398       if ((c = nextchar(s)) == 0)
1399 	return SWIG_TOKEN_XOR;
1400       else if (c == '=')
1401 	return SWIG_TOKEN_XOREQUAL;
1402       else {
1403 	retract(s, 1);
1404 	return SWIG_TOKEN_XOR;
1405       }
1406       break;
1407 
1408     case 240:			/* LSHIFT, LSEQUAL */
1409       if ((c = nextchar(s)) == 0)
1410 	return SWIG_TOKEN_LSHIFT;
1411       else if (c == '=')
1412 	return SWIG_TOKEN_LSEQUAL;
1413       else {
1414 	retract(s, 1);
1415 	return SWIG_TOKEN_LSHIFT;
1416       }
1417       break;
1418 
1419     case 250:			/* RSHIFT, RSEQUAL */
1420       if ((c = nextchar(s)) == 0)
1421 	return SWIG_TOKEN_RSHIFT;
1422       else if (c == '=')
1423 	return SWIG_TOKEN_RSEQUAL;
1424       else {
1425 	retract(s, 1);
1426 	return SWIG_TOKEN_RSHIFT;
1427       }
1428       break;
1429 
1430 
1431       /* An illegal character */
1432 
1433       /* Reverse string */
1434     case 900:
1435       if ((c = nextchar(s)) == 0) {
1436 	Swig_error(cparse_file, cparse_start_line, "Unterminated character constant\n");
1437 	return SWIG_TOKEN_ERROR;
1438       }
1439       if (c == '`') {
1440 	Delitem(s->text, DOH_END);
1441 	return (SWIG_TOKEN_RSTRING);
1442       }
1443       break;
1444 
1445     default:
1446       return SWIG_TOKEN_ILLEGAL;
1447     }
1448   }
1449 }
1450 
1451 /* -----------------------------------------------------------------------------
1452  * Scanner_token()
1453  *
1454  * Real entry point to return the next token. Returns 0 if at end of input.
1455  * ----------------------------------------------------------------------------- */
1456 
Scanner_token(Scanner * s)1457 int Scanner_token(Scanner *s) {
1458   int t;
1459   Delete(s->error);
1460   if (s->nexttoken >= 0) {
1461     t = s->nexttoken;
1462     s->nexttoken = -1;
1463     return t;
1464   }
1465   s->start_line = 0;
1466   t = look(s);
1467   if (!s->start_line) {
1468     Setline(s->text,s->line);
1469   } else {
1470     Setline(s->text,s->start_line);
1471   }
1472   return t;
1473 }
1474 
1475 /* -----------------------------------------------------------------------------
1476  * Scanner_text()
1477  *
1478  * Return the lexene associated with the last returned token.
1479  * ----------------------------------------------------------------------------- */
1480 
Scanner_text(Scanner * s)1481 String *Scanner_text(Scanner *s) {
1482   return s->text;
1483 }
1484 
1485 /* -----------------------------------------------------------------------------
1486  * Scanner_skip_line()
1487  *
1488  * Skips to the end of a line
1489  * ----------------------------------------------------------------------------- */
1490 
Scanner_skip_line(Scanner * s)1491 void Scanner_skip_line(Scanner *s) {
1492   char c;
1493   int done = 0;
1494   Clear(s->text);
1495   Setfile(s->text, Getfile(s->str));
1496   Setline(s->text, s->line);
1497   while (!done) {
1498     if ((c = nextchar(s)) == 0)
1499       return;
1500     if (c == '\\') {
1501       nextchar(s);
1502     } else if (c == '\n') {
1503       done = 1;
1504     }
1505   }
1506   return;
1507 }
1508 
1509 /* -----------------------------------------------------------------------------
1510  * Scanner_skip_balanced()
1511  *
1512  * Skips a piece of code enclosed in begin/end symbols such as '{...}' or
1513  * (...).  Ignores symbols inside comments or strings.
1514  * ----------------------------------------------------------------------------- */
1515 
Scanner_skip_balanced(Scanner * s,int startchar,int endchar)1516 int Scanner_skip_balanced(Scanner *s, int startchar, int endchar) {
1517   char c;
1518   int num_levels = 1;
1519   int state = 0;
1520   char temp[2] = { 0, 0 };
1521   String *locator = 0;
1522   temp[0] = (char) startchar;
1523   Clear(s->text);
1524   Setfile(s->text, Getfile(s->str));
1525   Setline(s->text, s->line);
1526 
1527   Append(s->text, temp);
1528   while (num_levels > 0) {
1529     if ((c = nextchar(s)) == 0) {
1530       Delete(locator);
1531       return -1;
1532     }
1533     switch (state) {
1534     case 0:
1535       if (c == startchar)
1536 	num_levels++;
1537       else if (c == endchar)
1538 	num_levels--;
1539       else if (c == '/')
1540 	state = 10;
1541       else if (c == '\"')
1542 	state = 20;
1543       else if (c == '\'')
1544 	state = 30;
1545       break;
1546     case 10:
1547       if (c == '/')
1548 	state = 11;
1549       else if (c == '*')
1550 	state = 12;
1551       else if (c == startchar) {
1552 	state = 0;
1553 	num_levels++;
1554       }
1555       else
1556 	state = 0;
1557       break;
1558     case 11:
1559       if (c == '\n')
1560 	state = 0;
1561       else
1562 	state = 11;
1563       break;
1564     case 12: /* first character inside C comment */
1565       if (c == '*')
1566 	state = 14;
1567       else if (c == '@')
1568 	state = 40;
1569       else
1570 	state = 13;
1571       break;
1572     case 13:
1573       if (c == '*')
1574 	state = 14;
1575       break;
1576     case 14: /* possible end of C comment */
1577       if (c == '*')
1578 	state = 14;
1579       else if (c == '/')
1580 	state = 0;
1581       else
1582 	state = 13;
1583       break;
1584     case 20:
1585       if (c == '\"')
1586 	state = 0;
1587       else if (c == '\\')
1588 	state = 21;
1589       break;
1590     case 21:
1591       state = 20;
1592       break;
1593     case 30:
1594       if (c == '\'')
1595 	state = 0;
1596       else if (c == '\\')
1597 	state = 31;
1598       break;
1599     case 31:
1600       state = 30;
1601       break;
1602     /* 40-45 SWIG locator checks - a C comment with contents starting: @SWIG */
1603     case 40:
1604       state = (c == 'S') ? 41 : (c == '*') ? 14 : 13;
1605       break;
1606     case 41:
1607       state = (c == 'W') ? 42 : (c == '*') ? 14 : 13;
1608       break;
1609     case 42:
1610       state = (c == 'I') ? 43 : (c == '*') ? 14 : 13;
1611       break;
1612     case 43:
1613       state = (c == 'G') ? 44 : (c == '*') ? 14 : 13;
1614       if (c == 'G') {
1615 	Delete(locator);
1616 	locator = NewString("/*@SWIG");
1617       }
1618       break;
1619     case 44:
1620       if (c == '*')
1621 	state = 45;
1622       Putc(c, locator);
1623       break;
1624     case 45: /* end of SWIG locator in C comment */
1625       if (c == '/') {
1626 	state = 0;
1627 	Putc(c, locator);
1628 	Scanner_locator(s, locator);
1629       } else {
1630 	/* malformed locator */
1631 	state = (c == '*') ? 14 : 13;
1632       }
1633       break;
1634     default:
1635       break;
1636     }
1637   }
1638   Delete(locator);
1639   return 0;
1640 }
1641 
1642 /* -----------------------------------------------------------------------------
1643  * Scanner_get_raw_text_balanced()
1644  *
1645  * Returns raw text between 2 braces, does not change scanner state in any way
1646  * ----------------------------------------------------------------------------- */
1647 
Scanner_get_raw_text_balanced(Scanner * s,int startchar,int endchar)1648 String *Scanner_get_raw_text_balanced(Scanner *s, int startchar, int endchar) {
1649   String *result = 0;
1650   char c;
1651   int old_line = s->line;
1652   String *old_text = Copy(s->text);
1653   long position = Tell(s->str);
1654 
1655   int num_levels = 1;
1656   int state = 0;
1657   char temp[2] = { 0, 0 };
1658   temp[0] = (char) startchar;
1659   Clear(s->text);
1660   Setfile(s->text, Getfile(s->str));
1661   Setline(s->text, s->line);
1662   Append(s->text, temp);
1663   while (num_levels > 0) {
1664     if ((c = nextchar(s)) == 0) {
1665       Clear(s->text);
1666       Append(s->text, old_text);
1667       Delete(old_text);
1668       s->line = old_line;
1669       return 0;
1670     }
1671     switch (state) {
1672     case 0:
1673       if (c == startchar)
1674 	num_levels++;
1675       else if (c == endchar)
1676 	num_levels--;
1677       else if (c == '/')
1678 	state = 10;
1679       else if (c == '\"')
1680 	state = 20;
1681       else if (c == '\'')
1682 	state = 30;
1683       break;
1684     case 10:
1685       if (c == '/')
1686 	state = 11;
1687       else if (c == '*')
1688 	state = 12;
1689       else if (c == startchar) {
1690 	state = 0;
1691 	num_levels++;
1692       }
1693       else
1694 	state = 0;
1695       break;
1696     case 11:
1697       if (c == '\n')
1698 	state = 0;
1699       else
1700 	state = 11;
1701       break;
1702     case 12: /* first character inside C comment */
1703       if (c == '*')
1704 	state = 14;
1705       else
1706 	state = 13;
1707       break;
1708     case 13:
1709       if (c == '*')
1710 	state = 14;
1711       break;
1712     case 14: /* possible end of C comment */
1713       if (c == '*')
1714 	state = 14;
1715       else if (c == '/')
1716 	state = 0;
1717       else
1718 	state = 13;
1719       break;
1720     case 20:
1721       if (c == '\"')
1722 	state = 0;
1723       else if (c == '\\')
1724 	state = 21;
1725       break;
1726     case 21:
1727       state = 20;
1728       break;
1729     case 30:
1730       if (c == '\'')
1731 	state = 0;
1732       else if (c == '\\')
1733 	state = 31;
1734       break;
1735     case 31:
1736       state = 30;
1737       break;
1738     default:
1739       break;
1740     }
1741   }
1742   Seek(s->str, position, SEEK_SET);
1743   result = Copy(s->text);
1744   Clear(s->text);
1745   Append(s->text, old_text);
1746   Delete(old_text);
1747   s->line = old_line;
1748   return result;
1749 }
1750 /* -----------------------------------------------------------------------------
1751  * Scanner_isoperator()
1752  *
1753  * Returns 0 or 1 depending on whether or not a token corresponds to a C/C++
1754  * operator.
1755  * ----------------------------------------------------------------------------- */
1756 
Scanner_isoperator(int tokval)1757 int Scanner_isoperator(int tokval) {
1758   if (tokval >= 100) return 1;
1759   return 0;
1760 }
1761 
1762 /* ----------------------------------------------------------------------
1763  * locator()
1764  *
1765  * Support for locator strings. These are strings of the form
1766  * @SWIG:filename,line,id@ emitted by the SWIG preprocessor.  They
1767  * are primarily used for macro line number reporting.
1768  * We just use the locator to mark when to activate/deactivate linecounting.
1769  * ---------------------------------------------------------------------- */
1770 
1771 
Scanner_locator(Scanner * s,String * loc)1772 void Scanner_locator(Scanner *s, String *loc) {
1773   static Locator *locs = 0;
1774   static int expanding_macro = 0;
1775 
1776   if (!follow_locators) {
1777     if (Equal(loc, "/*@SWIG@*/")) {
1778       /* End locator. */
1779       if (expanding_macro)
1780 	--expanding_macro;
1781     } else {
1782       /* Begin locator. */
1783       ++expanding_macro;
1784     }
1785     /* Freeze line number processing in Scanner */
1786     freeze_line(s,expanding_macro);
1787   } else {
1788     int c;
1789     Locator *l;
1790     (void)Seek(loc, 7, SEEK_SET);
1791     c = Getc(loc);
1792     if (c == '@') {
1793       /* Empty locator.  We pop the last location off */
1794       if (locs) {
1795 	Scanner_set_location(s, locs->filename, locs->line_number);
1796 	cparse_file = locs->filename;
1797 	cparse_line = locs->line_number;
1798 	l = locs->next;
1799 	free(locs);
1800 	locs = l;
1801       }
1802       return;
1803     }
1804 
1805     /* We're going to push a new location */
1806     l = (Locator *) malloc(sizeof(Locator));
1807     l->filename = cparse_file;
1808     l->line_number = cparse_line;
1809     l->next = locs;
1810     locs = l;
1811 
1812     /* Now, parse the new location out of the locator string */
1813     {
1814       String *fn = NewStringEmpty();
1815       /*      Putc(c, fn); */
1816 
1817       while ((c = Getc(loc)) != EOF) {
1818 	if ((c == '@') || (c == ','))
1819 	  break;
1820 	Putc(c, fn);
1821       }
1822       cparse_file = Swig_copy_string(Char(fn));
1823       Clear(fn);
1824       cparse_line = 1;
1825       /* Get the line number */
1826       while ((c = Getc(loc)) != EOF) {
1827 	if ((c == '@') || (c == ','))
1828 	  break;
1829 	Putc(c, fn);
1830       }
1831       cparse_line = atoi(Char(fn));
1832       Clear(fn);
1833 
1834       /* Get the rest of it */
1835       while ((c = Getc(loc)) != EOF) {
1836 	if (c == '@')
1837 	  break;
1838 	Putc(c, fn);
1839       }
1840       /*  Swig_diagnostic(cparse_file, cparse_line, "Scanner_set_location\n"); */
1841       Scanner_set_location(s, cparse_file, cparse_line);
1842       Delete(fn);
1843     }
1844   }
1845 }
1846 
Swig_cparse_follow_locators(int v)1847 void Swig_cparse_follow_locators(int v) {
1848    follow_locators = v;
1849 }
1850 
1851 
1852