2 /*===========================================================================
3 Copyright (c) 1998-2000, The Santa Cruz Operation
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
9 *Redistributions of source code must retain the above copyright notice,
10 this list of conditions and the following disclaimer.
12 *Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
16 *Neither name of The Santa Cruz Operation nor the names of its contributors
17 may be used to endorse or promote products derived from this software
18 without specific prior written permission.
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
21 IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
24 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
32 =========================================================================*/
34 /* cscope - interactive C symbol cross-reference
42 /* the line counting has been moved from character reading for speed */
43 /* comments are discarded */
45 #define IFLEVELINC 5 /* #if nesting level size increment */
47 static char const rcsid[] = "$Id: scanner.l,v 1.10 2011/06/29 15:48:00 nhorman Exp $";
49 int first; /* buffer index for first char of symbol */
50 int last; /* buffer index for last char of symbol */
51 int lineno; /* symbol line number */
54 static BOOL arraydimension; /* inside array dimension declaration */
55 static BOOL bplisting; /* breakpoint listing */
56 static int braces; /* unmatched left brace count */
57 static BOOL classdef; /* c++ class definition */
58 static BOOL elseelif; /* #else or #elif found */
59 static BOOL esudef; /* enum/struct/union global definition */
60 static BOOL external; /* external definition */
61 static int externalbraces; /* external definition outer brace count */
62 static BOOL fcndef; /* function definition */
63 static BOOL global; /* file global scope (outside functions) */
64 static int iflevel; /* #if nesting level */
65 static BOOL initializer; /* data initializer */
66 static int initializerbraces; /* data initializer outer brace count */
67 static BOOL lex; /* lex file */
68 static int miflevel = IFLEVELINC; /* maximum #if nesting level */
69 static int *maxifbraces; /* maximum brace count within #if */
70 static int *preifbraces; /* brace count before #if */
71 static int parens; /* unmatched left parenthesis count */
72 static BOOL ppdefine; /* preprocessor define statement */
73 static BOOL pseudoelif; /* pseudo-#elif */
74 static BOOL oldtype; /* next identifier is an old type */
75 static BOOL rules; /* lex/yacc rules */
76 static BOOL sdl; /* sdl file */
77 static BOOL structfield; /* structure field declaration */
78 static int tagdef; /* class/enum/struct/union tag definition */
79 static BOOL template; /* function template */
80 static int templateparens; /* function template outer parentheses count */
81 static int typedefbraces = -1; /* initial typedef brace count */
82 static int token; /* token found */
85 void multicharconstant(char terminator);
86 int skipcomment_input(void);
90 #define YY_INPUT(buf,result,max_size) \
92 int c = skipcomment_input (); \
93 result = (c == EOF) ? YY_NULL : (buf[0] = c, 1); \
96 /* Assume this is the AT&T/SCO style lex */
98 #define input() ((yytchar=(yytchar=yysptr>yysbuf?*(unsigned char *)--yysptr:getc(yyin))=='/'?comment():yytchar)==EOF?LEXEOF:yytchar)
99 #define noncommentinput() ((yytchar=yysptr>yysbuf?*--yysptr:getc(yyin))==EOF?LEXEOF:yytchar)
101 #define unput(c) (*yysptr++=(c))
109 identifier [a-zA-Z_$][a-zA-Z_0-9$]*
110 number \.?[0-9][.0-9a-fA-FlLuUxX]*
116 %\{ { /* lex/yacc C declarations/definitions */
126 ^%% { /* lex/yacc rules delimiter */
131 /* simulate a yylex() or yyparse() definition */
132 (void) strcat(yytext, " /* ");
133 first = strlen(yytext);
135 (void) strcat(yytext, "yylex");
137 else { /* yacc: yyparse implicitly calls yylex */
138 char *s = " yylex()";
139 char *cp = s + strlen(s);
143 (void) strcat(yytext, "yyparse");
145 last = strlen(yytext);
146 (void) strcat(yytext, " */");
147 yyleng = strlen(yytext);
160 <SDL>STATE{ws}+({identifier}|\*) { /* sdl state, treat as function def */
167 <SDL>ENDSTATE{ws} { /* end of an sdl state, treat as end of a function */
171 \{ { /* count unmatched left braces for fcn def detection */
174 /* mark an untagged enum/struct/union so its beginning
189 \#{ws}*endif/.*\n{wsnl}*#{ws}*if {
190 /* attempt to correct erroneous brace count caused by:
199 /* the current #if must not have an #else or #elif */
200 if (elseelif == YES) {
208 \#{ws}*ifn?(def)? { /* #if, #ifdef or #ifndef */
210 if (pseudoelif == YES) {
215 /* make sure there is room for the current brace count */
216 if (iflevel == miflevel) {
217 miflevel += IFLEVELINC;
218 maxifbraces = myrealloc(maxifbraces, miflevel * sizeof(int));
219 preifbraces = myrealloc(preifbraces, miflevel * sizeof(int));
221 /* push the current brace count */
222 preifbraces[iflevel] = braces;
223 maxifbraces[iflevel++] = 0;
227 \#{ws}*el(se|if) { /* #elif or #else */
232 /* save the maximum brace count for this #if */
233 if (braces > maxifbraces[iflevel - 1]) {
234 maxifbraces[iflevel - 1] = braces;
236 /* restore the brace count to before the #if */
237 braces = preifbraces[iflevel - 1];
242 \#{ws}*endif { /* #endif */
246 /* get the maximum brace count for this #if */
247 if (braces < maxifbraces[--iflevel]) {
248 braces = maxifbraces[iflevel];
255 /* could be the last enum member initializer */
256 if (braces == initializerbraces) {
257 initializerbraces = -1;
265 if (braces == 0 || (braces == 1 && classdef == YES)) {
267 /* if the end of an enum/struct/union definition */
271 /* if the end of the function */
272 else if (fcndef == YES) {
282 \( { /* count unmatched left parentheses for function templates */
291 /* if the end of a function template */
292 if (parens == templateparens) {
299 = { /* if a global definition initializer */
300 if (global == YES && ppdefine == NO && yytext[0] != '#') {
301 initializerbraces = braces;
307 : { /* a if global structure field */
308 if (global == YES && ppdefine == NO && yytext[0] != '#') {
315 if (braces == initializerbraces) {
316 initializerbraces = -1;
323 ; { /* if the enum/struct/union was not a definition */
327 /* if the end of a typedef */
328 if (braces == typedefbraces) {
331 /* if the end of a external definition */
332 if (braces == externalbraces) {
341 \#{ws}*define{ws}+{identifier} {
343 /* preprocessor macro or constant definition */
346 if (compress == YES) {
347 yytext[0] = '\1'; /* compress the keyword */
351 while (yytext[first] != ' ' && yytext[first] != '\t') {
358 class{ws}+{identifier}({wsnl}|[a-zA-Z0-9_():])*\{ { /* class definition */
364 (enum|struct|union)/({wsnl}+{identifier}){wsnl}*\{ { /* enum/struct/union definition */
365 tagdef = *(yytext + first);
369 (enum|struct|union)/{wsnl}*\{ { /* tag-less e/s/u definition */
370 tagdef = yytext[first];
378 {identifier}/{ws}*\(({wsnl}|a-zA-Z0-9_*&[\]=,.:])*\)({wsnl}|[()])*[:a-zA-Z_#{] {
380 /* warning: "if (...)" must not overflow yytext, so the content
381 of function argument definitions is restricted, in particular
382 parentheses are not allowed */
384 /* if a function definition */
385 /* note: "#define a (b) {" and "#if defined(a)\n#" are not */
386 if ((braces == 0 && ppdefine == NO && yytext[0] != '#' && rules == NO) ||
387 (braces == 1 && classdef == YES)) {
396 {identifier}/{ws}*\( { /* if a function call */
397 fcncal: if (fcndef == YES || ppdefine == YES || rules == YES) {
402 if (template == NO) {
403 templateparens = parens;
409 {identifier}/([*]|{wsnl})+[a-zA-Z0-9_] { /* typedef name use */
416 if (global == YES && ppdefine == NO && yytext[0] != '#' &&
417 external == NO && initializer == NO &&
418 arraydimension == NO && structfield == NO &&
419 template == NO && fcndef == NO) {
420 if (esudef == YES) { /* if enum/struct/union */
428 ident: token = IDENT;
432 if (yyleng > STMTMAX) {
435 /* skip to the end of the line */
436 warning("line too long");
437 while ((c = skipcomment_input()) != LEXEOF) {
444 /* truncate a long symbol */
445 if (yyleng - first > PATLEN) {
446 warning("symbol too long");
447 yyleng = first + PATLEN;
448 yytext[yyleng] = '\0';
452 if ((s = lookup(yytext + first)) != NULL) {
455 /* if the start of a typedef */
456 if (s == typedeftext) {
457 typedefbraces = braces;
460 /* if an enum/struct/union */
461 /* (needed for "typedef struct tag name;" so
462 tag isn't marked as the typedef name) */
463 else if (s == enumtext || s == structtext || s == uniontext) {
465 /* if an external definition */
466 else if (s == externtext) {
467 externalbraces = braces;
470 /* keyword doesn't start a function template */
471 else if (templateparens == parens && template == YES) {
475 else { /* next identifier after typedef was a keyword */
479 else { /* identifier */
482 /* if a class/enum/struct/union tag definition */
483 if (tagdef && strnotequal(yytext + first, "class")) {
490 /* if a typedef name */
491 else if (braces == typedefbraces && oldtype == NO &&
492 arraydimension == NO) {
502 \[ { /* array dimension (don't worry or about subscripts) */
503 arraydimension = YES;
512 \\\n { /* preprocessor statement is continued on next line */
516 \n { /* end of the line */
517 if (ppdefine == YES) { /* end of a #define */
519 yyless(yyleng - 1); /* rescan \n */
524 /* skip the first 8 columns of a breakpoint listing line */
525 /* and skip the file path in the page header */
526 if (bplisting == YES) {
529 switch (skipcomment_input()) { /* tab and EOF just fall through */
530 case ' ': /* breakpoint number line */
532 for (i = 1; i < 8 && skipcomment_input() != LEXEOF; ++i)
535 case '.': /* header line */
537 /* skip to the end of the line */
538 while ((c = skipcomment_input()) != LEXEOF) {
545 case '\n': /* empty line */
559 \' { /* character constant */
561 multicharconstant('\'');
566 \" { /* string constant */
567 multicharconstant('"');
571 ^{ws}+ { /* don't save leading white space */
573 \#{ws}*include{ws}*["<][^"> \t\n]+ { /* #include file */
576 s = strpbrk(yytext, "\"<");
580 /* HBB: avoid pointer mismatch if yytext is
581 * unsigned, or a pointer */
582 first = s - (char *)&(yytext[0]);
584 if (compress == YES) {
585 yytext[0] = '\2'; /* compress the keyword */
591 \#{ws}*{identifier} | /* preprocessor keyword */
592 {number} | /* number */
593 . { /* punctuation and operators */
594 more: first = yyleng;
600 initscanner(char *srcfile)
604 if (maxifbraces == NULL) {
605 maxifbraces = mymalloc(miflevel * sizeof(int));
606 preifbraces = mymalloc(miflevel * sizeof(int));
608 first = 0; /* buffer index for first char of symbol */
609 last = 0; /* buffer index for last char of symbol */
610 lineno = 1; /* symbol line number */
611 myylineno = 1; /* input line number */
612 arraydimension = NO; /* inside array dimension declaration */
613 bplisting = NO; /* breakpoint listing */
614 braces = 0; /* unmatched left brace count */
615 classdef = NO; /* c++ class definition */
616 elseelif = NO; /* #else or #elif found */
617 esudef = NO; /* enum/struct/union global definition */
618 external = NO; /* external definition */
619 externalbraces = -1; /* external definition outer brace count */
620 fcndef = NO; /* function definition */
621 global = YES; /* file global scope (outside functions) */
622 iflevel = 0; /* #if nesting level */
623 initializer = NO; /* data initializer */
624 initializerbraces = -1; /* data initializer outer brace count */
625 lex = NO; /* lex file */
626 parens = 0; /* unmatched left parenthesis count */
627 ppdefine = NO; /* preprocessor define statement */
628 pseudoelif = NO; /* pseudo-#elif */
629 oldtype = NO; /* next identifier is an old type */
630 rules = NO; /* lex/yacc rules */
631 sdl = NO; /* sdl file */
632 structfield = NO; /* structure field declaration */
633 tagdef = '\0'; /* class/enum/struct/union tag definition */
634 template = NO; /* function template */
635 templateparens = -1; /* function template outer parentheses count */
636 typedefbraces = -1; /* initial typedef braces count */
640 /* if this is not a C file */
641 if ((s = strrchr(srcfile, '.')) != NULL) {
642 switch (*++s) { /* this switch saves time on C files */
644 if (strcmp(s, "bp") == 0) { /* breakpoint listing */
649 if (strcmp(s, "l") == 0) { /* lex */
655 if (strcmp(s, "sd") == 0) { /* sdl */
661 if (strcmp(s, "y") == 0) { /* yacc */
670 skipcomment_input(void)
674 if ((c = getc (yyin)) == '/') {
690 return (c == EOF) ? LEXEOF : c;
699 if ((c = getc(yyin)) == '*') { /* C comment */
701 while ((c = getc(yyin)) != EOF &&
702 (c != '/' || lastc != '*')) { /* fewer '/'s */
708 /* return a blank for Reiser cpp token concatenation */
709 if ((c = getc(yyin)) == '_' || isalnum(c)) {
710 (void) ungetc(c, yyin);
715 else if (c == '/') { /* C++ comment */
716 while ((c = getc(yyin)) != EOF && c != '\n') {
721 else { /* not a comment */
722 (void) ungetc(c, yyin);
728 /* there may be an immediately following comment */
734 multicharconstant(char terminator)
738 /* scan until the terminator is found */
739 while ((c = yytext[yyleng++] = comment_input()) != terminator) {
741 case '\\': /* escape character */
742 if ((yytext[yyleng++] = comment_input()) == '\n') {
746 case '\t': /* tab character */
748 /* if not a lex program, continue */
754 case '\n': /* illegal character */
756 /* assume the terminator is missing, so put
757 this character back */
759 yytext[--yyleng] = '\0';
762 case LEXEOF: /* end of file */
766 /* change a control character to a blank */
767 if (!isprint((unsigned char)c)) {
768 yytext[yyleng - 1] = ' ';
771 /* if this token will overflow the line buffer */
772 /* note: '\\' may cause yyleng to be > STMTMAX */
773 if (yyleng >= STMTMAX) {
775 /* truncate the token */
776 while ((c = comment_input()) != LEXEOF) {
777 if (c == terminator) {
781 else if (c == '\n') {
787 yytext[yyleng] = '\0';