c90f71dd8c
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;
|
|
}
|