swig/Source/CParse/cscanner.c
Dave Beazley 8a9b2cbdb1 Changed Header to Id
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@9610 626c5289-ae23-0410-ae9c-e8d60b6d4f22
2006-12-05 22:14:31 +00:00

1593 lines
35 KiB
C

/* -----------------------------------------------------------------------------
* See the LICENSE file for information on copyright, usage and redistribution
* of SWIG, and the README file for authors - http://www.swig.org/release.html.
*
* scanner.c
*
* SWIG tokenizer.
* ----------------------------------------------------------------------------- */
char cvsroot_cscanner_c[] = "$Id$";
#include "cparse.h"
#include "parser.h"
#include <string.h>
#include <ctype.h>
#define YYBSIZE 65536
typedef struct InFile {
DOHFile *f;
int line_number;
char *in_file;
struct InFile *prev;
} InFile;
static InFile *in_head;
DOHFile *LEX_in = 0;
static DOHString *header = 0;
static DOHString *comment = 0;
DOHString *scanner_ccode = 0; /* String containing C code */
static char *yybuffer = 0;
static char yytext[YYBSIZE];
static int yylen = 0;
int cparse_line = 1;
char *cparse_file;
int cparse_start_line = 0;
static int comment_start;
static int scan_init = 0;
static int num_brace = 0;
static int last_brace = 0;
static int last_id = 0;
static int rename_active = 0;
static int swigtemplate_active = 0;
int cparse_cplusplus = 0;
static int expanding_macro = 0;
/* -----------------------------------------------------------------------------
* Swig_cparse_cplusplus()
* ----------------------------------------------------------------------------- */
void Swig_cparse_cplusplus(int v) {
cparse_cplusplus = v;
}
/* ----------------------------------------------------------------------
* locator()
*
* Support for locator strings. These are strings of the form
* @filename,line,id@ emitted by the SWIG preprocessor. They
* are primarily used for macro line number reporting
* ---------------------------------------------------------------------- */
#if 1
/* we just use the locator to mark when active/deactive the linecounting */
static void scanner_locator(String *loc) {
if (Equal(loc, "@SWIG@")) {
/* End locator. */
if (expanding_macro)
--expanding_macro;
} else {
/* Begin locator. */
++expanding_macro;
}
}
#else
typedef struct Locator {
char *filename;
int line_number;
struct Locator *next;
} Locator;
static Locator *locs = 0;
static void scanner_locator(String *loc) {
int c;
Locator *l;
Seek(loc, 1, SEEK_SET);
c = Getc(loc);
if (c == '@') {
/* Empty locator. We pop the last location off */
if (locs) {
cparse_file = locs->filename;
cparse_line = locs->line_number;
l = locs->next;
free(locs);
locs = l;
}
/* Printf(stderr,"location: %s:%d\n",cparse_file,cparse_line); */
return;
}
/* We're going to push a new location */
l = (Locator *) malloc(sizeof(Locator));
l->filename = cparse_file;
l->line_number = cparse_line;
l->next = locs;
locs = l;
/* Now, parse the new location out of the locator string */
{
String *fn = NewStringEmpty();
Putc(c, fn);
while ((c = Getc(loc)) != EOF) {
if ((c == '@') || (c == ','))
break;
Putc(c, fn);
}
cparse_file = Swig_copy_string(Char(fn));
Clear(fn);
cparse_line = 1;
/* Get the line number */
while ((c = Getc(loc)) != EOF) {
if ((c == '@') || (c == ','))
break;
Putc(c, fn);
}
cparse_line = atoi(Char(fn));
Clear(fn);
/* Get the rest of it */
while ((c = Getc(loc)) != EOF) {
if (c == '@')
break;
Putc(c, fn);
}
/* Printf(stderr,"location: %s:%d\n",cparse_file,cparse_line); */
Delete(fn);
}
}
#endif
/* ----------------------------------------------------------------------------
* scanner_init()
*
* Initialize buffers
* ------------------------------------------------------------------------- */
void scanner_init() {
yybuffer = (char *) malloc(YYBSIZE);
scan_init = 1;
header = NewStringEmpty();
comment = NewStringEmpty();
scanner_ccode = NewStringEmpty();
}
/* ----------------------------------------------------------------------------
* scanner_file(FILE *f)
*
* Start reading from new file
* ------------------------------------------------------------------------- */
void scanner_file(DOHFile * f) {
InFile *in;
in = (InFile *) malloc(sizeof(InFile));
in->f = f;
in->in_file = cparse_file;
in->line_number = 1;
if (!in_head)
in->prev = 0;
else
in->prev = in_head;
in_head = in;
LEX_in = f;
cparse_line = 1;
}
/* ----------------------------------------------------------------------------
* scanner_close()
*
* Close current input file and go to next
* ------------------------------------------------------------------------- */
void scanner_close() {
InFile *p;
if (!in_head)
return;
Delete(LEX_in);
p = in_head->prev;
if (p != 0) {
LEX_in = p->f;
cparse_line = p->line_number;
cparse_file = p->in_file;
} else {
LEX_in = 0;
}
free(in_head);
in_head = p;
}
/* ----------------------------------------------------------------------------
* unsigned char nextchar()
*
* gets next character from input.
* If we're in inlining mode, we actually retrieve a character
* from inline_yybuffer instead.
* Return value is unsigned char since isalpha(), etc aren't defined for the
* negative values that we get if char is signed.
* ------------------------------------------------------------------------- */
unsigned char nextchar() {
int c = 0;
while (LEX_in) {
c = Getc(LEX_in);
if (c == EOF) {
scanner_close();
} else {
break;
}
}
if (!LEX_in)
return 0;
if (yylen >= YYBSIZE) {
Printf(stderr, "** FATAL ERROR. Buffer overflow in scanner.c.\nPlease report to the SWIG developers.\n");
exit(EXIT_FAILURE);
}
yytext[yylen] = c;
yylen++;
if (c == '\n') {
if (!expanding_macro)
cparse_line++;
}
return c;
}
void retract(int n) {
int i;
for (i = 0; i < n; i++) {
yylen--;
if (yylen >= 0) {
Ungetc(yytext[yylen], LEX_in);
if (yytext[yylen] == '\n') {
if (!expanding_macro)
cparse_line--;
}
}
}
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) {
InFile *in;
if (!in_head)
return;
/* Save current state */
in_head->line_number = cparse_line;
in_head->in_file = cparse_file;
in = (InFile *) malloc(sizeof(InFile));
in->f = NewString(text);
Seek(in->f, 0, SEEK_SET);
in->in_file = Swig_copy_string(cparse_file);
in->line_number = line;
in->prev = in_head;
in_head = in;
LEX_in = in->f;
cparse_line = line;
}
/* ----------------------------------------------------------------------------
* yycomment(char *, int line)
*
* Inserts a comment into a documentation entry.
* ------------------------------------------------------------------------- */
/*
void yycomment(char *a, int b, int c) {
}
*/
/* -----------------------------------------------------------------------------
* skip_balanced()
*
* Skips a piece of code enclosed in begin/end symbols such as '{...}' or
* (...). Ignores symbols inside comments or strings.
* ----------------------------------------------------------------------------- */
void skip_balanced(int startchar, int endchar) {
int c;
int num_levels = 1;
int state = 0;
int start_line = cparse_line;
Clear(scanner_ccode);
Putc(startchar, scanner_ccode);
while (num_levels > 0) {
c = nextchar();
if (c == 0) {
Swig_error(cparse_file, start_line, "Missing '%c'. Reached end of input.\n", endchar);
return;
}
Putc(c, scanner_ccode);
switch (state) {
case 0:
if (c == startchar)
num_levels++;
else if (c == endchar)
num_levels--;
else if (c == '/')
state = 10;
else if (c == '\"')
state = 20;
else if (c == '\'')
state = 30;
break;
case 10:
if (c == '/')
state = 11;
else if (c == '*')
state = 12;
else
state = 0;
break;
case 11:
if (c == '\n')
state = 0;
else
state = 11;
break;
case 12:
if (c == '*')
state = 13;
break;
case 13:
if (c == '*')
state = 13;
else if (c == '/')
state = 0;
else
state = 12;
break;
case 20:
if (c == '\"')
state = 0;
else if (c == '\\')
state = 21;
break;
case 21:
state = 20;
break;
case 30:
if (c == '\'')
state = 0;
else if (c == '\\')
state = 31;
break;
case 31:
state = 30;
break;
default:
break;
}
yylen = 0;
}
if (endchar == '}')
num_brace--;
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) {
int c;
int done = 0;
int start_line = cparse_line;
while (!done) {
if ((c = nextchar()) == 0) {
if (!Swig_error_count()) {
Swig_error(cparse_file, start_line - 1, "Missing semicolon. Reached end of input.\n");
}
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) {
if (!Swig_error_count()) {
Swig_error(cparse_file, start_line - 1, "Missing '}'. Reached end of input.\n");
}
return;
}
if (c == '{')
num_brace++;
if (c == '}')
num_brace--;
yylen = 0;
}
}
}
/* This function is called when a backslash is found in a string */
static void get_escape() {
int result = 0;
int state = 0;
int c;
while (1) {
c = nextchar();
if (c == 0)
break;
switch (state) {
case 0:
if (c == 'n') {
yytext[yylen - 1] = '\n';
return;
}
if (c == 'r') {
yytext[yylen - 1] = '\r';
return;
}
if (c == 't') {
yytext[yylen - 1] = '\t';
return;
}
if (c == 'a') {
yytext[yylen - 1] = '\a';
return;
}
if (c == 'b') {
yytext[yylen - 1] = '\b';
return;
}
if (c == 'f') {
yytext[yylen - 1] = '\f';
return;
}
if (c == '\\') {
yytext[yylen - 1] = '\\';
return;
}
if (c == 'v') {
yytext[yylen - 1] = '\v';
return;
}
if (c == 'e') {
yytext[yylen - 1] = '\033';
return;
}
if (c == '\'') {
yytext[yylen - 1] = '\'';
return;
}
if (c == '\"') {
yytext[yylen - 1] = '\"';
return;
}
if (c == '\n') {
yylen--;
return;
}
if (isdigit(c)) {
state = 10;
result = (c - '0');
} else if (c == 'x') {
state = 20;
} else {
yytext[yylen - 1] = '\\';
yytext[yylen] = c;
yylen++;
return;
}
break;
case 10:
if (!isdigit(c)) {
retract(1);
yytext[yylen - 1] = (char) result;
return;
}
result = (result << 3) + (c - '0');
yylen--;
break;
case 20:
if (!isxdigit(c)) {
retract(1);
yytext[yylen - 1] = (char) result;
return;
}
if (isdigit(c))
result = (result << 4) + (c - '0');
else
result = (result << 4) + (10 + tolower(c) - 'a');
yylen--;
break;
}
}
return;
}
/* ----------------------------------------------------------------------------
* int yylook()
*
* Lexical scanner.
* See Aho,Sethi, and Ullman, pg. 106
* ------------------------------------------------------------------------- */
int yylook(void) {
int state;
int c = 0;
state = 0;
yylen = 0;
while (1) {
/* printf("State = %d\n", state); */
switch (state) {
case 0:
if ((c = nextchar()) == 0)
return (0);
/* Process delimiters */
if (c == '\n') {
state = 0;
yylen = 0;
/* last_id = 0; */
} else if (isspace(c) || (c == '\\')) {
state = 0;
yylen = 0;
/* last_id = 0; */
}
else if ((isalpha(c)) || (c == '_'))
state = 7;
else if (c == '$')
state = 75;
/* Look for single character symbols */
else if (c == '(')
return (LPAREN);
else if (c == ')')
return (RPAREN);
else if (c == ';') {
swigtemplate_active = 0;
return (SEMI);
}
else if (c == ',')
return (COMMA);
else if (c == '*')
return (STAR);
else if (c == '}') {
num_brace--;
if (num_brace < 0) {
Swig_error(cparse_file, cparse_line, "Syntax error. Extraneous '}'\n");
state = 0;
num_brace = 0;
} else {
return (RBRACE);
}
} else if (c == '{') {
cparse_start_line = cparse_line;
last_brace = num_brace;
num_brace++;
return (LBRACE);
} else if (c == '=')
state = 63;
else if (c == '+')
return (PLUS);
else if (c == '-')
return (MINUS);
else if (c == '&') {
state = 300;
} else if (c == '|') {
state = 301;
} else if (c == '^')
return (XOR);
else if (c == '<')
state = 60;
else if (c == '>')
state = 61;
else if (c == '~') {
return (NOT);
} else if (c == '!')
state = 62;
else if (c == '\\') {
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 (c == '?')
return (QUESTIONMARK); /* Ternary conditional operator */
else if (c == '`') {
state = 200; /* Back-tick type */
yylen = 0;
} else if (isdigit(c))
state = 8; /* A numerical value */
else
state = 99;
break;
case 1: /* Comment block */
if ((c = nextchar()) == 0)
return (0);
if (c == '/') {
comment_start = cparse_line;
Clear(comment);
state = 10; /* C++ style comment */
} else if (c == '*') {
comment_start = cparse_line;
Clear(comment);
state = 12; /* C style comment */
} else {
retract(1);
return (SLASH);
}
break;
case 300: /* & or && */
if ((c = nextchar()) == 0)
return (AND);
if (c == '&')
return (LAND);
else {
retract(1);
return (AND);
}
case 301: /* | or || */
if ((c = nextchar()) == 0)
return (OR);
if (c == '|')
return (LOR);
else {
retract(1);
return (OR);
}
case 10: /* C++ style comment */
if ((c = nextchar()) == 0) {
Swig_error(cparse_file, -1, "Unterminated comment detected.\n");
return 0;
}
if (c == '\n') {
Putc(c, comment);
/* Add the comment to documentation */
/* yycomment(Char(comment),comment_start, column_start); */
yylen = 0;
state = 0;
} else {
state = 10;
Putc(c, comment);
yylen = 0;
}
break;
case 12: /* C style comment block */
if ((c = nextchar()) == 0) {
Swig_error(cparse_file, -1, "Unterminated comment detected.\n");
return 0;
}
if (c == '*') {
state = 13;
} else {
Putc(c, comment);
yylen = 0;
state = 12;
}
break;
case 13: /* Still in C style comment */
if ((c = nextchar()) == 0) {
Swig_error(cparse_file, -1, "Unterminated comment detected.\n");
return 0;
}
if (c == '*') {
Putc(c, comment);
state = 13;
} else if (c == '/') {
/* Look for locator markers */
char *loc = Char(comment);
if (loc && (strncmp(loc, "@SWIG", 4) == 0) && (*(loc + Len(comment) - 1) == '@')) {
/* Locator */
scanner_locator(comment);
yylen = 0;
state = 0;
} else {
yylen = 0;
state = 0;
}
} else {
Putc('*', comment);
Putc(c, comment);
yylen = 0;
state = 12;
}
break;
case 2: /* Processing a string */
if ((c = nextchar()) == 0) {
Swig_error(cparse_file, -1, "Unterminated string detected.\n");
return 0;
}
if (c == '\"') {
yytext[yylen - 1] = 0;
yylval.id = Swig_copy_string(yytext + 1);
return (STRING);
} else if (c == '\\') {
yylen--;
get_escape();
break;
} else
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);
}
break;
case 4: /* A wrapper generator directive (maybe) */
if ((c = nextchar()) == 0)
return 0;
if (c == '{') {
state = 40; /* Include block */
Clear(header);
cparse_start_line = cparse_line;
} else if ((isalpha(c)) || (c == '_'))
state = 7;
else if (c == '}') {
Swig_error(cparse_file, cparse_line, "Misplaced %%}.\n");
return 0;
} else {
retract(1);
return (MODULO);
}
break;
case 40: /* Process an include block */
if ((c = nextchar()) == 0) {
Swig_error(cparse_file, -1, "Unterminated include block detected.\n");
return 0;
}
yylen = 0;
if (c == '%')
state = 41;
else {
Putc(c, header);
yylen = 0;
state = 40;
}
break;
case 41: /* Still processing include block */
if ((c = nextchar()) == 0) {
Swig_error(cparse_file, -1, "Unterminated include block detected.\n");
return 0;
}
if (c == '}') {
yylval.str = NewString(header);
return (HBLOCK);
} else {
Putc('%', header);
Putc(c, header);
yylen = 0;
state = 40;
}
break;
case 5: /* Maybe a double colon */
if ((c = nextchar()) == 0)
return 0;
if (c == ':') {
state = 51;
} else {
retract(1);
return COLON;
}
break;
case 51: /* Maybe a ::*, ::~, or :: */
if ((c = nextchar()) == 0)
return 0;
if (c == '*') {
return DSTAR;
} else if (c == '~') {
return DCNOT;
} else if (isspace(c)) {
/* Keep scanning ahead. Might be :: * or :: ~ */
} else {
retract(1);
if (!last_id) {
retract(2);
return NONID;
} else {
return DCOLON;
}
}
break;
case 60: /* < - less than or less than or equal to or left shift operator */
if ((c = nextchar()) == 0)
return (0);
if (c == '<')
return LSHIFT;
if (c == '=')
return LESSTHANOREQUALTO;
else {
retract(1);
return LESSTHAN;
}
case 61: /* > - greater than or greater or equal to or right shift operator */
if ((c = nextchar()) == 0)
return (0);
if (c == '>')
return RSHIFT;
if (c == '=')
return GREATERTHANOREQUALTO;
else {
retract(1);
return GREATERTHAN;
}
case 62: /* ! - logical not or not equal to */
if ((c = nextchar()) == 0)
return (0);
if (c == '=')
return NOTEQUALTO;
retract(1);
return LNOT;
case 63: /* = - equal (assignment) or equal to */
if ((c = nextchar()) == 0)
return (0);
if (c == '=')
return EQUALTO;
retract(1);
return EQUAL;
case 7: /* Identifier */
if ((c = nextchar()) == 0)
return (0);
if (isalnum(c) || (c == '_') || (c == '.') || (c == '$')) {
state = 7;
} else {
retract(1);
return (ID);
}
break;
case 75: /* Special identifier $ */
if ((c = nextchar()) == 0)
return (0);
if (isalnum(c) || (c == '_') || (c == '*') || (c == '&')) {
state = 7;
} else {
retract(1);
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')) {
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);
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')) {
return (NUM_FLOAT);
} else {
retract(1);
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;
return (NUM_INT);
}
break;
case 83:
/* Might be a hexadecimal 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);
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);
return (NUM_INT);
}
break;
case 85:
/* This is an hex number */
if ((c = nextchar()) == 0)
return (0);
if (isxdigit(c))
state = 85;
else if ((c == 'l') || (c == 'L')) {
state = 87;
} else if ((c == 'u') || (c == 'U')) {
state = 88;
} else {
retract(1);
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')) {
return (NUM_FLOAT);
} else {
retract(1);
return (NUM_FLOAT);
}
break;
case 87:
/* A long integer of some sort */
if ((c = nextchar()) == 0)
return (NUM_LONG);
if ((c == 'u') || (c == 'U')) {
return (NUM_ULONG);
} else if ((c == 'l') || (c == 'L')) {
state = 870;
} else {
retract(1);
return (NUM_LONG);
}
break;
case 870:
if ((c = nextchar()) == 0)
return (NUM_LONGLONG);
if ((c == 'u') || (c == 'U')) {
return (NUM_ULONGLONG);
} else {
retract(1);
return (NUM_LONGLONG);
}
case 88:
/* An unsigned integer of some sort */
if ((c = nextchar()) == 0)
return (NUM_UNSIGNED);
if ((c == 'l') || (c == 'L')) {
state = 880;
} else {
retract(1);
return (NUM_UNSIGNED);
}
break;
case 880:
if ((c = nextchar()) == 0)
return (NUM_ULONG);
if ((c == 'l') || (c == 'L'))
return (NUM_ULONGLONG);
else {
retract(1);
return (NUM_ULONG);
}
case 9:
/* Parse a character constant. ie. 'a' */
if ((c = nextchar()) == 0)
return (0);
if (c == '\\') {
yylen--;
get_escape();
} else if (c == '\'') {
yytext[yylen - 1] = 0;
yylval.str = NewString(yytext + 1);
if (yylen == 2) {
Swig_error(cparse_file, cparse_line, "Empty character constant\n");
}
return (CHARCONST);
}
break;
case 100:
if ((c = nextchar()) == 0)
return (0);
if (isdigit(c))
state = 81;
else {
retract(1);
return (PERIOD);
}
break;
case 200:
if ((c = nextchar()) == 0)
return (0);
if (c == '`') {
yytext[yylen - 1] = 0;
yylval.type = NewString(yytext);
return (TYPE_RAW);
}
break;
default:
Swig_error(cparse_file, cparse_line, "Illegal character '%c'=%d.\n", c, c);
state = 0;
return (ILLEGAL);
}
}
}
static int check_typedef = 0;
void scanner_check_typedef() {
check_typedef = 1;
}
void scanner_ignore_typedef() {
check_typedef = 0;
}
void scanner_last_id(int x) {
/* printf("Setting last_id = %d\n", x); */
last_id = x;
}
void scanner_clear_rename() {
rename_active = 0;
}
static int next_token = 0;
void scanner_next_token(int tok) {
next_token = tok;
}
/* ----------------------------------------------------------------------------
* int yylex()
*
* Gets the lexene and returns tokens.
* ------------------------------------------------------------------------- */
int yylex(void) {
int l;
if (!scan_init) {
scanner_init();
}
if (next_token) {
l = next_token;
next_token = 0;
return l;
}
/* Printf(stdout,"%d\n", last_id); */
l = yylook();
if (l == NONID) {
last_id = 1;
} else {
last_id = 0;
}
/*
yytext[yylen]= 0;
Printf(stdout,"%d '%s' %d\n", l, yytext, last_id);
*/
/* We got some sort of non-white space object. We set the start_line
variable unless it has already been set */
if (!cparse_start_line) {
cparse_start_line = cparse_line;
}
/* Copy the lexene */
yytext[yylen] = 0;
switch (l) {
case NUM_INT:
case NUM_FLOAT:
case NUM_ULONG:
case NUM_LONG:
case NUM_UNSIGNED:
case NUM_LONGLONG:
case NUM_ULONGLONG:
if (l == NUM_INT)
yylval.dtype.type = T_INT;
if (l == NUM_FLOAT)
yylval.dtype.type = T_DOUBLE;
if (l == NUM_ULONG)
yylval.dtype.type = T_ULONG;
if (l == NUM_LONG)
yylval.dtype.type = T_LONG;
if (l == NUM_UNSIGNED)
yylval.dtype.type = T_UINT;
if (l == NUM_LONGLONG)
yylval.dtype.type = T_LONGLONG;
if (l == NUM_ULONGLONG)
yylval.dtype.type = T_ULONGLONG;
yylval.dtype.val = NewString(yytext);
yylval.dtype.bitfield = 0;
yylval.dtype.throws = 0;
return (l);
case ID:
if (yytext[0] != '%') {
/* Look for keywords now */
if (strcmp(yytext, "int") == 0) {
yylval.type = NewSwigType(T_INT);
return (TYPE_INT);
}
if (strcmp(yytext, "double") == 0) {
yylval.type = NewSwigType(T_DOUBLE);
return (TYPE_DOUBLE);
}
if (strcmp(yytext, "void") == 0) {
yylval.type = NewSwigType(T_VOID);
return (TYPE_VOID);
}
if (strcmp(yytext, "char") == 0) {
yylval.type = NewSwigType(T_CHAR);
return (TYPE_CHAR);
}
if (strcmp(yytext, "wchar_t") == 0) {
yylval.type = NewSwigType(T_WCHAR);
return (TYPE_WCHAR);
}
if (strcmp(yytext, "short") == 0) {
yylval.type = NewSwigType(T_SHORT);
return (TYPE_SHORT);
}
if (strcmp(yytext, "long") == 0) {
yylval.type = NewSwigType(T_LONG);
return (TYPE_LONG);
}
if (strcmp(yytext, "float") == 0) {
yylval.type = NewSwigType(T_FLOAT);
return (TYPE_FLOAT);
}
if (strcmp(yytext, "signed") == 0) {
yylval.type = NewSwigType(T_INT);
return (TYPE_SIGNED);
}
if (strcmp(yytext, "unsigned") == 0) {
yylval.type = NewSwigType(T_UINT);
return (TYPE_UNSIGNED);
}
if (strcmp(yytext, "bool") == 0) {
yylval.type = NewSwigType(T_BOOL);
return (TYPE_BOOL);
}
/* Non ISO (Windows) C extensions */
if (strcmp(yytext, "__int8") == 0) {
yylval.type = NewString(yytext);
return (TYPE_NON_ISO_INT8);
}
if (strcmp(yytext, "__int16") == 0) {
yylval.type = NewString(yytext);
return (TYPE_NON_ISO_INT16);
}
if (strcmp(yytext, "__int32") == 0) {
yylval.type = NewString(yytext);
return (TYPE_NON_ISO_INT32);
}
if (strcmp(yytext, "__int64") == 0) {
yylval.type = NewString(yytext);
return (TYPE_NON_ISO_INT64);
}
/* C++ keywords */
if (cparse_cplusplus) {
if (strcmp(yytext, "and") == 0)
return (LAND);
if (strcmp(yytext, "or") == 0)
return (LOR);
if (strcmp(yytext, "not") == 0)
return (LNOT);
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) {
String *s = NewString("operator");
int c;
int state = 0;
int sticky = 0;
int isconversion = 0;
int count = 0;
int start_template = 0;
int end_template = 0;
while ((c = nextchar())) {
if (((c == '(') || (c == ';')) && state) {
retract(1);
break;
}
if ((c == '<') && !start_template) {
int fcount = 1;
int c2 = nextchar();
while (isspace(c2)) {
c2 = nextchar();
++fcount;
}
if (isalpha(c2) || c2 == ':') {
start_template = count;
}
retract(fcount);
}
if ((c == '>') && start_template)
end_template = count;
count++;
if (!isspace(c)) {
if ((!state) && (isalpha(c))) {
isconversion = 1;
}
if (!state && !sticky)
Putc(' ', s);
Putc(c, s);
sticky = 0;
state = 1;
} else {
if (!sticky)
Putc(' ', s);
sticky = 1;
}
}
Chop(s);
if (swigtemplate_active && start_template && end_template) {
/*
Manage the case:
%template(foo) operator()<int>;
ie, don't count <int> as part of the operator.
*/
int len = Len(s);
char *end = Char(s);
int tlen = end_template - start_template + 1;
int nlen = len - tlen;
if (nlen) {
String *ns = 0;
while (isspace((unsigned char) end[--nlen]));
ns = NewStringWithSize(s, nlen + 1);
retract(count - start_template);
Delete(s);
s = ns;
count = start_template;
isconversion = 0;
}
}
yylval.str = s;
while (Replaceall(s, "[ ", "["));
if (isconversion) {
String *ns = Swig_symbol_string_qualify(s, 0);
yylval.str = ns;
}
if (isconversion && !rename_active) {
char *t = Char(s) + 9;
if (!((strcmp(t, "new") == 0)
|| (strcmp(t, "delete") == 0)
|| (strcmp(t, "new[]") == 0)
|| (strcmp(t, "delete[]") == 0)
|| (strcmp(t, "and") == 0)
|| (strcmp(t, "and_eq") == 0)
|| (strcmp(t, "bitand") == 0)
|| (strcmp(t, "bitor") == 0)
|| (strcmp(t, "compl") == 0)
|| (strcmp(t, "not") == 0)
|| (strcmp(t, "not_eq") == 0)
|| (strcmp(t, "or") == 0)
|| (strcmp(t, "or_eq") == 0)
|| (strcmp(t, "xor") == 0)
|| (strcmp(t, "xor_eq") == 0)
)) {
/* retract(strlen(t)); */
retract(count);
return COPERATOR;
}
}
return (OPERATOR);
}
if (strcmp(yytext, "throw") == 0)
return (THROW);
if (strcmp(yytext, "try") == 0)
return (yylex());
if (strcmp(yytext, "catch") == 0)
return (CATCH);
if (strcmp(yytext, "inline") == 0)
return (yylex());
if (strcmp(yytext, "mutable") == 0)
return (yylex());
if (strcmp(yytext, "restrict") == 0)
return (yylex());
if (strcmp(yytext, "explicit") == 0)
return (EXPLICIT);
if (strcmp(yytext, "export") == 0)
return (yylex());
if (strcmp(yytext, "typename") == 0)
return (TYPENAME);
if (strcmp(yytext, "template") == 0) {
yylval.ivalue = cparse_line;
return (TEMPLATE);
}
if (strcmp(yytext, "delete") == 0) {
return (DELETE_KW);
}
if (strcmp(yytext, "using") == 0) {
return (USING);
}
if (strcmp(yytext, "namespace") == 0) {
return (NAMESPACE);
}
} else {
if (strcmp(yytext, "class") == 0) {
Swig_warning(WARN_PARSE_CLASS_KEYWORD, cparse_file, cparse_line, "class keyword used, but not in C++ mode.\n");
}
if (strcmp(yytext, "complex") == 0) {
yylval.type = NewSwigType(T_COMPLEX);
return (TYPE_COMPLEX);
}
}
/* Objective-C keywords */
#ifdef OBJECTIVEC
if ((ObjC) && (yytext[0] == '@')) {
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);
}
#endif
/* Misc keywords */
if (strcmp(yytext, "extern") == 0)
return (EXTERN);
if (strcmp(yytext, "const") == 0)
return (CONST_QUAL);
if (strcmp(yytext, "static") == 0)
return (STATIC);
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, "typedef") == 0) {
yylval.ivalue = 0;
return (TYPEDEF);
}
/* Ignored keywords */
if (strcmp(yytext, "volatile") == 0)
return (VOLATILE);
if (strcmp(yytext, "register") == 0)
return (REGISTER);
if (strcmp(yytext, "inline") == 0)
return (yylex());
if (strcmp(yytext, "restrict") == 0)
return (yylex());
/* SWIG directives */
} else {
if (strcmp(yytext, "%module") == 0)
return (MODULE);
if (strcmp(yytext, "%insert") == 0)
return (INSERT);
if (strcmp(yytext, "%name") == 0)
return (NAME);
if (strcmp(yytext, "%rename") == 0) {
rename_active = 1;
return (RENAME);
}
if (strcmp(yytext, "%namewarn") == 0) {
rename_active = 1;
return (NAMEWARN);
}
if (strcmp(yytext, "%includefile") == 0)
return (INCLUDE);
if (strcmp(yytext, "%val") == 0) {
Swig_warning(WARN_DEPRECATED_VAL, cparse_file, cparse_line, "%%val directive deprecated (ignored).\n");
return (yylex());
}
if (strcmp(yytext, "%out") == 0) {
Swig_warning(WARN_DEPRECATED_OUT, cparse_file, cparse_line, "%%out directive deprecated (ignored).\n");
return (yylex());
}
if (strcmp(yytext, "%constant") == 0)
return (CONSTANT);
if (strcmp(yytext, "%typedef") == 0) {
yylval.ivalue = 1;
return (TYPEDEF);
}
if (strcmp(yytext, "%native") == 0)
return (NATIVE);
if (strcmp(yytext, "%pragma") == 0)
return (PRAGMA);
if (strcmp(yytext, "%extend") == 0)
return (EXTEND);
if (strcmp(yytext, "%fragment") == 0)
return (FRAGMENT);
if (strcmp(yytext, "%inline") == 0)
return (INLINE);
if (strcmp(yytext, "%typemap") == 0)
return (TYPEMAP);
if (strcmp(yytext, "%feature") == 0)
return (FEATURE);
if (strcmp(yytext, "%except") == 0)
return (EXCEPT);
if (strcmp(yytext, "%importfile") == 0)
return (IMPORT);
if (strcmp(yytext, "%echo") == 0)
return (ECHO);
if (strcmp(yytext, "%apply") == 0)
return (APPLY);
if (strcmp(yytext, "%clear") == 0)
return (CLEAR);
if (strcmp(yytext, "%types") == 0)
return (TYPES);
if (strcmp(yytext, "%parms") == 0)
return (PARMS);
if (strcmp(yytext, "%varargs") == 0)
return (VARARGS);
if (strcmp(yytext, "%template") == 0) {
swigtemplate_active = 1;
return (SWIGTEMPLATE);
}
if (strcmp(yytext, "%warn") == 0)
return (WARN);
}
/* Have an unknown identifier, as a last step, we'll do a typedef lookup on it. */
/* Need to fix this */
if (check_typedef) {
if (SwigType_istypedef(yytext)) {
yylval.type = NewString(yytext);
return (TYPE_TYPEDEF);
}
}
yylval.id = Swig_copy_string(yytext);
last_id = 1;
return (ID);
case POUND:
return yylex();
default:
return (l);
}
}