📄 fscanner.l
字号:
* are not fcn definitions! */ /* warning: "if (...)" must not overflow yytext, * so the content of function argument definitions * is restricted, in particular parentheses are * not allowed */ /* FIXME HBB 20001003: the above 'not allowed' may well be the * reason for the parsing bug concerning function pointer usage, * I suspect. --- I think my new special-case rule for 'if' * could be helpful in removing that limitation */ if ((braces == 0 && ppdefine == NO && my_yytext[0] != '#' && rules == NO) || (braces == 1 && classdef == YES)) { fcndef = YES; token = FCNDEF; goto fcn; /* NOTREACHED */ } goto fcncal; /* NOTREACHED */ }{ws}*\(([*&[\]=,.]|{identifier}|{wsnl})* { /* function call */ fcncal: if (fcndef == YES || ppdefine == YES || rules == YES) { token = FCNCALL; goto fcn; /* NOTREACHED */ } if (template == NO) { templateparens = parens; template = YES; } goto ident; /* NOTREACHED */ }("*"|{wsnl})+{identifier} { /* typedef name or modifier use */ goto ident; /* NOTREACHED */ }.|\n { /* general identifer usage */ char *s; if (global == YES && ppdefine == NO && my_yytext[0] != '#' && external == NO && initializer == NO && arraydimension == NO && structfield == NO && template == NO && fcndef == NO) { if (esudef == YES) { /* if enum/struct/union */ token = MEMBERDEF; } else { token = GLOBALDEF; } } else { ident: token = IDENT; } fcn: if (YYSTATE == WAS_IDENTIFIER) { /* Position back to the actual identifier: */ last = first; first = ident_start; yyless(0); /* HBB 20001008: if the anti-backup-pattern above matched, * and the matched context ended with a \n, then the scanner * believes it's at the start of a new line. But the yyless() * should feeds that \n back into the input, so that's * wrong. --> force 'beginning-of-line' status off. */ yy_set_bol(0); BEGIN(INITIAL); } else { my_yymore(); last = my_yyleng; } definition: /* if a long line */ if (yyleng > STMTMAX) { int c; /* skip to the end of the line */ warning("line too long"); while ((c = skipcomment_input()) > LEXEOF) { if (c == '\n') { unput(c); break; } } } /* truncate a long symbol */ if (yyleng > PATLEN) { warning("symbol too long"); my_yyleng = first + PATLEN; my_yytext[my_yyleng] = '\0'; } /* if found word was a keyword: */ if ((s = lookup(my_yytext + first)) != NULL) { first = my_yyleng; /* if the start of a typedef */ if (s == typedeftext) { typedefbraces = braces; oldtype = YES; } /* if an enum/struct/union */ /* (needed for "typedef struct tag name;" so tag isn't marked as the typedef name) */ else if (s == enumtext || s == structtext || s == uniontext) { /* do nothing */ } else if (s == externtext) { /* if an external definition */ externalbraces = braces; external = YES; } else if (templateparens == parens && template == YES) { /* keyword doesn't start a function * template */ templateparens = -1; template = NO; } else { /* identifier after typedef was a * keyword */ oldtype = NO; } } else { /* not a keyword --> found an identifier */ /* last = yyleng; */ /* if a class/enum/struct/union tag definition */ /* FIXME HBB 20001001: why reject "class"? */ if (tagdef && strnotequal(my_yytext + first, "class")) { token = tagdef; tagdef = '\0'; if (braces == 0) { esudef = YES; } } else if (braces == typedefbraces && oldtype == NO && arraydimension == NO) { /* if a typedef name */ token = TYPEDEF; } else { oldtype = NO; } /* my_yymore(); */ return(token); /* NOTREACHED */ } }}\[ { /* array dimension (don't worry or about subscripts) */ arraydimension = YES; goto more; /* NOTREACHED */ }\] { arraydimension = NO; goto more; /* NOTREACHED */ }\\\n { /* preprocessor statement is continued on next line */ /* save the '\\' to the output file, but not the '\n': */ yyleng = 1; my_yymore(); goto eol; /* NOTREACHED */ }\n { /* end of the line */ if (ppdefine == YES) { /* end of a #define */ ppdefine = NO; yyless(yyleng - 1); last = first; my_yymore(); return(DEFINEEND); } /* skip the first 8 columns of a breakpoint listing line */ /* and skip the file path in the page header */ if (bplisting == YES) { int c, i; /* FIXME HBB 20001007: should call input() instead */ switch (skipcomment_input()) { /* tab and EOF just fall through */ case ' ': /* breakpoint number line */ case '[': for (i = 1; i < 8 && skipcomment_input() > LEXEOF; ++i) ; break; case '.': /* header line */ case '/': /* skip to the end of the line */ while ((c = skipcomment_input()) > LEXEOF) { if (c == '\n') { unput(c); break; } } break; case '\n': /* empty line */ unput('\n'); break; } } eol: ++myylineno; first = 0; last = 0; if (symbols > 0) { /* no my_yymore(): \n doesn't need to be in my_yytext */ return(NEWLINE); } /* line ended --> flush my_yytext */ if (my_yytext) *my_yytext = '\0'; my_yyleng = 0; lineno = myylineno; }\' { /* character constant */ if (sdl == NO) BEGIN(IN_SQUOTE); goto more; /* NOTREACHED */ }<IN_SQUOTE>\' { BEGIN(INITIAL); goto more; /* NOTREACHED */ }\" { /* string constant */ BEGIN(IN_DQUOTE); goto more; /* NOTREACHED */ }<IN_DQUOTE>\" { BEGIN(INITIAL); goto more; /* NOTREACHED */ }<IN_DQUOTE,IN_SQUOTE>{\n { /* syntax error: unexpected EOL */ BEGIN(INITIAL); goto eol; /* NOTREACHED */ }\\. |. { goto more; /* NOTREACHED */ }\\\n { /* line continuation inside a string! */ myylineno++; goto more; /* NOTREACHED */ }} ^{ws}+ { /* don't save leading white space */ } {ws}+\n { /* eat whitespace at end of line */ unput('\n'); }[\t\r\v\f]+ { /* eat non-blank whitespace sequences, replace * by single blank */ unput(' '); }{ws}{2,} { /* compress sequential whitespace here, not in putcrossref() */ unput(' '); }"/*" yy_push_state(COMMENT);<COMMENT>{[^*\n]* |"*"+[^*/\n]* ; /* do nothing */[^*\n]*\n |"*"+[^*/\n]*\n { if (ppdefine == NO) { goto eol; } else { ++myylineno; } /* NOTREACHED */ }"*"+"/" { /* replace the comment by a single blank */ unput(' '); yy_pop_state(); }} "//".*\n? { /* C++-style one-line comment */ goto eol; /* NOTREACHED */ }{number} | /* number */<SDL>STATE[ \t]+ | /* ... and other syntax error catchers... */. { /* punctuation and operators */ more: my_yymore(); first = my_yyleng; }%%voidinitscanner(char *srcfile){ char *s; if (maxifbraces == NULL) { maxifbraces = mymalloc(miflevel * sizeof(int)); preifbraces = mymalloc(miflevel * sizeof(int)); } first = 0; /* buffer index for first char of symbol */ last = 0; /* buffer index for last char of symbol */ lineno = 1; /* symbol line number */ myylineno = 1; /* input line number */ arraydimension = NO; /* inside array dimension declaration */ bplisting = NO; /* breakpoint listing */ braces = 0; /* unmatched left brace count */ classdef = NO; /* c++ class definition */ elseelif = NO; /* #else or #elif found */ esudef = NO; /* enum/struct/union global definition */ external = NO; /* external definition */ externalbraces = -1; /* external definition outer brace count */ fcndef = NO; /* function definition */ global = YES; /* file global scope (outside functions) */ iflevel = 0; /* #if nesting level */ initializer = NO; /* data initializer */ initializerbraces = -1; /* data initializer outer brace count */ lex = NO; /* lex file */ parens = 0; /* unmatched left parenthesis count */ ppdefine = NO; /* preprocessor define statement */ pseudoelif = NO; /* pseudo-#elif */ oldtype = NO; /* next identifier is an old type */ rules = NO; /* lex/yacc rules */ sdl = NO; /* sdl file */ structfield = NO; /* structure field declaration */ tagdef = '\0'; /* class/enum/struct/union tag definition */ template = NO; /* function template */ templateparens = -1; /* function template outer parentheses count */ typedefbraces = -1; /* initial typedef braces count */ ident_start = 0; /* start of previously found identifier */ if (my_yytext) *my_yytext = '\0'; my_yyleng = 0; BEGIN(INITIAL); /* if this is not a C file */ if ((s = strrchr(srcfile, '.')) != NULL) { switch (*++s) { /* this switch saves time on C files */ case 'b': if (strcmp(s, "bp") == 0) { /* breakpoint listing */ bplisting = YES; } break; case 'l': if (strcmp(s, "l") == 0) { /* lex */ lex = YES; global = NO; } break; case 's': if (strcmp(s, "sd") == 0) { /* sdl */ sdl = YES; BEGIN(SDL); } break; case 'y': if (strcmp(s, "y") == 0) { /* yacc */ global = NO; } break; } }}#if !COMMENTS_BY_FLEX/* A micro-scanner that serves as the input() function of the * scanner. It throws away any comments in the input, correctly * avoiding doing this inside string/character constants, and knows * about backslash sequences. Now that the main scanner doesn't use * yymore() any longer, this could be replaced by lex rules. Left for * trying later. *//* Status variable: If this is non-NUL, it's the character that* terminates a string we're currently in. */static int string_terminator = '\0';/* Helper routine: treat 'c' as a character found inside a * string. Check if this character might be the end of that * string. Backslashes have to be taken care of, for the sake of * "quotes like \"these\" found inside a string". */static intinsidestring_input(int c){ static BOOL was_backslash = NO; if ((c == '\\') && (was_backslash == NO)) { /* escape character found --> treat next char specially */ /* FIXME HBB 20001003: need treatment of backslash in the main * scanner, too. It'll get false line counts in case of "\\'", * otherwise --- they can occur as part of a lex pattern */ was_backslash = YES; return c; } if (((c == '\t') && (lex == YES)) /* Note: "\\\n" is removed even inside strings! */ || ((c == '\n') && (was_backslash == NO)) || (c == EOF) || ((c == string_terminator) && (was_backslash == NO)) ) { /* Line ended, or end-of-string was found. That is a syntax * error. To recover, stop treatment as a string constant: */ string_terminator = '\0'; } else if (!isprint((unsigned char)c)) { /* mask unprintable characters */ c = ' '; } was_backslash = NO; return c;}/* Helper function: skip over input until end of comment is found (or * we find that it wasn't really comment, in the first place): */static intcomment(void){ int c, lastc; /* Coming here, we've just read in the opening '/' of a * comment. */ do { if ((c = getc(yyin)) == '*') { /* C comment */ lastc = '\0'; while ((c = getc(yyin)) != EOF /* fewer '/'s --> test them first! */ && (c != '/' || lastc != '*') ) { if (c == '\n') { /* keep the line number count */ /* FIXME HBB 20001008: this is not synchronized * properly with myylineno changes by the main * scanner. A strong point in favour of moving * this to lex-code that is, IMHO */ ++myylineno; } lastc = c; } /* return a blank for Reiser cpp token concatenation */ /* FIXME HBB 20001008: what on earth is 'Reiser cpp'? ANSI * C defines cpp to explicitly replace any comment by a * blank. Pre-ANSI cpp's behaved differently, but do we * really want that? If at all, it should only ever be a * non-default option (like gcc's "-traditional-cpp") * */ if ((c = getc(yyin)) == '_' || isalnum(c)) { (void) ungetc(c, yyin); c = ' '; break; } } else if (c == '/') { /* C++ comment */ while ((c = getc(yyin)) != EOF && c != '\n') { ; /* do nothing else */ } break; } else { /* not a comment */ (void) ungetc(c, yyin); c = '/'; break; /* NOTREACHED */ } /* there may be an immediately following comment */ } while (c == '/'); return(c);}/* The core of the actual input() function to be used by (f)lex. The * calling scheme between this and the actual input() redefinition is * a bit different for lex and flex. See the #ifdef FLEX_SCANNER part * in the head section. */static intskipcomment_input(void){ int c; c = getc (yyin); if (string_terminator != '\0') { /* don't look for comments inside strings! */ return insidestring_input(c); } else if (c == '/') { /* swallow everything until end of comment, if this is one */ return comment (); } else if (c == '"' || c == '\'') { /* a string is beginning here, so switch input method */ string_terminator = c; } return c;}#endif /* !COMMENTS_BY_FLEX */#define MY_YY_ALLOCSTEP 1000static voidmy_yymore(void){ static size_t yytext_size = 0; /* my_yytext is an ever-growing buffer. It will not ever * shrink, nor will it be freed at end of program, for now */ while (my_yyleng + yyleng + 1 >= yytext_size) { my_yytext = myrealloc(my_yytext, yytext_size += MY_YY_ALLOCSTEP); } strncpy (my_yytext + my_yyleng, yytext, yyleng+1); my_yyleng += yyleng;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -