/* ----------------------------------------------------------------------------- * This file is part of SWIG, which is licensed as a whole under version 3 * (or any later version) of the GNU General Public License. Some additional * terms also apply to certain portions of SWIG. The full details of the SWIG * license and copyrights can be found in the LICENSE and COPYRIGHT files * included with the SWIG source code as distributed by the SWIG developers * and at http://www.swig.org/legal.html. * * scanner.c * * This file implements a general purpose C/C++ compatible lexical scanner. * This scanner isn't intended to be plugged directly into a parser built * with yacc. Rather, it contains a lot of generic code that could be used * to easily construct yacc-compatible scanners. * ----------------------------------------------------------------------------- */ char cvsroot_scanner_c[] = "$Id: scanner.c 12536 2011-03-14 07:22:08Z wsfulton $"; #include "swig.h" #include extern String *cparse_file; extern int cparse_line; extern int cparse_cplusplus; extern int cparse_start_line; struct Scanner { String *text; /* Current token value */ List *scanobjs; /* Objects being scanned */ String *str; /* Current object being scanned */ char *idstart; /* Optional identifier start characters */ int nexttoken; /* Next token to be returned */ int start_line; /* Starting line of certain declarations */ int line; int yylen; /* Length of text pushed into text */ String *file; String *error; /* Last error message (if any) */ int error_line; /* Error line number */ int freeze_line; /* Suspend line number updates */ }; typedef struct Locator { String *filename; int line_number; struct Locator *next; } Locator; static int follow_locators = 0; /* ----------------------------------------------------------------------------- * NewScanner() * * Create a new scanner object * ----------------------------------------------------------------------------- */ Scanner *NewScanner(void) { Scanner *s; s = (Scanner *) malloc(sizeof(Scanner)); s->line = 1; s->file = 0; s->nexttoken = -1; s->start_line = 1; s->yylen = 0; s->idstart = NULL; s->scanobjs = NewList(); s->text = NewStringEmpty(); s->str = 0; s->error = 0; s->freeze_line = 0; return s; } /* ----------------------------------------------------------------------------- * DelScanner() * * Delete a scanner object. * ----------------------------------------------------------------------------- */ void DelScanner(Scanner * s) { assert(s); Delete(s->scanobjs); Delete(s->text); Delete(s->file); Delete(s->error); Delete(s->str); free(s->idstart); free(s); } /* ----------------------------------------------------------------------------- * Scanner_clear() * * Clear the contents of a scanner object. * ----------------------------------------------------------------------------- */ void Scanner_clear(Scanner * s) { assert(s); Delete(s->str); Clear(s->text); Clear(s->scanobjs); Delete(s->error); s->str = 0; s->error = 0; s->line = 1; s->nexttoken = -1; s->start_line = 0; s->yylen = 0; } /* ----------------------------------------------------------------------------- * Scanner_push() * * Push some new text into the scanner. The scanner will start parsing this text * immediately before returning to the old text. * ----------------------------------------------------------------------------- */ void Scanner_push(Scanner * s, String *txt) { assert(s && txt); Push(s->scanobjs, txt); if (s->str) { Setline(s->str,s->line); Delete(s->str); } s->str = txt; DohIncref(s->str); s->line = Getline(txt); } /* ----------------------------------------------------------------------------- * Scanner_pushtoken() * * Push a token into the scanner. This token will be returned on the next * call to Scanner_token(). * ----------------------------------------------------------------------------- */ void Scanner_pushtoken(Scanner * s, int nt, const_String_or_char_ptr val) { assert(s); assert((nt >= 0) && (nt < SWIG_MAXTOKENS)); s->nexttoken = nt; if ( Char(val) != Char(s->text) ) { Clear(s->text); Append(s->text,val); } } /* ----------------------------------------------------------------------------- * Scanner_set_location() * * Set the file and line number location of the scanner. * ----------------------------------------------------------------------------- */ void Scanner_set_location(Scanner * s, String *file, int line) { Setline(s->str, line); Setfile(s->str, file); s->line = line; } /* ----------------------------------------------------------------------------- * Scanner_file() * * Get the current file. * ----------------------------------------------------------------------------- */ String *Scanner_file(Scanner * s) { return Getfile(s->str); } /* ----------------------------------------------------------------------------- * Scanner_line() * * Get the current line number * ----------------------------------------------------------------------------- */ int Scanner_line(Scanner * s) { return s->line; } /* ----------------------------------------------------------------------------- * Scanner_start_line() * * Get the line number on which the current token starts * ----------------------------------------------------------------------------- */ int Scanner_start_line(Scanner * s) { return s->start_line; } /* ----------------------------------------------------------------------------- * Scanner_idstart() * * Change the set of additional characters that can be used to start an identifier. * ----------------------------------------------------------------------------- */ void Scanner_idstart(Scanner * s, const char *id) { free(s->idstart); s->idstart = Swig_copy_string(id); } /* ----------------------------------------------------------------------------- * nextchar() * * Returns the next character from the scanner or 0 if end of the string. * ----------------------------------------------------------------------------- */ static char nextchar(Scanner * s) { int nc; if (!s->str) return 0; while ((nc = Getc(s->str)) == EOF) { Delete(s->str); s->str = 0; Delitem(s->scanobjs, 0); if (Len(s->scanobjs) == 0) return 0; s->str = Getitem(s->scanobjs, 0); if (s->str) { s->line = Getline(s->str); DohIncref(s->str); } } if ((nc == '\n') && (!s->freeze_line)) s->line++; Putc(nc,s->text); return (char)nc; } /* ----------------------------------------------------------------------------- * set_error() * * Sets error information on the scanner. * ----------------------------------------------------------------------------- */ static void set_error(Scanner *s, int line, const_String_or_char_ptr msg) { s->error_line = line; s->error = NewString(msg); } /* ----------------------------------------------------------------------------- * Scanner_errmsg() * Scanner_errline() * * Returns error information (if any) * ----------------------------------------------------------------------------- */ String *Scanner_errmsg(Scanner *s) { return s->error; } int Scanner_errline(Scanner *s) { return s->error_line; } /* ----------------------------------------------------------------------------- * freeze_line() * * Freezes the current line number. * ----------------------------------------------------------------------------- */ static void freeze_line(Scanner *s, int val) { s->freeze_line = val; } /* ----------------------------------------------------------------------------- * retract() * * Retract n characters * ----------------------------------------------------------------------------- */ static void retract(Scanner * s, int n) { int i, l; char *str; str = Char(s->text); l = Len(s->text); assert(n <= l); for (i = 0; i < n; i++) { if (str[l - 1] == '\n') { if (!s->freeze_line) s->line--; } Seek(s->str, -1, SEEK_CUR); Delitem(s->text, DOH_END); } } /* ----------------------------------------------------------------------------- * get_escape() * * Get escape sequence. Called when a backslash is found in a string * ----------------------------------------------------------------------------- */ static void get_escape(Scanner *s) { int result = 0; int state = 0; int c; while (1) { c = nextchar(s); if (c == 0) break; switch (state) { case 0: if (c == 'n') { Delitem(s->text, DOH_END); Append(s->text,"\n"); return; } if (c == 'r') { Delitem(s->text, DOH_END); Append(s->text,"\r"); return; } if (c == 't') { Delitem(s->text, DOH_END); Append(s->text,"\t"); return; } if (c == 'a') { Delitem(s->text, DOH_END); Append(s->text,"\a"); return; } if (c == 'b') { Delitem(s->text, DOH_END); Append(s->text,"\b"); return; } if (c == 'f') { Delitem(s->text, DOH_END); Append(s->text,"\f"); return; } if (c == '\\') { Delitem(s->text, DOH_END); Append(s->text,"\\"); return; } if (c == 'v') { Delitem(s->text, DOH_END); Append(s->text,"\v"); return; } if (c == 'e') { Delitem(s->text, DOH_END); Append(s->text,"\033"); return; } if (c == '\'') { Delitem(s->text, DOH_END); Append(s->text,"\'"); return; } if (c == '\"') { Delitem(s->text, DOH_END); Append(s->text,"\""); return; } if (c == '\n') { Delitem(s->text, DOH_END); return; } if (isdigit(c)) { state = 10; result = (c - '0'); Delitem(s->text, DOH_END); } else if (c == 'x') { state = 20; Delitem(s->text, DOH_END); } else { char tmp[3]; tmp[0] = '\\'; tmp[1] = (char)c; tmp[2] = 0; Delitem(s->text, DOH_END); Append(s->text, tmp); return; } break; case 10: if (!isdigit(c)) { retract(s,1); Putc((char)result,s->text); return; } result = (result << 3) + (c - '0'); Delitem(s->text, DOH_END); break; case 20: if (!isxdigit(c)) { retract(s,1); Putc((char)result, s->text); return; } if (isdigit(c)) result = (result << 4) + (c - '0'); else result = (result << 4) + (10 + tolower(c) - 'a'); Delitem(s->text, DOH_END); break; } } return; } /* ----------------------------------------------------------------------------- * look() * * Return the raw value of the next token. * ----------------------------------------------------------------------------- */ static int look(Scanner * s) { int state; int c = 0; state = 0; Clear(s->text); s->start_line = s->line; Setfile(s->text, Getfile(s->str)); while (1) { switch (state) { case 0: if ((c = nextchar(s)) == 0) return (0); /* Process delimiters */ if (c == '\n') { return SWIG_TOKEN_ENDLINE; } else if (!isspace(c)) { retract(s, 1); state = 1000; Clear(s->text); Setline(s->text, s->line); Setfile(s->text, Getfile(s->str)); } break; case 1000: if ((c = nextchar(s)) == 0) return (0); if (c == '%') state = 4; /* Possibly a SWIG directive */ /* Look for possible identifiers */ else if ((isalpha(c)) || (c == '_') || (s->idstart && strchr(s->idstart, c))) state = 7; /* Look for single character symbols */ else if (c == '(') return SWIG_TOKEN_LPAREN; else if (c == ')') return SWIG_TOKEN_RPAREN; else if (c == ';') return SWIG_TOKEN_SEMI; else if (c == ',') return SWIG_TOKEN_COMMA; else if (c == '*') state = 220; else if (c == '}') return SWIG_TOKEN_RBRACE; else if (c == '{') return SWIG_TOKEN_LBRACE; else if (c == '=') state = 33; else if (c == '+') state = 200; else if (c == '-') state = 210; else if (c == '&') state = 31; else if (c == '|') state = 32; else if (c == '^') state = 230; else if (c == '<') state = 60; else if (c == '>') state = 61; else if (c == '~') return SWIG_TOKEN_NOT; else if (c == '!') state = 3; else if (c == '\\') return SWIG_TOKEN_BACKSLASH; else if (c == '[') return SWIG_TOKEN_LBRACKET; else if (c == ']') return SWIG_TOKEN_RBRACKET; else if (c == '@') return SWIG_TOKEN_AT; else if (c == '$') state = 75; else if (c == '#') return SWIG_TOKEN_POUND; else if (c == '?') return SWIG_TOKEN_QUESTION; /* Look for multi-character sequences */ else if (c == '/') { state = 1; /* Comment (maybe) */ s->start_line = s->line; } else if (c == '\"') { state = 2; /* Possibly a string */ s->start_line = s->line; Clear(s->text); } else if (c == ':') state = 5; /* maybe double colon */ else if (c == '0') state = 83; /* An octal or hex value */ else if (c == '\'') { s->start_line = s->line; Clear(s->text); state = 9; /* A character constant */ } else if (c == '`') { s->start_line = s->line; Clear(s->text); state = 900; } else if (c == '.') state = 100; /* Maybe a number, maybe just a period */ else if (isdigit(c)) state = 8; /* A numerical value */ else state = 99; /* An error */ break; case 1: /* Comment block */ if ((c = nextchar(s)) == 0) return (0); if (c == '/') { state = 10; /* C++ style comment */ Clear(s->text); Setline(s->text, Getline(s->str)); Setfile(s->text, Getfile(s->str)); Append(s->text, "//"); } else if (c == '*') { state = 11; /* C style comment */ Clear(s->text); Setline(s->text, Getline(s->str)); Setfile(s->text, Getfile(s->str)); Append(s->text, "/*"); } else if (c == '=') { return SWIG_TOKEN_DIVEQUAL; } else { retract(s, 1); return SWIG_TOKEN_SLASH; } break; case 10: /* C++ style comment */ if ((c = nextchar(s)) == 0) { Swig_error(cparse_file, cparse_start_line, "Unterminated comment\n"); return SWIG_TOKEN_ERROR; } if (c == '\n') { retract(s,1); return SWIG_TOKEN_COMMENT; } else { state = 10; } break; case 11: /* C style comment block */ if ((c = nextchar(s)) == 0) { Swig_error(cparse_file, cparse_start_line, "Unterminated comment\n"); return SWIG_TOKEN_ERROR; } if (c == '*') { state = 12; } else { state = 11; } break; case 12: /* Still in C style comment */ if ((c = nextchar(s)) == 0) { Swig_error(cparse_file, cparse_start_line, "Unterminated comment\n"); return SWIG_TOKEN_ERROR; } if (c == '*') { state = 12; } else if (c == '/') { return SWIG_TOKEN_COMMENT; } else { state = 11; } break; case 2: /* Processing a string */ if ((c = nextchar(s)) == 0) { Swig_error(cparse_file, cparse_start_line, "Unterminated string\n"); return SWIG_TOKEN_ERROR; } if (c == '\"') { Delitem(s->text, DOH_END); return SWIG_TOKEN_STRING; } else if (c == '\\') { Delitem(s->text, DOH_END); get_escape(s); } else state = 2; break; case 3: /* Maybe a not equals */ if ((c = nextchar(s)) == 0) return SWIG_TOKEN_LNOT; else if (c == '=') return SWIG_TOKEN_NOTEQUAL; else { retract(s, 1); return SWIG_TOKEN_LNOT; } break; case 31: /* AND or Logical AND or ANDEQUAL */ if ((c = nextchar(s)) == 0) return SWIG_TOKEN_AND; else if (c == '&') return SWIG_TOKEN_LAND; else if (c == '=') return SWIG_TOKEN_ANDEQUAL; else { retract(s, 1); return SWIG_TOKEN_AND; } break; case 32: /* OR or Logical OR */ if ((c = nextchar(s)) == 0) return SWIG_TOKEN_OR; else if (c == '|') return SWIG_TOKEN_LOR; else if (c == '=') return SWIG_TOKEN_OREQUAL; else { retract(s, 1); return SWIG_TOKEN_OR; } break; case 33: /* EQUAL or EQUALTO */ if ((c = nextchar(s)) == 0) return SWIG_TOKEN_EQUAL; else if (c == '=') return SWIG_TOKEN_EQUALTO; else { retract(s, 1); return SWIG_TOKEN_EQUAL; } break; case 4: /* A wrapper generator directive (maybe) */ if ((c = nextchar(s)) == 0) return SWIG_TOKEN_PERCENT; if (c == '{') { state = 40; /* Include block */ Clear(s->text); Setline(s->text, Getline(s->str)); Setfile(s->text, Getfile(s->str)); s->start_line = s->line; } else if (s->idstart && strchr(s->idstart, '%') && ((isalpha(c)) || (c == '_'))) { state = 7; } else if (c == '=') { return SWIG_TOKEN_MODEQUAL; } else { retract(s, 1); return SWIG_TOKEN_PERCENT; } break; case 40: /* Process an include block */ if ((c = nextchar(s)) == 0) { Swig_error(cparse_file, cparse_start_line, "Unterminated block\n"); return SWIG_TOKEN_ERROR; } if (c == '%') state = 41; break; case 41: /* Still processing include block */ if ((c = nextchar(s)) == 0) { set_error(s,s->start_line,"Unterminated code block"); return 0; } if (c == '}') { Delitem(s->text, DOH_END); Delitem(s->text, DOH_END); Seek(s->text,0,SEEK_SET); return SWIG_TOKEN_CODEBLOCK; } else { state = 40; } break; case 5: /* Maybe a double colon */ if ((c = nextchar(s)) == 0) return SWIG_TOKEN_COLON; if (c == ':') state = 50; else { retract(s, 1); return SWIG_TOKEN_COLON; } break; case 50: /* DCOLON, DCOLONSTAR */ if ((c = nextchar(s)) == 0) return SWIG_TOKEN_DCOLON; else if (c == '*') return SWIG_TOKEN_DCOLONSTAR; else { retract(s, 1); return SWIG_TOKEN_DCOLON; } break; case 60: /* shift operators */ if ((c = nextchar(s)) == 0) return SWIG_TOKEN_LESSTHAN; if (c == '<') state = 240; else if (c == '=') return SWIG_TOKEN_LTEQUAL; else { retract(s, 1); return SWIG_TOKEN_LESSTHAN; } break; case 61: if ((c = nextchar(s)) == 0) return SWIG_TOKEN_GREATERTHAN; if (c == '>') state = 250; else if (c == '=') return SWIG_TOKEN_GTEQUAL; else { retract(s, 1); return SWIG_TOKEN_GREATERTHAN; } break; case 7: /* Identifier */ if ((c = nextchar(s)) == 0) state = 71; else if (isalnum(c) || (c == '_') || (c == '$')) { state = 7; } else { retract(s, 1); state = 71; } break; case 71: /* Identifier or true/false */ if (cparse_cplusplus) { if (Strcmp(s->text, "true") == 0) return SWIG_TOKEN_BOOL; else if (Strcmp(s->text, "false") == 0) return SWIG_TOKEN_BOOL; } return SWIG_TOKEN_ID; break; case 75: /* Special identifier $ */ if ((c = nextchar(s)) == 0) return SWIG_TOKEN_DOLLAR; if (isalnum(c) || (c == '_') || (c == '*') || (c == '&')) { state = 7; } else { retract(s,1); if (Len(s->text) == 1) return SWIG_TOKEN_DOLLAR; state = 71; } break; case 8: /* A numerical digit */ if ((c = nextchar(s)) == 0) return SWIG_TOKEN_INT; if (c == '.') { state = 81; } else if ((c == 'e') || (c == 'E')) { state = 82; } else if ((c == 'f') || (c == 'F')) { Delitem(s->text, DOH_END); return SWIG_TOKEN_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(s, 1); return SWIG_TOKEN_INT; } break; case 81: /* A floating pointer number of some sort */ if ((c = nextchar(s)) == 0) return SWIG_TOKEN_DOUBLE; if (isdigit(c)) state = 81; else if ((c == 'e') || (c == 'E')) state = 820; else if ((c == 'f') || (c == 'F')) { Delitem(s->text, DOH_END); return SWIG_TOKEN_FLOAT; } else if ((c == 'l') || (c == 'L')) { Delitem(s->text, DOH_END); return SWIG_TOKEN_DOUBLE; } else { retract(s, 1); return (SWIG_TOKEN_DOUBLE); } break; case 82: if ((c = nextchar(s)) == 0) { retract(s, 1); return SWIG_TOKEN_INT; } if ((isdigit(c)) || (c == '-') || (c == '+')) state = 86; else { retract(s, 2); return (SWIG_TOKEN_INT); } break; case 820: /* Like case 82, but we've seen a decimal point. */ if ((c = nextchar(s)) == 0) { retract(s, 1); return SWIG_TOKEN_DOUBLE; } if ((isdigit(c)) || (c == '-') || (c == '+')) state = 86; else { retract(s, 2); return (SWIG_TOKEN_DOUBLE); } break; case 83: /* Might be a hexadecimal or octal number */ if ((c = nextchar(s)) == 0) return SWIG_TOKEN_INT; 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(s, 1); return SWIG_TOKEN_INT; } break; case 84: /* This is an octal number */ if ((c = nextchar(s)) == 0) return SWIG_TOKEN_INT; if (isdigit(c)) state = 84; else if ((c == 'l') || (c == 'L')) { state = 87; } else if ((c == 'u') || (c == 'U')) { state = 88; } else { retract(s, 1); return SWIG_TOKEN_INT; } break; case 85: /* This is an hex number */ if ((c = nextchar(s)) == 0) return SWIG_TOKEN_INT; if (isxdigit(c)) state = 85; else if ((c == 'l') || (c == 'L')) { state = 87; } else if ((c == 'u') || (c == 'U')) { state = 88; } else { retract(s, 1); return SWIG_TOKEN_INT; } break; case 86: /* Rest of floating point number */ if ((c = nextchar(s)) == 0) return SWIG_TOKEN_DOUBLE; if (isdigit(c)) state = 86; else if ((c == 'f') || (c == 'F')) { Delitem(s->text, DOH_END); return SWIG_TOKEN_FLOAT; } else if ((c == 'l') || (c == 'L')) { Delitem(s->text, DOH_END); return SWIG_TOKEN_DOUBLE; } else { retract(s, 1); return SWIG_TOKEN_DOUBLE; } break; case 87: /* A long integer of some sort */ if ((c = nextchar(s)) == 0) return SWIG_TOKEN_LONG; if ((c == 'u') || (c == 'U')) { return SWIG_TOKEN_ULONG; } else if ((c == 'l') || (c == 'L')) { state = 870; } else { retract(s, 1); return SWIG_TOKEN_LONG; } break; /* A long long integer */ case 870: if ((c = nextchar(s)) == 0) return SWIG_TOKEN_LONGLONG; if ((c == 'u') || (c == 'U')) { return SWIG_TOKEN_ULONGLONG; } else { retract(s, 1); return SWIG_TOKEN_LONGLONG; } /* An unsigned number */ case 88: if ((c = nextchar(s)) == 0) return SWIG_TOKEN_UINT; if ((c == 'l') || (c == 'L')) { state = 880; } else { retract(s, 1); return SWIG_TOKEN_UINT; } break; /* Possibly an unsigned long long or unsigned long */ case 880: if ((c = nextchar(s)) == 0) return SWIG_TOKEN_ULONG; if ((c == 'l') || (c == 'L')) return SWIG_TOKEN_ULONGLONG; else { retract(s, 1); return SWIG_TOKEN_ULONG; } /* A character constant */ case 9: if ((c = nextchar(s)) == 0) { Swig_error(cparse_file, cparse_start_line, "Unterminated character constant\n"); return SWIG_TOKEN_ERROR; } if (c == '\'') { Delitem(s->text, DOH_END); return (SWIG_TOKEN_CHAR); } else if (c == '\\') { Delitem(s->text, DOH_END); get_escape(s); } break; /* A period or maybe a floating point number */ case 100: if ((c = nextchar(s)) == 0) return (0); if (isdigit(c)) state = 81; else { retract(s, 1); return SWIG_TOKEN_PERIOD; } break; case 200: /* PLUS, PLUSPLUS, PLUSEQUAL */ if ((c = nextchar(s)) == 0) return SWIG_TOKEN_PLUS; else if (c == '+') return SWIG_TOKEN_PLUSPLUS; else if (c == '=') return SWIG_TOKEN_PLUSEQUAL; else { retract(s, 1); return SWIG_TOKEN_PLUS; } break; case 210: /* MINUS, MINUSMINUS, MINUSEQUAL, ARROW */ if ((c = nextchar(s)) == 0) return SWIG_TOKEN_MINUS; else if (c == '-') return SWIG_TOKEN_MINUSMINUS; else if (c == '=') return SWIG_TOKEN_MINUSEQUAL; else if (c == '>') state = 211; else { retract(s, 1); return SWIG_TOKEN_MINUS; } break; case 211: /* ARROW, ARROWSTAR */ if ((c = nextchar(s)) == 0) return SWIG_TOKEN_ARROW; else if (c == '*') return SWIG_TOKEN_ARROWSTAR; else { retract(s, 1); return SWIG_TOKEN_ARROW; } break; case 220: /* STAR, TIMESEQUAL */ if ((c = nextchar(s)) == 0) return SWIG_TOKEN_STAR; else if (c == '=') return SWIG_TOKEN_TIMESEQUAL; else { retract(s, 1); return SWIG_TOKEN_STAR; } break; case 230: /* XOR, XOREQUAL */ if ((c = nextchar(s)) == 0) return SWIG_TOKEN_XOR; else if (c == '=') return SWIG_TOKEN_XOREQUAL; else { retract(s, 1); return SWIG_TOKEN_XOR; } break; case 240: /* LSHIFT, LSEQUAL */ if ((c = nextchar(s)) == 0) return SWIG_TOKEN_LSHIFT; else if (c == '=') return SWIG_TOKEN_LSEQUAL; else { retract(s, 1); return SWIG_TOKEN_LSHIFT; } break; case 250: /* RSHIFT, RSEQUAL */ if ((c = nextchar(s)) == 0) return SWIG_TOKEN_RSHIFT; else if (c == '=') return SWIG_TOKEN_RSEQUAL; else { retract(s, 1); return SWIG_TOKEN_RSHIFT; } break; /* An illegal character */ /* Reverse string */ case 900: if ((c = nextchar(s)) == 0) { Swig_error(cparse_file, cparse_start_line, "Unterminated character constant\n"); return SWIG_TOKEN_ERROR; } if (c == '`') { Delitem(s->text, DOH_END); return (SWIG_TOKEN_RSTRING); } break; default: return SWIG_TOKEN_ILLEGAL; } } } /* ----------------------------------------------------------------------------- * Scanner_token() * * Real entry point to return the next token. Returns 0 if at end of input. * ----------------------------------------------------------------------------- */ int Scanner_token(Scanner * s) { int t; Delete(s->error); if (s->nexttoken >= 0) { t = s->nexttoken; s->nexttoken = -1; return t; } s->start_line = 0; t = look(s); if (!s->start_line) { Setline(s->text,s->line); } else { Setline(s->text,s->start_line); } return t; } /* ----------------------------------------------------------------------------- * Scanner_text() * * Return the lexene associated with the last returned token. * ----------------------------------------------------------------------------- */ String *Scanner_text(Scanner * s) { return s->text; } /* ----------------------------------------------------------------------------- * Scanner_skip_line() * * Skips to the end of a line * ----------------------------------------------------------------------------- */ void Scanner_skip_line(Scanner * s) { char c; int done = 0; Clear(s->text); Setfile(s->text, Getfile(s->str)); Setline(s->text, s->line); while (!done) { if ((c = nextchar(s)) == 0) return; if (c == '\\') { c = nextchar(s); } else if (c == '\n') { done = 1; } } return; } /* ----------------------------------------------------------------------------- * Scanner_skip_balanced() * * Skips a piece of code enclosed in begin/end symbols such as '{...}' or * (...). Ignores symbols inside comments or strings. * ----------------------------------------------------------------------------- */ int Scanner_skip_balanced(Scanner * s, int startchar, int endchar) { char c; int num_levels = 1; int state = 0; char temp[2] = { 0, 0 }; String *locator = 0; temp[0] = (char) startchar; Clear(s->text); Setfile(s->text, Getfile(s->str)); Setline(s->text, s->line); Append(s->text, temp); while (num_levels > 0) { if ((c = nextchar(s)) == 0) { Delete(locator); return -1; } 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 if (c == startchar) { state = 0; num_levels++; } else state = 0; break; case 11: if (c == '\n') state = 0; else state = 11; break; case 12: /* first character inside C comment */ if (c == '*') state = 14; else if (c == '@') state = 40; else state = 13; break; case 13: if (c == '*') state = 14; break; case 14: /* possible end of C comment */ if (c == '*') state = 14; else if (c == '/') state = 0; else state = 13; 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; /* 40-45 SWIG locator checks - a C comment with contents starting: @SWIG */ case 40: state = (c == 'S') ? 41 : (c == '*') ? 14 : 13; break; case 41: state = (c == 'W') ? 42 : (c == '*') ? 14 : 13; break; case 42: state = (c == 'I') ? 43 : (c == '*') ? 14 : 13; break; case 43: state = (c == 'G') ? 44 : (c == '*') ? 14 : 13; if (c == 'G') { Delete(locator); locator = NewString("/*@SWIG"); } break; case 44: if (c == '*') state = 45; Putc(c, locator); break; case 45: /* end of SWIG locator in C comment */ if (c == '/') { state = 0; Putc(c, locator); Scanner_locator(s, locator); } else { /* malformed locator */ state = (c == '*') ? 14 : 13; } break; default: break; } } Delete(locator); return 0; } /* ----------------------------------------------------------------------------- * Scanner_isoperator() * * Returns 0 or 1 depending on whether or not a token corresponds to a C/C++ * operator. * ----------------------------------------------------------------------------- */ int Scanner_isoperator(int tokval) { if (tokval >= 100) return 1; return 0; } /* ---------------------------------------------------------------------- * locator() * * Support for locator strings. These are strings of the form * @SWIG:filename,line,id@ emitted by the SWIG preprocessor. They * are primarily used for macro line number reporting. * We just use the locator to mark when to activate/deactivate linecounting. * ---------------------------------------------------------------------- */ void Scanner_locator(Scanner *s, String *loc) { static Locator *locs = 0; static int expanding_macro = 0; if (!follow_locators) { if (Equal(loc, "/*@SWIG@*/")) { /* End locator. */ if (expanding_macro) --expanding_macro; } else { /* Begin locator. */ ++expanding_macro; } /* Freeze line number processing in Scanner */ freeze_line(s,expanding_macro); } else { int c; Locator *l; Seek(loc, 7, SEEK_SET); c = Getc(loc); if (c == '@') { /* Empty locator. We pop the last location off */ if (locs) { Scanner_set_location(s, locs->filename, locs->line_number); cparse_file = locs->filename; cparse_line = locs->line_number; l = locs->next; free(locs); locs = l; } 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); } /* Swig_diagnostic(cparse_file, cparse_line, "Scanner_set_location\n"); */ Scanner_set_location(s, cparse_file, cparse_line); Delete(fn); } } } void Swig_cparse_follow_locators(int v) { follow_locators = v; }