PageRenderTime 69ms CodeModel.GetById 2ms app.highlight 59ms RepoModel.GetById 1ms app.codeStats 0ms

/trunk/Source/Swig/scanner.c

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