PageRenderTime 71ms CodeModel.GetById 20ms app.highlight 43ms RepoModel.GetById 1ms app.codeStats 0ms

/trunk/Source/CParse/cscanner.c

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