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 * SWIG tokenizer.  This file is a wrapper around the generic C scanner
8 * found in Swig/scanner.c.   Extra logic is added both to accomodate the
9 * bison-based grammar and certain peculiarities of C++ parsing (e.g.,
10 * operator overloading, typedef resolution, etc.).  This code also splits
11 * C identifiers up into keywords and SWIG directives.
12 * ----------------------------------------------------------------------------- */
13
14char cvsroot_cscanner_c[] = "$Id: cscanner.c 11123 2009-02-08 22:30:10Z wsfulton $";
15
16#include "cparse.h"
17#include "parser.h"
18#include <string.h>
19#include <ctype.h>
20
21/* Scanner object */
22static Scanner *scan = 0;
23
24/* Global string containing C code. Used by the parser to grab code blocks */
25String *scanner_ccode = 0;
26
27/* The main file being parsed */
28static String *main_input_file = 0;
29
30/* Error reporting/location information */
31int     cparse_line = 1;
32String *cparse_file = 0;
33int     cparse_start_line = 0;
34
35/* C++ mode */
36int cparse_cplusplus = 0;
37
38/* Private vars */
39static int scan_init = 0;
40static int num_brace = 0;
41static int last_brace = 0;
42static int last_id = 0;
43static int rename_active = 0;
44static int expanding_macro = 0;
45static int follow_locators = 0;
46
47/* -----------------------------------------------------------------------------
48 * Swig_cparse_cplusplus()
49 * ----------------------------------------------------------------------------- */
50
51void Swig_cparse_cplusplus(int v) {
52  cparse_cplusplus = v;
53}
54
55/* ----------------------------------------------------------------------
56 * locator()
57 *
58 * Support for locator strings.   These are strings of the form
59 * @SWIG:filename,line,id@ emitted by the SWIG preprocessor.  They
60 * are primarily used for macro line number reporting
61 * ---------------------------------------------------------------------- */
62
63typedef struct Locator {
64  String         *filename;
65  int             line_number;
66  struct Locator *next;
67} Locator;
68
69static Locator *locs = 0;
70
71/* we just use the locator to mark when active/deactive the linecounting */
72
73static void scanner_locator(String *loc) {
74  if (!follow_locators) {
75    if (Equal(loc, "/*@SWIG@*/")) {
76      /* End locator. */
77      if (expanding_macro)
78	--expanding_macro;
79    } else {
80      /* Begin locator. */
81      ++expanding_macro;
82    }
83    /* Freeze line number processing in Scanner */
84    Scanner_freeze_line(scan,expanding_macro);
85  } else {
86    int c;
87    Locator *l;
88    Seek(loc, 7, SEEK_SET);
89    c = Getc(loc);
90    if (c == '@') {
91      /* Empty locator.  We pop the last location off */
92      if (locs) {
93	Scanner_set_location(scan,locs->filename,locs->line_number);
94	cparse_file = locs->filename;
95	cparse_line = locs->line_number;
96	l = locs->next;
97	free(locs);
98	locs = l;
99      }
100      return;
101    }
102
103    /* We're going to push a new location */
104    l = (Locator *) malloc(sizeof(Locator));
105    l->filename = cparse_file;
106    l->line_number = cparse_line;
107    l->next = locs;
108    locs = l;
109
110    /* Now, parse the new location out of the locator string */
111    {
112      String *fn = NewStringEmpty();
113      /*      Putc(c, fn); */
114
115      while ((c = Getc(loc)) != EOF) {
116	if ((c == '@') || (c == ','))
117	  break;
118	Putc(c, fn);
119      }
120      cparse_file = Swig_copy_string(Char(fn));
121      Clear(fn);
122      cparse_line = 1;
123      /* Get the line number */
124      while ((c = Getc(loc)) != EOF) {
125	if ((c == '@') || (c == ','))
126	  break;
127	Putc(c, fn);
128      }
129      cparse_line = atoi(Char(fn));
130      Clear(fn);
131
132      /* Get the rest of it */
133      while ((c = Getc(loc)) != EOF) {
134	if (c == '@')
135	  break;
136	Putc(c, fn);
137      }
138      /*  Printf(stderr,"location: %s:%d\n",cparse_file,cparse_line); */
139      Scanner_set_location(scan,cparse_file,cparse_line);
140      Delete(fn);
141    }
142  }
143}
144
145void Swig_cparse_follow_locators(int v) {
146   follow_locators = v;
147}
148
149
150/* ----------------------------------------------------------------------------
151 * scanner_init()
152 *
153 * Initialize buffers
154 * ------------------------------------------------------------------------- */
155
156void scanner_init() {
157  scan = NewScanner();
158  Scanner_idstart(scan,"%");
159  scan_init = 1;
160  scanner_ccode = NewStringEmpty();
161}
162
163/* ----------------------------------------------------------------------------
164 * scanner_file(DOHFile *f)
165 *
166 * Start reading from new file
167 * ------------------------------------------------------------------------- */
168void scanner_file(DOHFile * f) {
169  if (!scan_init) scanner_init();
170  Scanner_clear(scan);
171  Scanner_push(scan,f);
172}
173
174/* ----------------------------------------------------------------------------
175 * start_inline(char *text, int line)
176 *
177 * Take a chunk of text and recursively feed it back into the scanner.  Used
178 * by the %inline directive.
179 * ------------------------------------------------------------------------- */
180
181void start_inline(char *text, int line) {
182  String *stext = NewString(text);
183
184  Seek(stext,0,SEEK_SET);
185  Setfile(stext,cparse_file);
186  Setline(stext,line);
187  Scanner_push(scan,stext);
188  Delete(stext);
189}
190
191/* -----------------------------------------------------------------------------
192 * skip_balanced()
193 *
194 * Skips a piece of code enclosed in begin/end symbols such as '{...}' or
195 * (...).  Ignores symbols inside comments or strings.
196 * ----------------------------------------------------------------------------- */
197
198void skip_balanced(int startchar, int endchar) {
199  Clear(scanner_ccode);
200
201  if (Scanner_skip_balanced(scan,startchar,endchar) < 0) {
202    Swig_error(Scanner_file(scan),Scanner_errline(scan), "Missing '%c'. Reached end of input.\n", endchar);
203    return;
204  }
205
206  cparse_line = Scanner_line(scan);
207  cparse_file = Scanner_file(scan);
208
209  Append(scanner_ccode, Scanner_text(scan));
210  if (endchar == '}')
211    num_brace--;
212  return;
213}
214
215/* ----------------------------------------------------------------------------
216 * void skip_decl(void)
217 *
218 * This tries to skip over an entire declaration.   For example
219 *
220 *  friend ostream& operator<<(ostream&, const char *s);
221 *
222 * or
223 *  friend ostream& operator<<(ostream&, const char *s) { };
224 *
225 * ------------------------------------------------------------------------- */
226
227void skip_decl(void) {
228  int tok;
229  int done = 0;
230  int start_line = Scanner_line(scan);
231
232  while (!done) {
233    tok = Scanner_token(scan);
234    if (tok == 0) {
235      if (!Swig_error_count()) {
236	Swig_error(cparse_file, start_line, "Missing semicolon. Reached end of input.\n");
237      }
238      return;
239    }
240    if (tok == SWIG_TOKEN_LBRACE) {
241      if (Scanner_skip_balanced(scan,'{','}') < 0) {
242	Swig_error(cparse_file, start_line, "Missing '}'. Reached end of input.\n");
243      }
244      break;
245    }
246    if (tok == SWIG_TOKEN_SEMI) {
247      done = 1;
248    }
249  }
250  cparse_file = Scanner_file(scan);
251  cparse_line = Scanner_line(scan);
252}
253
254/* ----------------------------------------------------------------------------
255 * int yylook()
256 *
257 * Lexical scanner.
258 * ------------------------------------------------------------------------- */
259
260int yylook(void) {
261
262  int tok = 0;
263
264  while (1) {
265    if ((tok = Scanner_token(scan)) == 0)
266      return 0;
267    if (tok == SWIG_TOKEN_ERROR)
268      return 0;
269    cparse_start_line = Scanner_start_line(scan);
270    cparse_line = Scanner_line(scan);
271    cparse_file = Scanner_file(scan);
272
273    switch(tok) {
274    case SWIG_TOKEN_ID:
275      return ID;
276    case SWIG_TOKEN_LPAREN:
277      return LPAREN;
278    case SWIG_TOKEN_RPAREN:
279      return RPAREN;
280    case SWIG_TOKEN_SEMI:
281      return SEMI;
282    case SWIG_TOKEN_COMMA:
283      return COMMA;
284    case SWIG_TOKEN_STAR:
285      return STAR;
286    case SWIG_TOKEN_RBRACE:
287      num_brace--;
288      if (num_brace < 0) {
289	Swig_error(cparse_file, cparse_line, "Syntax error. Extraneous '}'\n");
290	num_brace = 0;
291      } else {
292	return RBRACE;
293      }
294      break;
295    case SWIG_TOKEN_LBRACE:
296      last_brace = num_brace;
297      num_brace++;
298      return LBRACE;
299    case SWIG_TOKEN_EQUAL:
300      return EQUAL;
301    case SWIG_TOKEN_EQUALTO:
302      return EQUALTO;
303    case SWIG_TOKEN_PLUS:
304      return PLUS;
305    case SWIG_TOKEN_MINUS:
306      return MINUS;
307    case SWIG_TOKEN_SLASH:
308      return SLASH;
309    case SWIG_TOKEN_AND:
310      return AND;
311    case SWIG_TOKEN_LAND:
312      return LAND;
313    case SWIG_TOKEN_OR:
314      return OR;
315    case SWIG_TOKEN_LOR:
316      return LOR;
317    case SWIG_TOKEN_XOR:
318      return XOR;
319    case SWIG_TOKEN_NOT:
320      return NOT;
321    case SWIG_TOKEN_LNOT:
322      return LNOT;
323    case SWIG_TOKEN_NOTEQUAL:
324      return NOTEQUALTO;
325    case SWIG_TOKEN_LBRACKET:
326      return LBRACKET;
327    case SWIG_TOKEN_RBRACKET:
328      return RBRACKET;
329    case SWIG_TOKEN_QUESTION:
330      return QUESTIONMARK;
331    case SWIG_TOKEN_LESSTHAN:
332      return LESSTHAN;
333    case SWIG_TOKEN_LTEQUAL:
334      return LESSTHANOREQUALTO;
335    case SWIG_TOKEN_LSHIFT:
336      return LSHIFT;
337    case SWIG_TOKEN_GREATERTHAN:
338      return GREATERTHAN;
339    case SWIG_TOKEN_GTEQUAL:
340      return GREATERTHANOREQUALTO;
341    case SWIG_TOKEN_RSHIFT:
342      return RSHIFT;
343    case SWIG_TOKEN_PERIOD:
344      return PERIOD;
345    case SWIG_TOKEN_MODULO:
346      return MODULO;
347    case SWIG_TOKEN_COLON:
348      return COLON;
349    case SWIG_TOKEN_DCOLONSTAR:
350      return DSTAR;
351
352    case SWIG_TOKEN_DCOLON:
353      {
354	int nexttok = Scanner_token(scan);
355	if (nexttok == SWIG_TOKEN_STAR) {
356	  return DSTAR;
357	} else if (nexttok == SWIG_TOKEN_NOT) {
358	  return DCNOT;
359	} else {
360	  Scanner_pushtoken(scan,nexttok,Scanner_text(scan));
361	  if (!last_id) {
362	    scanner_next_token(DCOLON);
363	    return NONID;
364	  } else {
365	    return DCOLON;
366	  }
367	}
368      }
369      break;
370
371      /* Look for multi-character sequences */
372
373    case SWIG_TOKEN_RSTRING:
374      yylval.type = NewString(Scanner_text(scan));
375      return TYPE_RAW;
376
377    case SWIG_TOKEN_STRING:
378      yylval.id = Swig_copy_string(Char(Scanner_text(scan)));
379      return STRING;
380
381    case SWIG_TOKEN_CHAR:
382      yylval.str = NewString(Scanner_text(scan));
383      if (Len(yylval.str) == 0) {
384	Swig_error(cparse_file, cparse_line, "Empty character constant\n");
385	Printf(stdout,"%d\n", Len(Scanner_text(scan)));
386      }
387      return CHARCONST;
388
389      /* Numbers */
390
391    case SWIG_TOKEN_INT:
392      return NUM_INT;
393
394    case SWIG_TOKEN_UINT:
395      return NUM_UNSIGNED;
396
397    case SWIG_TOKEN_LONG:
398      return NUM_LONG;
399
400    case SWIG_TOKEN_ULONG:
401      return NUM_ULONG;
402
403    case SWIG_TOKEN_LONGLONG:
404      return NUM_LONGLONG;
405
406    case SWIG_TOKEN_ULONGLONG:
407      return NUM_ULONGLONG;
408
409    case SWIG_TOKEN_DOUBLE:
410    case SWIG_TOKEN_FLOAT:
411      return NUM_FLOAT;
412
413    case SWIG_TOKEN_POUND:
414      Scanner_skip_line(scan);
415      yylval.id = Swig_copy_string(Char(Scanner_text(scan)));
416      return POUND;
417      break;
418
419    case SWIG_TOKEN_CODEBLOCK:
420      yylval.str = NewString(Scanner_text(scan));
421      return HBLOCK;
422
423    case SWIG_TOKEN_COMMENT:
424      {
425	String *cmt = Scanner_text(scan);
426	char *loc = Char(cmt);
427	if ((strncmp(loc,"/*@SWIG",7) == 0) && (loc[Len(cmt)-3] == '@')) {
428	  scanner_locator(cmt);
429	}
430      }
431      break;
432    case SWIG_TOKEN_ENDLINE:
433      break;
434    case SWIG_TOKEN_BACKSLASH:
435      break;
436    default:
437      Swig_error(cparse_file, cparse_line, "Illegal token '%s'.\n", Scanner_text(scan));
438      return (ILLEGAL);
439    }
440  }
441}
442
443static int check_typedef = 0;
444
445void scanner_set_location(String *file, int line) {
446  Scanner_set_location(scan,file,line-1);
447}
448
449void scanner_check_typedef() {
450  check_typedef = 1;
451}
452
453void scanner_ignore_typedef() {
454  check_typedef = 0;
455}
456
457void scanner_last_id(int x) {
458  last_id = x;
459}
460
461void scanner_clear_rename() {
462  rename_active = 0;
463}
464
465/* Used to push a ficticious token into the scanner */
466static int next_token = 0;
467void scanner_next_token(int tok) {
468  next_token = tok;
469}
470
471void scanner_set_main_input_file(String *file) {
472  main_input_file = file;
473}
474
475String *scanner_get_main_input_file() {
476  return main_input_file;
477}
478
479/* ----------------------------------------------------------------------------
480 * int yylex()
481 *
482 * Gets the lexene and returns tokens.
483 * ------------------------------------------------------------------------- */
484
485int yylex(void) {
486
487  int l;
488  char *yytext;
489
490  if (!scan_init) {
491    scanner_init();
492  }
493
494  if (next_token) {
495    l = next_token;
496    next_token = 0;
497    return l;
498  }
499
500  l = yylook();
501
502  /*   Printf(stdout, "%s:%d:::%d: '%s'\n", cparse_file, cparse_line, l, Scanner_text(scan)); */
503
504  if (l == NONID) {
505    last_id = 1;
506  } else {
507    last_id = 0;
508  }
509
510  /* We got some sort of non-white space object.  We set the start_line
511     variable unless it has already been set */
512
513  if (!cparse_start_line) {
514    cparse_start_line = cparse_line;
515  }
516
517  /* Copy the lexene */
518
519  switch (l) {
520
521  case NUM_INT:
522  case NUM_FLOAT:
523  case NUM_ULONG:
524  case NUM_LONG:
525  case NUM_UNSIGNED:
526  case NUM_LONGLONG:
527  case NUM_ULONGLONG:
528    if (l == NUM_INT)
529      yylval.dtype.type = T_INT;
530    if (l == NUM_FLOAT)
531      yylval.dtype.type = T_DOUBLE;
532    if (l == NUM_ULONG)
533      yylval.dtype.type = T_ULONG;
534    if (l == NUM_LONG)
535      yylval.dtype.type = T_LONG;
536    if (l == NUM_UNSIGNED)
537      yylval.dtype.type = T_UINT;
538    if (l == NUM_LONGLONG)
539      yylval.dtype.type = T_LONGLONG;
540    if (l == NUM_ULONGLONG)
541      yylval.dtype.type = T_ULONGLONG;
542    yylval.dtype.val = NewString(Scanner_text(scan));
543    yylval.dtype.bitfield = 0;
544    yylval.dtype.throws = 0;
545    return (l);
546
547  case ID:
548    yytext = Char(Scanner_text(scan));
549    if (yytext[0] != '%') {
550      /* Look for keywords now */
551
552      if (strcmp(yytext, "int") == 0) {
553	yylval.type = NewSwigType(T_INT);
554	return (TYPE_INT);
555      }
556      if (strcmp(yytext, "double") == 0) {
557	yylval.type = NewSwigType(T_DOUBLE);
558	return (TYPE_DOUBLE);
559      }
560      if (strcmp(yytext, "void") == 0) {
561	yylval.type = NewSwigType(T_VOID);
562	return (TYPE_VOID);
563      }
564      if (strcmp(yytext, "char") == 0) {
565	yylval.type = NewSwigType(T_CHAR);
566	return (TYPE_CHAR);
567      }
568      if (strcmp(yytext, "wchar_t") == 0) {
569	yylval.type = NewSwigType(T_WCHAR);
570	return (TYPE_WCHAR);
571      }
572      if (strcmp(yytext, "short") == 0) {
573	yylval.type = NewSwigType(T_SHORT);
574	return (TYPE_SHORT);
575      }
576      if (strcmp(yytext, "long") == 0) {
577	yylval.type = NewSwigType(T_LONG);
578	return (TYPE_LONG);
579      }
580      if (strcmp(yytext, "float") == 0) {
581	yylval.type = NewSwigType(T_FLOAT);
582	return (TYPE_FLOAT);
583      }
584      if (strcmp(yytext, "signed") == 0) {
585	yylval.type = NewSwigType(T_INT);
586	return (TYPE_SIGNED);
587      }
588      if (strcmp(yytext, "unsigned") == 0) {
589	yylval.type = NewSwigType(T_UINT);
590	return (TYPE_UNSIGNED);
591      }
592      if (strcmp(yytext, "bool") == 0) {
593	yylval.type = NewSwigType(T_BOOL);
594	return (TYPE_BOOL);
595      }
596
597      /* Non ISO (Windows) C extensions */
598      if (strcmp(yytext, "__int8") == 0) {
599	yylval.type = NewString(yytext);
600	return (TYPE_NON_ISO_INT8);
601      }
602      if (strcmp(yytext, "__int16") == 0) {
603	yylval.type = NewString(yytext);
604	return (TYPE_NON_ISO_INT16);
605      }
606      if (strcmp(yytext, "__int32") == 0) {
607	yylval.type = NewString(yytext);
608	return (TYPE_NON_ISO_INT32);
609      }
610      if (strcmp(yytext, "__int64") == 0) {
611	yylval.type = NewString(yytext);
612	return (TYPE_NON_ISO_INT64);
613      }
614
615      /* C++ keywords */
616      if (cparse_cplusplus) {
617	if (strcmp(yytext, "and") == 0)
618	  return (LAND);
619	if (strcmp(yytext, "or") == 0)
620	  return (LOR);
621	if (strcmp(yytext, "not") == 0)
622	  return (LNOT);
623	if (strcmp(yytext, "class") == 0)
624	  return (CLASS);
625	if (strcmp(yytext, "private") == 0)
626	  return (PRIVATE);
627	if (strcmp(yytext, "public") == 0)
628	  return (PUBLIC);
629	if (strcmp(yytext, "protected") == 0)
630	  return (PROTECTED);
631	if (strcmp(yytext, "friend") == 0)
632	  return (FRIEND);
633	if (strcmp(yytext, "virtual") == 0)
634	  return (VIRTUAL);
635	if (strcmp(yytext, "operator") == 0) {
636	  int nexttok;
637	  String *s = NewString("operator ");
638
639	  /* If we have an operator, we have to collect the operator symbol and attach it to
640             the operator identifier.   To do this, we need to scan ahead by several tokens.
641             Cases include:
642
643             (1) If the next token is an operator as determined by Scanner_isoperator(),
644                 it means that the operator applies to one of the standard C++ mathematical,
645                 assignment, or logical operator symbols (e.g., '+','<=','==','&', etc.)
646                 In this case, we merely append the symbol text to the operator string above.
647
648             (2) If the next token is (, we look for ).  This is operator ().
649             (3) If the next token is [, we look for ].  This is operator [].
650	     (4) If the next token is an identifier.  The operator is possibly a conversion operator.
651                      (a) Must check for special case new[] and delete[]
652
653             Error handling is somewhat tricky here.  We'll try to back out gracefully if we can.
654
655	  */
656
657	  nexttok = Scanner_token(scan);
658	  if (Scanner_isoperator(nexttok)) {
659	    /* One of the standard C/C++ symbolic operators */
660	    Append(s,Scanner_text(scan));
661	    yylval.str = s;
662	    return OPERATOR;
663	  } else if (nexttok == SWIG_TOKEN_LPAREN) {
664	    /* Function call operator.  The next token MUST be a RPAREN */
665	    nexttok = Scanner_token(scan);
666	    if (nexttok != SWIG_TOKEN_RPAREN) {
667	      Swig_error(Scanner_file(scan),Scanner_line(scan),"Syntax error. Bad operator name.\n");
668	    } else {
669	      Append(s,"()");
670	      yylval.str = s;
671	      return OPERATOR;
672	    }
673	  } else if (nexttok == SWIG_TOKEN_LBRACKET) {
674	    /* Array access operator.  The next token MUST be a RBRACKET */
675	    nexttok = Scanner_token(scan);
676	    if (nexttok != SWIG_TOKEN_RBRACKET) {
677	      Swig_error(Scanner_file(scan),Scanner_line(scan),"Syntax error. Bad operator name.\n");
678	    } else {
679	      Append(s,"[]");
680	      yylval.str = s;
681	      return OPERATOR;
682	    }
683	  } else if (nexttok == SWIG_TOKEN_ID) {
684	    /* We have an identifier.  This could be any number of things. It could be a named version of
685               an operator (e.g., 'and_eq') or it could be a conversion operator.   To deal with this, we're
686               going to read tokens until we encounter a ( or ;.  Some care is needed for formatting. */
687	    int needspace = 1;
688	    int termtoken = 0;
689	    const char *termvalue = 0;
690
691	    Append(s,Scanner_text(scan));
692	    while (1) {
693
694	      nexttok = Scanner_token(scan);
695	      if (nexttok <= 0) {
696		Swig_error(Scanner_file(scan),Scanner_line(scan),"Syntax error. Bad operator name.\n");
697	      }
698	      if (nexttok == SWIG_TOKEN_LPAREN) {
699		termtoken = SWIG_TOKEN_LPAREN;
700		termvalue = "(";
701		break;
702              } else if (nexttok == SWIG_TOKEN_CODEBLOCK) {
703                termtoken = SWIG_TOKEN_CODEBLOCK;
704                termvalue = Char(Scanner_text(scan));
705                break;
706              } else if (nexttok == SWIG_TOKEN_LBRACE) {
707                termtoken = SWIG_TOKEN_LBRACE;
708                termvalue = "{";
709                break;
710              } else if (nexttok == SWIG_TOKEN_SEMI) {
711		termtoken = SWIG_TOKEN_SEMI;
712		termvalue = ";";
713		break;
714              } else if (nexttok == SWIG_TOKEN_STRING) {
715		termtoken = SWIG_TOKEN_STRING;
716                termvalue = Swig_copy_string(Char(Scanner_text(scan)));
717		break;
718	      } else if (nexttok == SWIG_TOKEN_ID) {
719		if (needspace) {
720		  Append(s," ");
721		}
722		Append(s,Scanner_text(scan));
723	      } else {
724		Append(s,Scanner_text(scan));
725		needspace = 0;
726	      }
727	    }
728	    yylval.str = s;
729	    if (!rename_active) {
730	      String *cs;
731	      char *t = Char(s) + 9;
732	      if (!((strcmp(t, "new") == 0)
733		    || (strcmp(t, "delete") == 0)
734		    || (strcmp(t, "new[]") == 0)
735		    || (strcmp(t, "delete[]") == 0)
736		    || (strcmp(t, "and") == 0)
737		    || (strcmp(t, "and_eq") == 0)
738		    || (strcmp(t, "bitand") == 0)
739		    || (strcmp(t, "bitor") == 0)
740		    || (strcmp(t, "compl") == 0)
741		    || (strcmp(t, "not") == 0)
742		    || (strcmp(t, "not_eq") == 0)
743		    || (strcmp(t, "or") == 0)
744		    || (strcmp(t, "or_eq") == 0)
745		    || (strcmp(t, "xor") == 0)
746		    || (strcmp(t, "xor_eq") == 0)
747		    )) {
748		/*              retract(strlen(t)); */
749
750		/* The operator is a conversion operator.   In order to deal with this, we need to feed the
751                   type information back into the parser.  For now this is a hack.  Needs to be cleaned up later. */
752		cs = NewString(t);
753		if (termtoken) Append(cs,termvalue);
754		Seek(cs,0,SEEK_SET);
755		Setline(cs,cparse_line);
756		Setfile(cs,cparse_file);
757		Scanner_push(scan,cs);
758		Delete(cs);
759		return COPERATOR;
760	      }
761	    }
762	    if (termtoken)
763              Scanner_pushtoken(scan, termtoken, termvalue);
764	    return (OPERATOR);
765	  }
766	}
767	if (strcmp(yytext, "throw") == 0)
768	  return (THROW);
769	if (strcmp(yytext, "try") == 0)
770	  return (yylex());
771	if (strcmp(yytext, "catch") == 0)
772	  return (CATCH);
773	if (strcmp(yytext, "inline") == 0)
774	  return (yylex());
775	if (strcmp(yytext, "mutable") == 0)
776	  return (yylex());
777	if (strcmp(yytext, "explicit") == 0)
778	  return (EXPLICIT);
779	if (strcmp(yytext, "export") == 0)
780	  return (yylex());
781	if (strcmp(yytext, "typename") == 0)
782	  return (TYPENAME);
783	if (strcmp(yytext, "template") == 0) {
784	  yylval.ivalue = cparse_line;
785	  return (TEMPLATE);
786	}
787	if (strcmp(yytext, "delete") == 0) {
788	  return (DELETE_KW);
789	}
790	if (strcmp(yytext, "using") == 0) {
791	  return (USING);
792	}
793	if (strcmp(yytext, "namespace") == 0) {
794	  return (NAMESPACE);
795	}
796      } else {
797	if (strcmp(yytext, "class") == 0) {
798	  Swig_warning(WARN_PARSE_CLASS_KEYWORD, cparse_file, cparse_line, "class keyword used, but not in C++ mode.\n");
799	}
800	if (strcmp(yytext, "complex") == 0) {
801	  yylval.type = NewSwigType(T_COMPLEX);
802	  return (TYPE_COMPLEX);
803	}
804	if (strcmp(yytext, "restrict") == 0)
805	  return (yylex());
806      }
807
808      /* Misc keywords */
809
810      if (strcmp(yytext, "extern") == 0)
811	return (EXTERN);
812      if (strcmp(yytext, "const") == 0)
813	return (CONST_QUAL);
814      if (strcmp(yytext, "static") == 0)
815	return (STATIC);
816      if (strcmp(yytext, "struct") == 0)
817	return (STRUCT);
818      if (strcmp(yytext, "union") == 0)
819	return (UNION);
820      if (strcmp(yytext, "enum") == 0)
821	return (ENUM);
822      if (strcmp(yytext, "sizeof") == 0)
823	return (SIZEOF);
824
825      if (strcmp(yytext, "typedef") == 0) {
826	yylval.ivalue = 0;
827	return (TYPEDEF);
828      }
829
830      /* Ignored keywords */
831
832      if (strcmp(yytext, "volatile") == 0)
833	return (VOLATILE);
834      if (strcmp(yytext, "register") == 0)
835	return (REGISTER);
836      if (strcmp(yytext, "inline") == 0)
837	return (yylex());
838
839      /* SWIG directives */
840    } else {
841      if (strcmp(yytext, "%module") == 0)
842	return (MODULE);
843      if (strcmp(yytext, "%insert") == 0)
844	return (INSERT);
845      if (strcmp(yytext, "%name") == 0)
846	return (NAME);
847      if (strcmp(yytext, "%rename") == 0) {
848	rename_active = 1;
849	return (RENAME);
850      }
851      if (strcmp(yytext, "%namewarn") == 0) {
852	rename_active = 1;
853	return (NAMEWARN);
854      }
855      if (strcmp(yytext, "%includefile") == 0)
856	return (INCLUDE);
857      if (strcmp(yytext, "%val") == 0) {
858	Swig_warning(WARN_DEPRECATED_VAL, cparse_file, cparse_line, "%%val directive deprecated (ignored).\n");
859	return (yylex());
860      }
861      if (strcmp(yytext, "%out") == 0) {
862	Swig_warning(WARN_DEPRECATED_OUT, cparse_file, cparse_line, "%%out directive deprecated (ignored).\n");
863	return (yylex());
864      }
865      if (strcmp(yytext, "%constant") == 0)
866	return (CONSTANT);
867      if (strcmp(yytext, "%typedef") == 0) {
868	yylval.ivalue = 1;
869	return (TYPEDEF);
870      }
871      if (strcmp(yytext, "%native") == 0)
872	return (NATIVE);
873      if (strcmp(yytext, "%pragma") == 0)
874	return (PRAGMA);
875      if (strcmp(yytext, "%extend") == 0)
876	return (EXTEND);
877      if (strcmp(yytext, "%fragment") == 0)
878	return (FRAGMENT);
879      if (strcmp(yytext, "%inline") == 0)
880	return (INLINE);
881      if (strcmp(yytext, "%typemap") == 0)
882	return (TYPEMAP);
883      if (strcmp(yytext, "%feature") == 0) {
884        /* The rename_active indicates we don't need the information of the
885         * following function's return type. This applied for %rename, so do
886         * %feature.
887         */
888        rename_active = 1;
889	return (FEATURE);
890      }
891      if (strcmp(yytext, "%except") == 0)
892	return (EXCEPT);
893      if (strcmp(yytext, "%importfile") == 0)
894	return (IMPORT);
895      if (strcmp(yytext, "%echo") == 0)
896	return (ECHO);
897      if (strcmp(yytext, "%apply") == 0)
898	return (APPLY);
899      if (strcmp(yytext, "%clear") == 0)
900	return (CLEAR);
901      if (strcmp(yytext, "%types") == 0)
902	return (TYPES);
903      if (strcmp(yytext, "%parms") == 0)
904	return (PARMS);
905      if (strcmp(yytext, "%varargs") == 0)
906	return (VARARGS);
907      if (strcmp(yytext, "%template") == 0) {
908	return (SWIGTEMPLATE);
909      }
910      if (strcmp(yytext, "%warn") == 0)
911	return (WARN);
912    }
913    /* Have an unknown identifier, as a last step, we'll do a typedef lookup on it. */
914
915    /* Need to fix this */
916    if (check_typedef) {
917      if (SwigType_istypedef(yytext)) {
918	yylval.type = NewString(yytext);
919	return (TYPE_TYPEDEF);
920      }
921    }
922    yylval.id = Swig_copy_string(yytext);
923    last_id = 1;
924    return (ID);
925  case POUND:
926    return yylex();
927  default:
928    return (l);
929  }
930}
931