special cases and other things in wxPython, and since I plan on making several more, I've decided to put the SWIG sources in wxPython's CVS instead of relying on maintaining patches. This effectivly becomes a fork of an obsolete version of SWIG, :-( but since SWIG 1.3 still doesn't have some things I rely on in 1.1, not to mention that my custom patches would all have to be redone, I felt that this is the easier road to take. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@15307 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
		
			
				
	
	
		
			1382 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1382 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*******************************************************************************
 | 
						|
 * Simplified Wrapper and Interface Generator  (SWIG)
 | 
						|
 * 
 | 
						|
 * Author : David Beazley
 | 
						|
 *
 | 
						|
 * Department of Computer Science        
 | 
						|
 * University of Chicago
 | 
						|
 * 1100 E 58th Street
 | 
						|
 * Chicago, IL  60637
 | 
						|
 * beazley@cs.uchicago.edu
 | 
						|
 *
 | 
						|
 * Please read the file LICENSE for the copyright and terms by which SWIG
 | 
						|
 * can be used and distributed.
 | 
						|
 *******************************************************************************/
 | 
						|
 | 
						|
/*************************************************************************
 | 
						|
 * $Header$
 | 
						|
 * scanner.c
 | 
						|
 *
 | 
						|
 * Dave Beazley
 | 
						|
 * January 1996
 | 
						|
 *
 | 
						|
 * Input scanner.   This scanner finds and returns tokens
 | 
						|
 * for the wrapper generator.   Since using lex/flex from
 | 
						|
 * C++ is so F'ed up, I've written this function to replace
 | 
						|
 * them entirely.     It's not as fast, but hopefully it will
 | 
						|
 * eliminate alot of compilation problems.
 | 
						|
 *
 | 
						|
 *************************************************************************/
 | 
						|
 | 
						|
 | 
						|
#include "internal.h"
 | 
						|
#include "parser.h"
 | 
						|
#include <string.h>
 | 
						|
#include <ctype.h>
 | 
						|
 | 
						|
#define  YYBSIZE  8192
 | 
						|
 | 
						|
struct InFile {
 | 
						|
  FILE   *f;
 | 
						|
  int    line_number;
 | 
						|
  char  *in_file;
 | 
						|
  int    extern_mode;	
 | 
						|
  int    force_extern;
 | 
						|
  struct InFile *prev;
 | 
						|
};
 | 
						|
 | 
						|
// This structure is used for managing code fragments as
 | 
						|
// might be used by the %inline directive and handling of
 | 
						|
// nested structures.
 | 
						|
 | 
						|
struct CodeFragment {
 | 
						|
  char          *text;
 | 
						|
  int            line_number;
 | 
						|
  CodeFragment  *next;
 | 
						|
};
 | 
						|
 | 
						|
InFile  *in_head;
 | 
						|
 | 
						|
FILE    *LEX_in = NULL;
 | 
						|
 | 
						|
static String         header;
 | 
						|
static String         comment;
 | 
						|
       String         CCode;              // String containing C code
 | 
						|
static char           *yybuffer;
 | 
						|
static int            lex_pos = 0;
 | 
						|
static int            lex_len = 0;         
 | 
						|
static char           *inline_yybuffer = 0;
 | 
						|
static int            inline_lex_pos = 0;
 | 
						|
static int            inline_lex_len = 0;
 | 
						|
static int            inline_line_number = 0;
 | 
						|
static CodeFragment  *fragments = 0;      // Code fragments
 | 
						|
 | 
						|
static 
 | 
						|
char           yytext[YYBSIZE];
 | 
						|
static int     yylen = 0;
 | 
						|
int            line_number = 1;
 | 
						|
int            column = 1;
 | 
						|
int            column_start = 1;
 | 
						|
char          *input_file;
 | 
						|
int            start_line = 0;
 | 
						|
static  int    comment_start;
 | 
						|
static  int    scan_init  = 0;
 | 
						|
static  int    num_brace = 0;
 | 
						|
static  int    last_brace = 0;
 | 
						|
static  int    in_define = 0;
 | 
						|
static  int    define_first_id = 0;   /* Set when looking for first identifier of a define */
 | 
						|
extern  int    Error;
 | 
						|
 | 
						|
 | 
						|
/**************************************************************
 | 
						|
 * scanner_init()
 | 
						|
 *
 | 
						|
 * Initialize buffers
 | 
						|
 **************************************************************/
 | 
						|
 | 
						|
void scanner_init() {
 | 
						|
 | 
						|
  yybuffer = (char *) malloc(YYBSIZE);
 | 
						|
  scan_init = 1;
 | 
						|
}
 | 
						|
 | 
						|
/**************************************************************
 | 
						|
 * scanner_file(FILE *f)
 | 
						|
 *
 | 
						|
 * Start reading from new file 
 | 
						|
 **************************************************************/
 | 
						|
void scanner_file(FILE *f) {
 | 
						|
  InFile *in;
 | 
						|
 | 
						|
  in = new InFile;
 | 
						|
  in->f = f;
 | 
						|
  in->in_file = input_file;
 | 
						|
  in->extern_mode = WrapExtern;	
 | 
						|
  in->force_extern = ForceExtern;
 | 
						|
  if (in_head) in_head->line_number = line_number+1;
 | 
						|
  if (!in_head) in->prev = 0;
 | 
						|
  else in->prev = in_head;
 | 
						|
  in_head = in;
 | 
						|
  LEX_in = f;
 | 
						|
  line_number = 1;
 | 
						|
}
 | 
						|
 | 
						|
/**************************************************************
 | 
						|
 * scanner_close()
 | 
						|
 *
 | 
						|
 * Close current input file and go to next 
 | 
						|
 **************************************************************/
 | 
						|
 | 
						|
void scanner_close() {
 | 
						|
 | 
						|
  InFile *p;
 | 
						|
  static int lib_insert = 0;
 | 
						|
  fclose(LEX_in);
 | 
						|
  if (!in_head) return;
 | 
						|
  p = in_head->prev;
 | 
						|
  if (p != 0) {
 | 
						|
    LEX_in = p->f;
 | 
						|
    line_number = p->line_number;
 | 
						|
    input_file = p->in_file;
 | 
						|
    WrapExtern = p->extern_mode;
 | 
						|
    if (!WrapExtern) remove_symbol("SWIGEXTERN");
 | 
						|
    ForceExtern = p->force_extern;
 | 
						|
  } else {
 | 
						|
    LEX_in = NULL;
 | 
						|
  }
 | 
						|
  delete in_head;
 | 
						|
  in_head = p;
 | 
						|
 | 
						|
  // if LEX_in is NULL it means we're done with the interface file. We're now
 | 
						|
  // going to grab all of the library files.
 | 
						|
 | 
						|
  if ((!LEX_in) && (!lib_insert)) {
 | 
						|
    library_insert();
 | 
						|
    lib_insert = 1;
 | 
						|
  }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/**************************************************************
 | 
						|
 * char nextchar()
 | 
						|
 *
 | 
						|
 * gets next character from input.
 | 
						|
 * If we're in inlining mode, we actually retrieve a character
 | 
						|
 * from inline_yybuffer instead.
 | 
						|
 **************************************************************/
 | 
						|
 | 
						|
char nextchar() {
 | 
						|
 | 
						|
    char c = 0;
 | 
						|
 | 
						|
    if (Inline) {
 | 
						|
      if (inline_lex_pos >= inline_lex_len) {
 | 
						|
	// Done with inlined code.  Check to see if we have any
 | 
						|
	// new code fragments.  If so, switch to them.
 | 
						|
	delete inline_yybuffer;
 | 
						|
	if (fragments) {
 | 
						|
	  CodeFragment *f;
 | 
						|
	  inline_yybuffer = fragments->text;
 | 
						|
	  inline_lex_pos = 1;
 | 
						|
	  inline_lex_len = strlen(fragments->text);
 | 
						|
	  line_number = fragments->line_number;
 | 
						|
	  f = fragments->next;
 | 
						|
	  delete fragments;
 | 
						|
	  fragments = f;
 | 
						|
	  c = inline_yybuffer[0];
 | 
						|
	} else {
 | 
						|
	  c = 0;
 | 
						|
	  Inline = 0;
 | 
						|
	  line_number = inline_line_number;       // Restore old line number
 | 
						|
	}
 | 
						|
      } else {
 | 
						|
	inline_lex_pos++;
 | 
						|
	c = inline_yybuffer[inline_lex_pos-1];
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (!Inline) {
 | 
						|
      if (lex_pos >= lex_len) {
 | 
						|
	if (!LEX_in) {
 | 
						|
	  SWIG_exit(1);
 | 
						|
	}
 | 
						|
	while(fgets(yybuffer, YYBSIZE, LEX_in) == NULL) {
 | 
						|
	  scanner_close();        // Close current input file
 | 
						|
	  if (!LEX_in) return 0;  // No more, we're outta here
 | 
						|
	}
 | 
						|
	lex_len = strlen(yybuffer);
 | 
						|
	lex_pos = 0;
 | 
						|
      }
 | 
						|
      
 | 
						|
      lex_pos++;
 | 
						|
      c = yybuffer[lex_pos-1];
 | 
						|
    }
 | 
						|
      
 | 
						|
    if (yylen >= YYBSIZE) {
 | 
						|
      fprintf(stderr,"** FATAL ERROR.  Buffer overflow in scanner.cxx.\nReport this to swig@cs.utah.edu.\n");
 | 
						|
      SWIG_exit(1);
 | 
						|
    }
 | 
						|
    yytext[yylen] = c;
 | 
						|
    yylen++;
 | 
						|
    if (c == '\n') {
 | 
						|
      line_number++;
 | 
						|
      column = 1;
 | 
						|
    } else {
 | 
						|
      column++;
 | 
						|
    }
 | 
						|
    return(c);
 | 
						|
}
 | 
						|
 | 
						|
void retract(int n) {
 | 
						|
  int i, j, c;
 | 
						|
  
 | 
						|
  for (i = 0; i < n; i++) {
 | 
						|
    if (Inline) {
 | 
						|
      inline_lex_pos--;
 | 
						|
      if (inline_lex_pos < 0) {
 | 
						|
	fprintf(stderr,"Internal scanner error. inline_lex_pos < 0\n");
 | 
						|
	SWIG_exit(1);
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else lex_pos--;
 | 
						|
    yylen--;
 | 
						|
    column--;
 | 
						|
    if (yylen >= 0) {
 | 
						|
      if (yytext[yylen] == '\n') {
 | 
						|
	line_number--;
 | 
						|
	// Figure out what column we're in
 | 
						|
	c = yylen-1;
 | 
						|
	j = 1;
 | 
						|
	while (c >= 0){
 | 
						|
	  if (yytext[c] == '\n') break;
 | 
						|
	  j++;
 | 
						|
	  c--;
 | 
						|
	}
 | 
						|
	column = j;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (yylen < 0) yylen = 0;
 | 
						|
}
 | 
						|
 | 
						|
/**************************************************************
 | 
						|
 * start_inline(char *text, int line)
 | 
						|
 * 
 | 
						|
 * This grabs a chunk of text and tries to inline it into
 | 
						|
 * the current file.  (This is kind of wild, but cool when
 | 
						|
 * it works).
 | 
						|
 *
 | 
						|
 * If we're already in inlining mode, we will save the code
 | 
						|
 * as a new fragment.
 | 
						|
 **************************************************************/
 | 
						|
 | 
						|
void start_inline(char *text, int line) {
 | 
						|
 | 
						|
  if (Inline) {
 | 
						|
 | 
						|
    // Already processing a code fragment, simply hang on
 | 
						|
    // to this one for later.
 | 
						|
 | 
						|
    CodeFragment *f,*f1;
 | 
						|
 | 
						|
    // Add a new code fragment to our list
 | 
						|
    f = new CodeFragment;
 | 
						|
    f->text = copy_string(text);
 | 
						|
    f->line_number = line;
 | 
						|
    f->next = 0;
 | 
						|
    if (!fragments) fragments = f;
 | 
						|
    else {
 | 
						|
      f1 = fragments;
 | 
						|
      while (f1->next) f1 = f1->next;
 | 
						|
      f1->next = f;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
 | 
						|
    // Switch our scanner over to process text from a string.
 | 
						|
    // Save current line number and other information however.
 | 
						|
 | 
						|
    inline_yybuffer = copy_string(text);
 | 
						|
    inline_lex_len = strlen(text);
 | 
						|
    inline_lex_pos = 0;
 | 
						|
    inline_line_number = line_number;       // Make copy of old line number
 | 
						|
    line_number = line;
 | 
						|
    Inline = 1;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**************************************************************
 | 
						|
 * yycomment(char *, int line)
 | 
						|
 *
 | 
						|
 * Inserts a comment into a documentation entry.    
 | 
						|
 **************************************************************/
 | 
						|
 | 
						|
void yycomment(char *s, int line, int col) {
 | 
						|
  comment_handler->add_comment(s,line,col,input_file);
 | 
						|
}
 | 
						|
 | 
						|
/**************************************************************
 | 
						|
 * void skip_brace(void)
 | 
						|
 *
 | 
						|
 * Found a {.
 | 
						|
 * Skip all characters until we find a matching closed }.
 | 
						|
 *
 | 
						|
 * This function is used to skip over inlined C code and other
 | 
						|
 * garbage found in interface files.
 | 
						|
 ***************************************************************/
 | 
						|
 | 
						|
void skip_brace(void) {
 | 
						|
 | 
						|
  char c;
 | 
						|
  CCode = "{";
 | 
						|
  while (num_brace > last_brace) {
 | 
						|
    if ((c = nextchar()) == 0) {
 | 
						|
      fprintf(stderr,"%s : Line %d.  Missing '}'. Reached end of input.\n",
 | 
						|
	      input_file, line_number);
 | 
						|
      FatalError();
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    CCode << c;
 | 
						|
    if (c == '{') num_brace++;
 | 
						|
    if (c == '}') num_brace--;
 | 
						|
    yylen = 0;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**************************************************************
 | 
						|
 * void skip_template(void)
 | 
						|
 *
 | 
						|
 * Found a <.
 | 
						|
 * Skip all characters until we find a matching closed >.
 | 
						|
 *
 | 
						|
 * This function is used to skip over C++ templated types
 | 
						|
 * and objective-C protocols.
 | 
						|
 ***************************************************************/
 | 
						|
 | 
						|
void skip_template(void) {
 | 
						|
 | 
						|
  char c;
 | 
						|
  CCode = "<";
 | 
						|
  int  num_lt = 1;
 | 
						|
  while (num_lt > 0) {
 | 
						|
    if ((c = nextchar()) == 0) {
 | 
						|
      fprintf(stderr,"%s : Line %d.  Missing '>'. Reached end of input.\n",
 | 
						|
	      input_file, line_number);
 | 
						|
      FatalError();
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    CCode << c;
 | 
						|
    if (c == '<') num_lt++;
 | 
						|
    if (c == '>') num_lt--;
 | 
						|
    yylen = 0;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**************************************************************
 | 
						|
 * void skip_to_end(void)
 | 
						|
 *
 | 
						|
 * Skips to the @end directive in a Objective-C definition
 | 
						|
 **************************************************************/
 | 
						|
 | 
						|
void skip_to_end(void) {
 | 
						|
  char c;
 | 
						|
  int  state = 0;
 | 
						|
  yylen = 0;
 | 
						|
  while ((c = nextchar())){
 | 
						|
    switch(state) {
 | 
						|
    case 0:
 | 
						|
      if (c == '@') state = 1;
 | 
						|
      else yylen = 0;
 | 
						|
      break;
 | 
						|
    case 1:
 | 
						|
      if (isspace(c)) {
 | 
						|
	if (strncmp(yytext,"@end",4) == 0) return; 
 | 
						|
	else {
 | 
						|
	  yylen = 0;
 | 
						|
	  state = 0;
 | 
						|
	}
 | 
						|
      } else {
 | 
						|
	state = 1;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  fprintf(stderr,"%s : EOF. Missing @end. Reached end of input.\n",
 | 
						|
	  input_file);
 | 
						|
  FatalError();
 | 
						|
  return;
 | 
						|
}  
 | 
						|
 | 
						|
/**************************************************************
 | 
						|
 * void skip_decl(void)
 | 
						|
 *
 | 
						|
 * This tries to skip over an entire declaration.   For example
 | 
						|
 *
 | 
						|
 *  friend ostream& operator<<(ostream&, const char *s);
 | 
						|
 * 
 | 
						|
 * or 
 | 
						|
 *  friend ostream& operator<<(ostream&, const char *s) { };
 | 
						|
 *
 | 
						|
 **************************************************************/
 | 
						|
 | 
						|
void skip_decl(void) {
 | 
						|
  char c;
 | 
						|
  int  done = 0;
 | 
						|
  while (!done) {
 | 
						|
    if ((c = nextchar()) == 0) {
 | 
						|
      fprintf(stderr,"%s : Line %d.  Missing semicolon. Reached end of input.\n",
 | 
						|
	      input_file, line_number);
 | 
						|
      FatalError();
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    if (c == '{') {
 | 
						|
      last_brace = num_brace;
 | 
						|
      num_brace++;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    yylen = 0;
 | 
						|
    if (c == ';') done = 1;
 | 
						|
  }
 | 
						|
  if (!done) {
 | 
						|
    while (num_brace > last_brace) {
 | 
						|
      if ((c = nextchar()) == 0) {
 | 
						|
	fprintf(stderr,"%s : Line %d.  Missing '}'. Reached end of input.\n",
 | 
						|
		input_file, line_number);
 | 
						|
	FatalError();
 | 
						|
	return;
 | 
						|
      }
 | 
						|
      if (c == '{') num_brace++;
 | 
						|
      if (c == '}') num_brace--;
 | 
						|
      yylen = 0;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**************************************************************
 | 
						|
 * void skip_define(void)
 | 
						|
 *
 | 
						|
 * Skips to the end of a #define statement.
 | 
						|
 *
 | 
						|
 **************************************************************/
 | 
						|
 | 
						|
void skip_define(void) {
 | 
						|
  char c;
 | 
						|
  while (in_define) {
 | 
						|
    if ((c = nextchar()) == 0) return;
 | 
						|
    if (c == '\\') in_define = 2;
 | 
						|
    if (c == '\n') {
 | 
						|
      if (in_define == 2) {
 | 
						|
	in_define = 1;
 | 
						|
      } else if (in_define == 1) {
 | 
						|
	in_define = 0;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    yylen = 0;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**************************************************************
 | 
						|
 * int skip_cond(int inthen)
 | 
						|
 *
 | 
						|
 * Skips the false portion of an #ifdef directive.   Looks
 | 
						|
 * for either a matching #else or #endif 
 | 
						|
 *
 | 
						|
 * inthen is 0 or 1 depending on whether or not we're
 | 
						|
 * handling the "then" or "else" part of a conditional.
 | 
						|
 *
 | 
						|
 * Returns 1 if the else part of the #if-#endif block was
 | 
						|
 * reached.  Returns 0 otherwise.  Returns -1 on error.
 | 
						|
 **************************************************************/
 | 
						|
 | 
						|
int skip_cond(int inthen) {
 | 
						|
  int    level = 0;         /* Used to handled nested if-then-else */
 | 
						|
  int    state = 0;
 | 
						|
  char   c;
 | 
						|
  int    start_line;
 | 
						|
  char  *file;
 | 
						|
  
 | 
						|
  file = copy_string(input_file);
 | 
						|
  start_line = line_number;
 | 
						|
  yylen = 0;
 | 
						|
 | 
						|
  while(1) {
 | 
						|
    switch(state) {
 | 
						|
    case 0 :
 | 
						|
      if ((c = nextchar()) == 0) {
 | 
						|
	fprintf(stderr,"%s : Line %d.  Unterminated #if-else directive.\n", file, start_line);
 | 
						|
	FatalError();
 | 
						|
	return -1;     /* Error */
 | 
						|
      }
 | 
						|
      if ((c == '#') || (c == '%')) {
 | 
						|
	state = 1;
 | 
						|
      } else if (isspace(c)) {
 | 
						|
	yylen =0;
 | 
						|
	state = 0;
 | 
						|
      } else {
 | 
						|
	/* Some non-whitespace character. Look for line end */
 | 
						|
	yylen = 0;
 | 
						|
	state = 3;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case 1:
 | 
						|
      /* Beginning of a C preprocessor statement */
 | 
						|
      if ((c = nextchar()) == 0) {
 | 
						|
	fprintf(stderr,"%s : Line %d.  Unterminated #if-else directive.\n", file, start_line);
 | 
						|
	FatalError();
 | 
						|
	return -1;     /* Error */
 | 
						|
      }
 | 
						|
      if (c == '\n') {
 | 
						|
	state = 0;
 | 
						|
	yylen = 0;
 | 
						|
      }
 | 
						|
      else if (isspace(c)) {
 | 
						|
	state = 1;
 | 
						|
	yylen--;
 | 
						|
      } else {
 | 
						|
	state = 2;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case 2:
 | 
						|
      /* CPP directive */
 | 
						|
      if ((c = nextchar()) == 0)  {
 | 
						|
	fprintf(stderr,"%s : Line %d.  Unterminated #if-else directive.\n", file, start_line);
 | 
						|
	FatalError();
 | 
						|
	return -1;     /* Error */
 | 
						|
      }
 | 
						|
      if ((c == ' ') || (c == '\t') || (c=='\n')) {
 | 
						|
	yytext[yylen-1] = 0;
 | 
						|
	if ((strcmp(yytext,"#ifdef") == 0) || (strcmp(yytext,"%ifdef") == 0)) {
 | 
						|
	  level++;
 | 
						|
	  state = 0;
 | 
						|
	} else if ((strcmp(yytext,"#ifndef") == 0) || (strcmp(yytext,"%ifndef") == 0)) {
 | 
						|
	  level++;
 | 
						|
	  state = 0;
 | 
						|
	} else if ((strcmp(yytext,"#if") == 0) || (strcmp(yytext,"%if") == 0)) {
 | 
						|
	  level++;
 | 
						|
	  state = 0;
 | 
						|
	} else if ((strcmp(yytext,"#else") == 0) || (strcmp(yytext,"%else") == 0)) {
 | 
						|
	  if (level == 0) {    /* Found matching else.  exit */
 | 
						|
	    if (!inthen) {
 | 
						|
	      /* Hmmm.  We've got an "extra #else" directive here */
 | 
						|
	      fprintf(stderr,"%s : Line %d.  Misplaced #else.\n", input_file, line_number);
 | 
						|
	      FatalError();
 | 
						|
	      yylen = 0;
 | 
						|
	      state = 0;
 | 
						|
	    } else {
 | 
						|
	      yylen = 0;
 | 
						|
	      delete file;
 | 
						|
	      return 1;
 | 
						|
	    }
 | 
						|
	  } else {
 | 
						|
	    yylen = 0;
 | 
						|
	    state = 0;
 | 
						|
	  }
 | 
						|
	} else if ((strcmp(yytext,"#endif") == 0) || (strcmp(yytext,"%endif") == 0)) {
 | 
						|
	  if (level <= 0) {    /* Found matching endif. exit */
 | 
						|
	    yylen = 0;
 | 
						|
	    delete file;
 | 
						|
	    return 0;
 | 
						|
	  } else {
 | 
						|
	    state = 0;
 | 
						|
	    yylen = 0;
 | 
						|
	    level--;
 | 
						|
	  }
 | 
						|
	} else if ((strcmp(yytext,"#elif") == 0) || (strcmp(yytext,"%elif") == 0)) {
 | 
						|
	  if (level <= 0) {
 | 
						|
	    // If we come across this, we pop it back onto the input queue and return
 | 
						|
	    retract(6);
 | 
						|
	    delete file;
 | 
						|
	    return 0;
 | 
						|
	  } else {
 | 
						|
	    yylen = 0;
 | 
						|
	    state = 0;
 | 
						|
	  }
 | 
						|
	} else {
 | 
						|
	  yylen = 0;
 | 
						|
	  state = 0;
 | 
						|
	}
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case 3:
 | 
						|
      /* Non-white space.  Look for line break */
 | 
						|
      if ((c = nextchar()) == 0) {
 | 
						|
	fprintf(stderr,"%s : Line %d.  Unterminated #if directive.\n", file, start_line);
 | 
						|
	FatalError();
 | 
						|
	return -1;     /* Error */
 | 
						|
      }
 | 
						|
      if (c == '\n') {
 | 
						|
	yylen = 0;
 | 
						|
	state = 0;
 | 
						|
      } else {
 | 
						|
	yylen = 0;
 | 
						|
	state = 3;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
      
 | 
						|
/**************************************************************
 | 
						|
 * int yylook()
 | 
						|
 *
 | 
						|
 * Lexical scanner.
 | 
						|
 * See Aho,Sethi, and Ullman,  pg. 106
 | 
						|
 **************************************************************/
 | 
						|
 | 
						|
int yylook(void) {
 | 
						|
 | 
						|
    int      state;
 | 
						|
    char     c = 0;
 | 
						|
 | 
						|
    state = 0;
 | 
						|
    yylen = 0;
 | 
						|
    while(1) {
 | 
						|
 | 
						|
/*	printf("State = %d\n", state);   */
 | 
						|
	switch(state) {
 | 
						|
 | 
						|
	case 0 :
 | 
						|
	  if((c = nextchar()) == 0) return(0);
 | 
						|
 | 
						|
	  /* Process delimeters */
 | 
						|
 | 
						|
	  if (c == '\n') {
 | 
						|
	    state = 0;
 | 
						|
	    yylen = 0;
 | 
						|
	    if (in_define == 1) {
 | 
						|
	      in_define = 0;
 | 
						|
	      return(ENDDEF);
 | 
						|
	    } else if (in_define == 2) {
 | 
						|
	      in_define = 1;
 | 
						|
	    }
 | 
						|
	  } else if (isspace(c)) {
 | 
						|
	    state = 0;
 | 
						|
	    yylen = 0;
 | 
						|
	  }
 | 
						|
	      
 | 
						|
	  /* Look for single character symbols */
 | 
						|
	      
 | 
						|
	  else if (c == '(') return (LPAREN);
 | 
						|
	  else if (c == ')') return (RPAREN);
 | 
						|
	  else if (c == ';') return (SEMI);
 | 
						|
	  else if (c == ',') return (COMMA);
 | 
						|
	  else if (c == '*') return (STAR);
 | 
						|
	  else if (c == '}') {
 | 
						|
	    num_brace--;
 | 
						|
	    if (num_brace < 0) {
 | 
						|
	      fprintf(stderr,"%s : Line %d. Error. Extraneous '}' (Ignored)\n",
 | 
						|
		      input_file, line_number);
 | 
						|
	      state = 0;
 | 
						|
	      num_brace = 0;
 | 
						|
	    } else {
 | 
						|
	      return (RBRACE);
 | 
						|
	    }
 | 
						|
	  }
 | 
						|
	  else if (c == '{') {
 | 
						|
	    last_brace = num_brace;
 | 
						|
	    num_brace++;
 | 
						|
	    return (LBRACE);
 | 
						|
	  }
 | 
						|
	  else if (c == '=') return (EQUAL);
 | 
						|
	  else if (c == '+') return (PLUS);
 | 
						|
          else if (c == '-') return (MINUS);
 | 
						|
	  else if (c == '&') return (AND);
 | 
						|
	  else if (c == '|') return (OR);
 | 
						|
	  else if (c == '^') return (XOR);
 | 
						|
          else if (c == '<') state = 60;
 | 
						|
	  else if (c == '>') state = 61;
 | 
						|
	  else if (c == '~') return (NOT);
 | 
						|
          else if (c == '!') return (LNOT);	                  
 | 
						|
	  else if (c == '\\') {
 | 
						|
	    if (in_define == 1) {
 | 
						|
	      in_define = 2;
 | 
						|
	      state = 0;
 | 
						|
	    } else 
 | 
						|
	      state = 99;
 | 
						|
	  }
 | 
						|
  	  else if (c == '[') return (LBRACKET);
 | 
						|
	  else if (c == ']') return (RBRACKET);
 | 
						|
 | 
						|
	  /* Look for multi-character sequences */
 | 
						|
	  
 | 
						|
	  else if (c == '/') state = 1;    // Comment (maybe) 
 | 
						|
	  else if (c == '\"') state = 2;   // Possibly a string
 | 
						|
	  else if (c == '#') state = 3;    // CPP
 | 
						|
	  else if (c == '%') state = 4;    // Directive
 | 
						|
	  else if (c == '@') state = 4;    // Objective C keyword
 | 
						|
	  else if (c == ':') state = 5;    // maybe double colon
 | 
						|
	  else if (c == '0') state = 83;   // An octal or hex value
 | 
						|
	  else if (c == '\'') state = 9;   // A character constant
 | 
						|
	  else if (c == '.') state = 100;  // Maybe a number, maybe just a period
 | 
						|
	  else if (isdigit(c)) state = 8;  // A numerical value
 | 
						|
	  else if ((isalpha(c)) || (c == '_') || (c == '$')) state = 7;
 | 
						|
	  else state = 99;
 | 
						|
	  break;
 | 
						|
	case 1:  /*  Comment block */
 | 
						|
	  if ((c = nextchar()) == 0) return(0);
 | 
						|
	  if (c == '/') {
 | 
						|
	    comment_start = line_number;
 | 
						|
	    column_start = column;
 | 
						|
	    comment = "  ";
 | 
						|
	    state = 10;        // C++ style comment
 | 
						|
	  } else if (c == '*') {
 | 
						|
	    comment_start = line_number;
 | 
						|
	    column_start = column;
 | 
						|
	    comment = "  ";
 | 
						|
	    state = 11;   // C style comment
 | 
						|
	  } else {
 | 
						|
	    retract(1);
 | 
						|
	    return(SLASH);
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
	case 10:  /* C++ style comment */
 | 
						|
	  if ((c = nextchar()) == 0) {
 | 
						|
	    fprintf(stderr,"%s : EOF. Unterminated comment detected.\n",input_file);
 | 
						|
	    FatalError();
 | 
						|
	    return 0;
 | 
						|
	  }
 | 
						|
	  if (c == '\n') {
 | 
						|
	    comment << c;
 | 
						|
	    // Add the comment to documentation
 | 
						|
	    yycomment(comment.get(),comment_start, column_start);
 | 
						|
	    yylen = 0;
 | 
						|
	    state = 0;
 | 
						|
	    if (in_define == 1) {
 | 
						|
	      in_define = 0;
 | 
						|
	      return(ENDDEF);
 | 
						|
	    }
 | 
						|
	  } else {
 | 
						|
	    state = 10;
 | 
						|
	    comment << c;
 | 
						|
	    yylen = 0;
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
	case 11: /* C style comment block */
 | 
						|
	  if ((c = nextchar()) == 0) {
 | 
						|
	    fprintf(stderr,"%s : EOF. Unterminated comment detected.\n", input_file);
 | 
						|
	    FatalError();
 | 
						|
	    return 0;
 | 
						|
	  }
 | 
						|
	  if (c == '*') {
 | 
						|
	    state = 12;
 | 
						|
	  } else {
 | 
						|
	    comment << c;
 | 
						|
	    yylen = 0;
 | 
						|
	    state = 11;
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
	case 12: /* Still in C style comment */
 | 
						|
	  if ((c = nextchar()) == 0) {
 | 
						|
	    fprintf(stderr,"%s : EOF. Unterminated comment detected.\n", input_file);
 | 
						|
	    FatalError();
 | 
						|
	    return 0;
 | 
						|
	  }
 | 
						|
	  if (c == '*') {
 | 
						|
	    comment << c;
 | 
						|
	    state = 12;
 | 
						|
	  } else if (c == '/') {
 | 
						|
	    comment << "  \n";
 | 
						|
	    yycomment(comment.get(),comment_start,column_start);
 | 
						|
	    yylen = 0;
 | 
						|
	    state = 0;
 | 
						|
	  } else {
 | 
						|
	    comment << '*' << c;
 | 
						|
	    yylen = 0;
 | 
						|
	    state = 11;
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
 | 
						|
	case 2: /* Processing a string */
 | 
						|
	  if ((c = nextchar()) == 0) {
 | 
						|
	    fprintf(stderr,"%s : EOF. Unterminated string detected.\n", input_file);
 | 
						|
	    FatalError();
 | 
						|
	    return 0;
 | 
						|
	  }
 | 
						|
	  if (c == '\"') {
 | 
						|
	    yytext[yylen-1] = 0;
 | 
						|
	    yylval.id = copy_string(yytext+1);
 | 
						|
	    return(STRING);
 | 
						|
	  } else if (c == '\\') {
 | 
						|
	    state = 21;             /* Possibly an escape sequence. */
 | 
						|
	    break;
 | 
						|
	  } else state = 2;
 | 
						|
	  break;
 | 
						|
	case 21: /* An escape sequence. get next character, then go
 | 
						|
		    back to processing strings */
 | 
						|
 | 
						|
	  if ((c = nextchar()) == 0) return 0;
 | 
						|
	  state = 2;
 | 
						|
	  break;
 | 
						|
 | 
						|
	case 3: /* a CPP directive */
 | 
						|
 | 
						|
	  if (( c= nextchar()) == 0) return 0;
 | 
						|
	  if (c == '\n') {
 | 
						|
	    retract(1);
 | 
						|
	    yytext[yylen] = 0;
 | 
						|
	    yylval.id = yytext;
 | 
						|
	    return(POUND);
 | 
						|
	  } else if ((c == ' ') || (c == '\t')) {  // Ignore white space after # symbol
 | 
						|
	    yytext[yylen] = 0;
 | 
						|
	    yylen--;
 | 
						|
	    state = 3;
 | 
						|
	  } else {
 | 
						|
	    yytext[yylen] = 0;
 | 
						|
	    state = 31;
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
	case 31:
 | 
						|
	  if ((c = nextchar()) == 0) return 0;
 | 
						|
	  if ((c == ' ') || (c == '\t') || (c=='\n')) {
 | 
						|
	    retract(1);
 | 
						|
	    yytext[yylen] = 0;
 | 
						|
	    if (strcmp(yytext,"#define") == 0) {
 | 
						|
	      in_define = 1;
 | 
						|
	      define_first_id = 1;
 | 
						|
	      return(DEFINE);
 | 
						|
	    } else if (strcmp(yytext,"#ifdef") == 0) {
 | 
						|
	      return(IFDEF);
 | 
						|
	    } else if (strcmp(yytext,"#ifndef") == 0) {
 | 
						|
	      return(IFNDEF);
 | 
						|
	    } else if (strcmp(yytext,"#else") == 0) {
 | 
						|
	      return(ELSE);
 | 
						|
	    } else if (strcmp(yytext,"#endif") == 0) {
 | 
						|
	      return(ENDIF);
 | 
						|
	    } else if (strcmp(yytext,"#undef") == 0) {
 | 
						|
	      return(UNDEF);
 | 
						|
	    } else if (strcmp(yytext,"#if") == 0) {
 | 
						|
	      return(IF);
 | 
						|
	    } else if (strcmp(yytext,"#elif") == 0) {
 | 
						|
	      return(ELIF);
 | 
						|
	    } else {
 | 
						|
	      /* Some kind of "unknown CPP directive.  Skip to end of the line */
 | 
						|
	      state = 32;
 | 
						|
	    }
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
	case 32:
 | 
						|
	  if ((c = nextchar()) == 0) return 0;
 | 
						|
	  if (c == '\n') {
 | 
						|
	    retract(1);
 | 
						|
	    yytext[yylen] = 0;
 | 
						|
	    yylval.id = yytext;
 | 
						|
	    return(POUND);
 | 
						|
	  }
 | 
						|
	  state = 32;
 | 
						|
	  break;
 | 
						|
 | 
						|
	case 4: /* A wrapper generator directive (maybe) */
 | 
						|
	  if (( c= nextchar()) == 0) return 0;
 | 
						|
	  if (c == '{') {
 | 
						|
	    state = 40;   /* Include block */
 | 
						|
	    header = "";
 | 
						|
	    start_line = line_number;
 | 
						|
	  }
 | 
						|
	  else if ((isalpha(c)) || (c == '_')) state = 7;
 | 
						|
	  else {
 | 
						|
	    retract(1);
 | 
						|
	    state = 99;
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
	  
 | 
						|
	case 40: /* Process an include block */
 | 
						|
	  if ((c = nextchar()) == 0) {
 | 
						|
	    fprintf(stderr,"%s : EOF. Unterminated include block detected.\n", input_file);
 | 
						|
	    FatalError();
 | 
						|
	    return 0;
 | 
						|
	  }
 | 
						|
	  yylen = 0;
 | 
						|
	  if (c == '%') state = 41;
 | 
						|
	  else {
 | 
						|
	    header << c;
 | 
						|
	    yylen = 0;
 | 
						|
	    state = 40;
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
	case 41: /* Still processing include block */
 | 
						|
	  if ((c = nextchar()) == 0) {
 | 
						|
	    fprintf(stderr,"%s : EOF. Unterminated include block detected.\n", input_file);
 | 
						|
	    FatalError();
 | 
						|
	    return 0;
 | 
						|
	  }
 | 
						|
	  if (c == '}') {
 | 
						|
	    yylval.id = header.get();
 | 
						|
	    return(HBLOCK);
 | 
						|
	  } else {
 | 
						|
	    header << '%';
 | 
						|
	    header << c;
 | 
						|
	    yylen = 0;
 | 
						|
	    state = 40;
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
 | 
						|
	case 5: /* Maybe a double colon */
 | 
						|
 | 
						|
	  if (( c= nextchar()) == 0) return 0;
 | 
						|
	  if ( c == ':') return DCOLON;
 | 
						|
	  else {
 | 
						|
	    retract(1);
 | 
						|
	    return COLON;
 | 
						|
	  }
 | 
						|
 | 
						|
 | 
						|
	case 60: /* shift operators */
 | 
						|
	  if ((c = nextchar()) == 0) return (0);
 | 
						|
	  if (c == '<') return LSHIFT;
 | 
						|
	  else {
 | 
						|
	    retract(1);
 | 
						|
	    return LESSTHAN;
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
	case 61: 
 | 
						|
	  if ((c = nextchar()) == 0) return (0);
 | 
						|
	  if (c == '>') return RSHIFT;
 | 
						|
	  else {
 | 
						|
	    retract(1);
 | 
						|
            return GREATERTHAN;
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
	case 7: /* Identifier */
 | 
						|
	  if ((c = nextchar()) == 0) return(0);
 | 
						|
	  if (isalnum(c) || (c == '_') || (c == '.') || (c == '$'))
 | 
						|
	    //              || (c == '.') || (c == '-'))
 | 
						|
	    state = 7;
 | 
						|
	  else if (c == '(') {
 | 
						|
	    /* We might just be in a CPP macro definition.  Better check */
 | 
						|
	    if ((in_define) && (define_first_id)) {
 | 
						|
	      /* Yep.  We're going to ignore the rest of it */
 | 
						|
	      skip_define();
 | 
						|
	      define_first_id = 0;
 | 
						|
	      return (MACRO);
 | 
						|
	    } else {
 | 
						|
	      retract(1);
 | 
						|
	      define_first_id = 0;
 | 
						|
	      return(ID);
 | 
						|
	    }
 | 
						|
	  } else {
 | 
						|
	    retract(1);
 | 
						|
	    define_first_id = 0;
 | 
						|
	    return(ID);
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
	case 8: /* A numerical digit */
 | 
						|
	  if ((c = nextchar()) == 0) return(0);
 | 
						|
	  if (c == '.') {state = 81;}
 | 
						|
	  else if ((c == 'e') || (c == 'E')) {state = 86;}
 | 
						|
	  else if ((c == 'f') || (c == 'F')) {
 | 
						|
             yytext[yylen] = 0;
 | 
						|
	     yylval.id = copy_string(yytext);
 | 
						|
	     return(NUM_FLOAT);
 | 
						|
	  }
 | 
						|
	  else if (isdigit(c)) { state = 8;}
 | 
						|
	  else if ((c == 'l') || (c == 'L')) {
 | 
						|
	    state = 87;
 | 
						|
	  } else if ((c == 'u') || (c == 'U')) {
 | 
						|
	    state = 88;
 | 
						|
	  } else {
 | 
						|
	      retract(1);
 | 
						|
	      yytext[yylen] = 0;
 | 
						|
	      yylval.id = copy_string(yytext);
 | 
						|
	      return(NUM_INT);
 | 
						|
	    }
 | 
						|
	  break;
 | 
						|
	case 81: /* A floating pointer number of some sort */
 | 
						|
	  if ((c = nextchar()) == 0) return(0);
 | 
						|
	  if (isdigit(c)) state = 81;
 | 
						|
	  else if ((c == 'e') || (c == 'E')) state = 82;
 | 
						|
          else if ((c == 'f') || (c == 'F') || (c == 'l') || (c == 'L')) {
 | 
						|
	    yytext[yylen] = 0;
 | 
						|
	    yylval.id = copy_string(yytext);
 | 
						|
	    return(NUM_FLOAT);
 | 
						|
	  } else {
 | 
						|
	    retract(1);
 | 
						|
	    yytext[yylen] = 0;
 | 
						|
	    yylval.id = copy_string(yytext);
 | 
						|
	    return(NUM_FLOAT);
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
	case 82:
 | 
						|
	  if ((c = nextchar()) == 0) return(0);
 | 
						|
	  if ((isdigit(c)) || (c == '-') || (c == '+')) state = 86;
 | 
						|
	  else {
 | 
						|
	    retract(2);
 | 
						|
	    yytext[yylen-1] = 0;
 | 
						|
	    yylval.id = copy_string(yytext);
 | 
						|
	    return(NUM_INT);
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
	case 83:
 | 
						|
	  /* Might be a hexidecimal or octal number */
 | 
						|
	  if ((c = nextchar()) == 0) return(0);
 | 
						|
	  if (isdigit(c)) state = 84;
 | 
						|
	  else if ((c == 'x') || (c == 'X')) state = 85;
 | 
						|
	  else if (c == '.') state = 81;
 | 
						|
	  else if ((c == 'l') || (c == 'L')) {
 | 
						|
	    state = 87;
 | 
						|
	  } else if ((c == 'u') || (c == 'U')) {
 | 
						|
	    state = 88;
 | 
						|
	  } else {
 | 
						|
	    retract(1);
 | 
						|
	    yytext[yylen] = 0;
 | 
						|
	    yylval.id = copy_string(yytext);
 | 
						|
	    return(NUM_INT);
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
	case 84:
 | 
						|
	  /* This is an octal number */
 | 
						|
	  if ((c = nextchar()) == 0) return (0);
 | 
						|
	  if (isdigit(c)) state = 84;
 | 
						|
	  else if ((c == 'l') || (c == 'L')) {
 | 
						|
	    state = 87;
 | 
						|
	  } else if ((c == 'u') || (c == 'U')) {
 | 
						|
	    state = 88;
 | 
						|
	  } else {
 | 
						|
	    retract(1);
 | 
						|
	    yytext[yylen] = 0;
 | 
						|
	    yylval.id = copy_string(yytext);
 | 
						|
	    return(NUM_INT);
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
	case 85:
 | 
						|
	  /* This is an hex number */
 | 
						|
	  if ((c = nextchar()) == 0) return (0);
 | 
						|
	  if ((isdigit(c)) || (c=='a') || (c=='b') || (c=='c') ||
 | 
						|
	      (c=='d') || (c=='e') || (c=='f') || (c=='A') ||
 | 
						|
	      (c=='B') || (c=='C') || (c=='D') || (c=='E') ||
 | 
						|
	      (c=='F'))
 | 
						|
	    state = 85;
 | 
						|
	  else if ((c == 'l') || (c == 'L')) {
 | 
						|
	    state = 87;
 | 
						|
	  } else if ((c == 'u') || (c == 'U')) {
 | 
						|
	    state = 88;
 | 
						|
	  } else {
 | 
						|
	    retract(1);
 | 
						|
	    yytext[yylen] = 0;
 | 
						|
	    yylval.id = copy_string(yytext);
 | 
						|
	    return(NUM_INT);
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
 | 
						|
	case 86:
 | 
						|
	  /* Rest of floating point number */
 | 
						|
 | 
						|
	  if ((c = nextchar()) == 0) return (0);
 | 
						|
	  if (isdigit(c)) state = 86;
 | 
						|
          else if ((c == 'f') || (c == 'F') || (c == 'l') || (c == 'L')) {
 | 
						|
	    yytext[yylen] = 0;
 | 
						|
	    yylval.id = copy_string(yytext);
 | 
						|
	    return(NUM_FLOAT);
 | 
						|
	  } else {
 | 
						|
	    retract(1);
 | 
						|
	    yytext[yylen] = 0;
 | 
						|
	    yylval.id = copy_string(yytext);
 | 
						|
	    return(NUM_FLOAT);
 | 
						|
	  }
 | 
						|
	  /* Parse a character constant. ie. 'a' */
 | 
						|
	  break;
 | 
						|
 | 
						|
	case 87 :
 | 
						|
	  /* A long integer of some sort */
 | 
						|
	  if ((c = nextchar()) == 0) return (0);
 | 
						|
	  if ((c == 'u') || (c == 'U')) {
 | 
						|
	    yytext[yylen] = 0;
 | 
						|
	    yylval.id = copy_string(yytext);
 | 
						|
	    return(NUM_ULONG);
 | 
						|
	  } else {
 | 
						|
	    retract(1);
 | 
						|
	    yytext[yylen] = 0;
 | 
						|
	    yylval.id = copy_string(yytext);
 | 
						|
	    return(NUM_LONG);
 | 
						|
	  } 
 | 
						|
 | 
						|
	case 88:
 | 
						|
	  /* An unsigned integer of some sort */
 | 
						|
	  if ((c = nextchar()) == 0) return (0);
 | 
						|
	  if ((c == 'l') || (c == 'L')) {
 | 
						|
	    yytext[yylen] = 0;
 | 
						|
	    yylval.id = copy_string(yytext);
 | 
						|
	    return(NUM_ULONG);
 | 
						|
	  } else {
 | 
						|
	    retract(1);
 | 
						|
	    yytext[yylen] = 0;
 | 
						|
	    yylval.id = copy_string(yytext);
 | 
						|
	    return(NUM_UNSIGNED);
 | 
						|
	  } 
 | 
						|
 | 
						|
	case 9:
 | 
						|
	  if ((c = nextchar()) == 0) return (0);
 | 
						|
	  if (c == '\'') {
 | 
						|
	    yytext[yylen-1] = 0;
 | 
						|
	    yylval.id = copy_string(yytext+1);
 | 
						|
	    return(CHARCONST);
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
 | 
						|
	case 100:
 | 
						|
	  if ((c = nextchar()) == 0) return (0);
 | 
						|
	  if (isdigit(c)) state = 81;
 | 
						|
	  else {
 | 
						|
	    retract(1);
 | 
						|
	    return(PERIOD);
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
	default:
 | 
						|
	  if (!Error) {
 | 
						|
	    fprintf(stderr,"%s : Line %d ::Illegal character '%c'=%d.\n",input_file, line_number,c,c);
 | 
						|
	    FatalError();
 | 
						|
	  }
 | 
						|
	  state = 0;	
 | 
						|
  	  Error = 1;	
 | 
						|
	  return(ILLEGAL);
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static int check_typedef = 0;
 | 
						|
 | 
						|
void scanner_check_typedef() {
 | 
						|
  check_typedef = 1;
 | 
						|
}
 | 
						|
 | 
						|
void scanner_ignore_typedef() {
 | 
						|
  check_typedef = 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**************************************************************
 | 
						|
 * int yylex()
 | 
						|
 *
 | 
						|
 * Gets the lexene and returns tokens.
 | 
						|
 *************************************************************/
 | 
						|
 | 
						|
extern "C" int yylex(void) {
 | 
						|
    
 | 
						|
    int   l;
 | 
						|
 | 
						|
    if (!scan_init) {
 | 
						|
      scanner_init();
 | 
						|
      //      if (LEX_in == NULL) LEX_in = stdin;
 | 
						|
      //      scanner_file(LEX_in);
 | 
						|
    }
 | 
						|
    
 | 
						|
    l = yylook();
 | 
						|
 | 
						|
    /* We got some sort of non-white space object.  We set the start_line 
 | 
						|
       variable unless it has already been set */
 | 
						|
 | 
						|
    if (!start_line) {
 | 
						|
      start_line = line_number;
 | 
						|
    }
 | 
						|
 | 
						|
    /* Copy the lexene */
 | 
						|
 | 
						|
    yytext[yylen] = 0;
 | 
						|
 | 
						|
    /* Hack to support ignoring of CPP macros */
 | 
						|
 | 
						|
    if (l != DEFINE) {
 | 
						|
      define_first_id = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    switch(l) {
 | 
						|
 | 
						|
      case ID:
 | 
						|
 | 
						|
	/* Look for keywords now */
 | 
						|
 | 
						|
	if (strcmp(yytext,"int") == 0) {
 | 
						|
	  yylval.type = new DataType;
 | 
						|
	  yylval.type->type = T_INT;
 | 
						|
	  strcpy(yylval.type->name,yytext);
 | 
						|
	  return(TYPE_INT);
 | 
						|
	}
 | 
						|
	if (strcmp(yytext,"double") == 0) {
 | 
						|
	  yylval.type = new DataType;
 | 
						|
	  yylval.type->type = T_DOUBLE;
 | 
						|
	  strcpy(yylval.type->name,yytext);
 | 
						|
	  return(TYPE_DOUBLE);
 | 
						|
	}
 | 
						|
	if (strcmp(yytext,"void") == 0) {
 | 
						|
	  yylval.type = new DataType;
 | 
						|
	  yylval.type->type = T_VOID;
 | 
						|
	  strcpy(yylval.type->name,yytext);
 | 
						|
	  return(TYPE_VOID);
 | 
						|
	}
 | 
						|
	if (strcmp(yytext,"char") == 0) {
 | 
						|
	  yylval.type = new DataType;
 | 
						|
	  yylval.type->type = T_CHAR;
 | 
						|
	  strcpy(yylval.type->name,yytext);
 | 
						|
	  return(TYPE_CHAR);
 | 
						|
	}
 | 
						|
	if (strcmp(yytext,"short") == 0) {
 | 
						|
	  yylval.type = new DataType;
 | 
						|
	  yylval.type->type = T_SHORT;
 | 
						|
	  strcpy(yylval.type->name,yytext);
 | 
						|
	  return(TYPE_SHORT);
 | 
						|
	}
 | 
						|
	if (strcmp(yytext,"long") == 0) {
 | 
						|
	  yylval.type = new DataType;
 | 
						|
	  yylval.type->type = T_LONG;
 | 
						|
	  strcpy(yylval.type->name,yytext);
 | 
						|
	  return(TYPE_LONG);
 | 
						|
	}
 | 
						|
	if (strcmp(yytext,"float") == 0) {
 | 
						|
	  yylval.type = new DataType;
 | 
						|
	  yylval.type->type = T_FLOAT;
 | 
						|
	  strcpy(yylval.type->name,yytext);
 | 
						|
	  return(TYPE_FLOAT);
 | 
						|
	}
 | 
						|
	if (strcmp(yytext,"signed") == 0) {
 | 
						|
	  yylval.type = new DataType;
 | 
						|
	  yylval.type->type = T_SINT;
 | 
						|
	  strcpy(yylval.type->name,yytext);
 | 
						|
	  return(TYPE_SIGNED);
 | 
						|
	}
 | 
						|
	if (strcmp(yytext,"unsigned") == 0) {
 | 
						|
	  yylval.type = new DataType;
 | 
						|
	  yylval.type->type = T_UINT;
 | 
						|
	  strcpy(yylval.type->name,yytext);
 | 
						|
	  return(TYPE_UNSIGNED);
 | 
						|
	}
 | 
						|
	if (strcmp(yytext,"bool") == 0) {
 | 
						|
	  yylval.type = new DataType;
 | 
						|
	  yylval.type->type = T_BOOL;
 | 
						|
	  strcpy(yylval.type->name,yytext);
 | 
						|
	  return(TYPE_BOOL);
 | 
						|
	}
 | 
						|
	// C++ keywords
 | 
						|
	
 | 
						|
	if (CPlusPlus) {
 | 
						|
	  if (strcmp(yytext,"class") == 0) return(CLASS);
 | 
						|
	  if (strcmp(yytext,"private") == 0) return(PRIVATE);
 | 
						|
	  if (strcmp(yytext,"public") == 0) return(PUBLIC);
 | 
						|
	  if (strcmp(yytext,"protected") == 0) return(PROTECTED);
 | 
						|
	  if (strcmp(yytext,"friend") == 0) return(FRIEND);
 | 
						|
	  if (strcmp(yytext,"virtual") == 0) return(VIRTUAL);
 | 
						|
	  if (strcmp(yytext,"operator") == 0) return(OPERATOR);
 | 
						|
	  if (strcmp(yytext,"throw") == 0) return(THROW);
 | 
						|
	  if (strcmp(yytext,"inline") == 0) return(yylex());
 | 
						|
	  if (strcmp(yytext,"template") == 0) return(TEMPLATE);
 | 
						|
	}
 | 
						|
 | 
						|
	// Objective-C keywords
 | 
						|
        if (ObjC) {
 | 
						|
	  if (strcmp(yytext,"@interface") == 0) return (OC_INTERFACE);
 | 
						|
	  if (strcmp(yytext,"@end") == 0) return (OC_END);
 | 
						|
	  if (strcmp(yytext,"@public") == 0) return (OC_PUBLIC);
 | 
						|
	  if (strcmp(yytext,"@private") == 0) return (OC_PRIVATE);
 | 
						|
	  if (strcmp(yytext,"@protected") == 0) return (OC_PROTECTED);
 | 
						|
	  if (strcmp(yytext,"@class") == 0) return(OC_CLASS);
 | 
						|
	  if (strcmp(yytext,"@implementation") == 0) return(OC_IMPLEMENT);
 | 
						|
          if (strcmp(yytext,"@protocol") == 0) return(OC_PROTOCOL);
 | 
						|
	}
 | 
						|
 | 
						|
	// Misc keywords
 | 
						|
 | 
						|
	if (strcmp(yytext,"static") == 0) return(STATIC);
 | 
						|
	if (strcmp(yytext,"extern") == 0) return(EXTERN);
 | 
						|
	if (strcmp(yytext,"const") == 0) return(CONST);
 | 
						|
	if (strcmp(yytext,"struct") == 0) return(STRUCT);
 | 
						|
	if (strcmp(yytext,"union") == 0) return(UNION);
 | 
						|
	if (strcmp(yytext,"enum") == 0) return(ENUM);
 | 
						|
	if (strcmp(yytext,"sizeof") == 0) return(SIZEOF);
 | 
						|
	if (strcmp(yytext,"defined") == 0) return(DEFINED);
 | 
						|
 | 
						|
	// Ignored keywords 
 | 
						|
 | 
						|
	if (strcmp(yytext,"volatile") == 0) return(yylex());
 | 
						|
 | 
						|
	// SWIG directives
 | 
						|
 | 
						|
	if (strcmp(yytext,"%module") == 0) return(MODULE);
 | 
						|
	if (strcmp(yytext,"%init") == 0)  return(INIT);
 | 
						|
	if (strcmp(yytext,"%wrapper") == 0) return(WRAPPER);
 | 
						|
	if (strcmp(yytext,"%readonly") == 0) return(READONLY);
 | 
						|
	if (strcmp(yytext,"%readwrite") == 0) return(READWRITE);
 | 
						|
	if (strcmp(yytext,"%name") == 0) return(NAME);
 | 
						|
        if (strcmp(yytext,"%rename") == 0) return(RENAME);
 | 
						|
	if (strcmp(yytext,"%include") == 0) return(INCLUDE);
 | 
						|
	if (strcmp(yytext,"%extern") == 0) return(WEXTERN);
 | 
						|
        if (strcmp(yytext,"%checkout") == 0) return(CHECKOUT);
 | 
						|
	if (strcmp(yytext,"%val") == 0) return(CVALUE);
 | 
						|
	if (strcmp(yytext,"%out") == 0) return(COUT);
 | 
						|
 | 
						|
	if (strcmp(yytext,"%section") == 0) {
 | 
						|
	  yylval.ivalue = line_number;
 | 
						|
	  return(SECTION);
 | 
						|
	}
 | 
						|
	if (strcmp(yytext,"%subsection") == 0) {
 | 
						|
	  yylval.ivalue = line_number;
 | 
						|
	  return(SUBSECTION);
 | 
						|
	}
 | 
						|
	if (strcmp(yytext,"%subsubsection") == 0) {
 | 
						|
	  yylval.ivalue = line_number;
 | 
						|
	  return (SUBSUBSECTION);
 | 
						|
	}
 | 
						|
	if (strcmp(yytext,"%title") == 0) {
 | 
						|
	  yylval.ivalue = line_number;
 | 
						|
	  return(TITLE);
 | 
						|
	} 
 | 
						|
	if (strcmp(yytext,"%style") == 0) return(STYLE);
 | 
						|
	if (strcmp(yytext,"%localstyle") == 0) return(LOCALSTYLE);
 | 
						|
	if (strcmp(yytext,"%typedef") == 0) {
 | 
						|
	  yylval.ivalue = 1;
 | 
						|
	  return(TYPEDEF);
 | 
						|
	}
 | 
						|
	if (strcmp(yytext,"typedef") == 0) {
 | 
						|
	  yylval.ivalue = 0;
 | 
						|
	  return(TYPEDEF);
 | 
						|
	}
 | 
						|
	if (strcmp(yytext,"%alpha") == 0) return(ALPHA_MODE);
 | 
						|
	if (strcmp(yytext,"%raw") == 0) return(RAW_MODE);
 | 
						|
	if (strcmp(yytext,"%text") == 0) return(TEXT);
 | 
						|
	if (strcmp(yytext,"%native") == 0) return(NATIVE);
 | 
						|
	if (strcmp(yytext,"%disabledoc") == 0) return(DOC_DISABLE);
 | 
						|
	if (strcmp(yytext,"%enabledoc") == 0) return(DOC_ENABLE);
 | 
						|
	if (strcmp(yytext,"%ifdef") == 0) return(IFDEF);
 | 
						|
	if (strcmp(yytext,"%else") == 0) return(ELSE);
 | 
						|
	if (strcmp(yytext,"%ifndef") == 0) return(IFNDEF);
 | 
						|
	if (strcmp(yytext,"%endif") == 0) return(ENDIF);
 | 
						|
	if (strcmp(yytext,"%if") == 0) return(IF);
 | 
						|
	if (strcmp(yytext,"%elif") == 0) return(ELIF);
 | 
						|
	if (strcmp(yytext,"%pragma") == 0) return(PRAGMA);
 | 
						|
	if (strcmp(yytext,"%addmethods") == 0) return(ADDMETHODS);
 | 
						|
	if (strcmp(yytext,"%inline") == 0) return(INLINE);
 | 
						|
	if (strcmp(yytext,"%typemap") == 0) return(TYPEMAP);
 | 
						|
	if (strcmp(yytext,"%except") == 0) return(EXCEPT);
 | 
						|
	if (strcmp(yytext,"%import") == 0) return(IMPORT);
 | 
						|
	if (strcmp(yytext,"%echo") == 0) return(ECHO);
 | 
						|
        if (strcmp(yytext,"%new") == 0) return(NEW);
 | 
						|
	if (strcmp(yytext,"%apply") == 0) return(APPLY);
 | 
						|
	if (strcmp(yytext,"%clear") == 0) return(CLEAR);
 | 
						|
        if (strcmp(yytext,"%doconly") == 0) return(DOCONLY);
 | 
						|
 
 | 
						|
	// Have an unknown identifier, as a last step, we'll
 | 
						|
	// do a typedef lookup on it.
 | 
						|
 | 
						|
	if (check_typedef) {
 | 
						|
	  if (DataType::is_typedef(yytext)) {
 | 
						|
	    yylval.type = new DataType;
 | 
						|
	    yylval.type->type = T_USER;
 | 
						|
	    strcpy(yylval.type->name,yytext);
 | 
						|
	    yylval.type->typedef_resolve();
 | 
						|
	    return(TYPE_TYPEDEF);
 | 
						|
	  }
 | 
						|
	}
 | 
						|
 | 
						|
	yylval.id = copy_string(yytext);
 | 
						|
	return(ID);
 | 
						|
      default:
 | 
						|
	return(l);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
// --------------------------------------------------------------
 | 
						|
// scanner_clear_start()
 | 
						|
//
 | 
						|
// Clears the start of a declaration
 | 
						|
// --------------------------------------------------------------
 | 
						|
 | 
						|
void scanner_clear_start() {
 | 
						|
  start_line = 0;
 | 
						|
}
 |