/******************************************************************************* * 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 #include #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; }