root/gtags-parser/C.c(9.html)

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. yacc
  2. C
  3. C_family
  4. process_attribute
  5. function_definition
  6. condition_macro
  7. seems_datatype

/*
 * Copyright (c) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008
 *      Tama Communications Corporation
 *
 * This file is part of GNU GLOBAL.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#ifdef HAVE_CONFIG_H #include <config.h> #endif #include <ctype.h> #ifdef HAVE_LIMITS_H #include <limits.h> #endif #include <stdio.h> #ifdef STDC_HEADERS #include <stdlib.h> #endif #ifdef HAVE_STRING_H #include <string.h> #else #include <strings.h> #endif #include "gctags.h" #include "defined.h" #include "die.h" #include "strbuf.h" #include "strlimcpy.h" #include "token.h" #include "c_res.h" static void C_family(const char *, int); static void process_attribute(int); static int function_definition(int, char *); static void condition_macro(int, int); static int seems_datatype(const char *); #define IS_TYPE_QUALIFIER(c) ((c) == C_CONST || (c) == C_RESTRICT || (c) == C_VOLATILE) #define DECLARATIONS 0 #define RULES 1 #define PROGRAMS 2 #define TYPE_C 0 #define TYPE_LEX 1 #define TYPE_YACC 2 /* * #ifdef stack. */
#define MAXPIFSTACK 100 static struct { short start; /* level when #if block started */
short end; /* level when #if block end */
short if0only; /* #if 0 or notdef only */
} stack[MAXPIFSTACK], *cur; static int piflevel; /* condition macro level */
static int level; /* brace level */
/* * yacc: read yacc file and pickup tag entries. */
void yacc(const char *file) { C_family(file, TYPE_YACC); } /* * C: read C file and pickup tag entries. */
void C(const char *file) { C_family(file, TYPE_C); } /* * i) file source file * i) type TYPE_C, TYPE_YACC, TYPE_LEX */
static void C_family(const char *file, int type) { int c, cc; int savelevel; int target; int startmacro, startsharp; const char *interested = "{}=;"; STRBUF *sb = strbuf_open(0); /* * yacc file format is like the following. * * declarations * %% * rules * %% * programs * */
int yaccstatus = (type == TYPE_YACC) ? DECLARATIONS : PROGRAMS; int inC = (type == TYPE_YACC) ? 0 : 1; /* 1 while C source */
level = piflevel = 0; savelevel = -1; target = (sflag) ? SYM : (rflag) ? REF : DEF; startmacro = startsharp = 0; if (!opentoken(file)) die("'%s' cannot open.", file); cmode = 1; /* allow token like '#xxx' */
crflag = 1; /* require '\n' as a token */
if (type == TYPE_YACC) ymode = 1; /* allow token like '%xxx' */
while ((cc = nexttoken(interested, c_reserved_word)) != EOF) { switch (cc) { case SYMBOL: /* symbol */
if (inC && peekc(0) == '('/* ) */
) { if (isnotfunction(token)) { if (target == REF && defined(token)) PUT(token, lineno, sp); } else if (level > 0 || startmacro) { if (target == REF) { if (defined(token)) PUT(token, lineno, sp); } else if (target == SYM) { if (!defined(token)) PUT(token, lineno, sp); } } else if (level == 0 && !startmacro && !startsharp) { char arg1[MAXTOKEN], savetok[MAXTOKEN], *saveline; int savelineno = lineno; strlimcpy(savetok, token, sizeof(savetok)); strbuf_reset(sb); strbuf_puts(sb, sp); saveline = strbuf_value(sb); arg1[0] = '\0'; /* * Guile function entry using guile-snarf is like follows: * * SCM_DEFINE (scm_list, "list", 0, 0, 1, * (SCM objs), * "Return a list containing OBJS, the arguments to `list'.") * #define FUNC_NAME s_scm_list * { * return objs; * } * #undef FUNC_NAME * * We should assume the first argument as a function name instead of 'SCM_DEFINE'. */
if (function_definition(target, arg1)) { if (!strcmp(savetok, "SCM_DEFINE") && *arg1) strlimcpy(savetok, arg1, sizeof(savetok)); if (target == DEF) PUT(savetok, savelineno, saveline); } else { if (target == REF && defined(savetok)) PUT(savetok, savelineno, saveline); } } } else { if (target == REF) { if (defined(token)) PUT(token, lineno, sp); } else if (target == SYM) { if (!defined(token)) PUT(token, lineno, sp); } } break; case '{': /* } */
DBG_PRINT(level, "{"); /* } */
if (yaccstatus == RULES && level == 0) inC = 1; ++level; if (bflag && atfirst) { if (wflag && level != 1) warning("forced level 1 block start by '{' at column 0 [+%d %s].", lineno, curfile); /* } */
level = 1; } break; /* { */
case '}': if (--level < 0) { if (wflag) warning("missing left '{' [+%d %s].", lineno, curfile); /* } */
level = 0; } if (eflag && atfirst) { if (wflag && level != 0) /* { */
warning("forced level 0 block end by '}' at column 0 [+%d %s].", lineno, curfile); level = 0; } if (yaccstatus == RULES && level == 0) inC = 0; /* { */
DBG_PRINT(level, "}"); break; case '\n': if (startmacro && level != savelevel) { if (wflag) warning("different level before and after #define macro. reseted. [+%d %s].", lineno, curfile); level = savelevel; } startmacro = startsharp = 0; break; case YACC_SEP: /* %% */
if (level != 0) { if (wflag) warning("forced level 0 block end by '%%' [+%d %s].", lineno, curfile); level = 0; } if (yaccstatus == DECLARATIONS) { if (target == DEF) PUT("yyparse", lineno, sp); yaccstatus = RULES; } else if (yaccstatus == RULES) yaccstatus = PROGRAMS; inC = (yaccstatus == PROGRAMS) ? 1 : 0; break; case YACC_BEGIN: /* %{ */
if (level != 0) { if (wflag) warning("forced level 0 block end by '%%{' [+%d %s].", lineno, curfile); level = 0; } if (inC == 1 && wflag) warning("'%%{' appeared in C mode. [+%d %s].", lineno, curfile); inC = 1; break; case YACC_END: /* %} */
if (level != 0) { if (wflag) warning("forced level 0 block end by '%%}' [+%d %s].", lineno, curfile); level = 0; } if (inC == 0 && wflag) warning("'%%}' appeared in Yacc mode. [+%d %s].", lineno, curfile); inC = 0; break; case YACC_UNION: /* %union {...} */
if (yaccstatus == DECLARATIONS && target == DEF) PUT("YYSTYPE", lineno, sp); break; /* * #xxx */
case SHARP_DEFINE: case SHARP_UNDEF: startmacro = 1; savelevel = level; if ((c = nexttoken(interested, c_reserved_word)) != SYMBOL) { pushbacktoken(); break; } if (peekc(1) == '('/* ) */
) { if (target == DEF) PUT(token, lineno, sp); while ((c = nexttoken("()", c_reserved_word)) != EOF && c != '\n' && c != /* ( */
')') if (c == SYMBOL && target == SYM) PUT(token, lineno, sp); if (c == '\n') pushbacktoken(); } else { if (target == DEF) PUT(token, lineno, sp); } break; case SHARP_IMPORT: case SHARP_INCLUDE: case SHARP_INCLUDE_NEXT: case SHARP_ERROR: case SHARP_LINE: case SHARP_PRAGMA: case SHARP_WARNING: case SHARP_IDENT: case SHARP_SCCS: while ((c = nexttoken(interested, c_reserved_word)) != EOF && c != '\n') ; break; case SHARP_IFDEF: case SHARP_IFNDEF: case SHARP_IF: case SHARP_ELIF: case SHARP_ELSE: case SHARP_ENDIF: condition_macro(cc, target); break; case SHARP_SHARP: /* ## */
(void)nexttoken(interested, c_reserved_word); break; case C_STRUCT: case C_ENUM: case C_UNION: c = nexttoken(interested, c_reserved_word); if (c == SYMBOL) { if (peekc(0) == '{') /* } */
{ if (target == DEF) PUT(token, lineno, sp); } else if (target == REF) { if (defined(token)) PUT(token, lineno, sp); } else if (target == SYM) { if (!defined(token)) PUT(token, lineno, sp); } c = nexttoken(interested, c_reserved_word); } if (c == '{' /* } */
&& cc == C_ENUM) { int savelevel = level; for (; c != EOF; c = nexttoken(interested, c_reserved_word)) { switch (c) { case SHARP_IFDEF: case SHARP_IFNDEF: case SHARP_IF: case SHARP_ELIF: case SHARP_ELSE: case SHARP_ENDIF: condition_macro(c, target); continue; default: break; } if (c == '{') level++; else if (c == '}') { if (--level == savelevel) break; } else if (c == SYMBOL) { if (target == DEF) PUT(token, lineno, sp); } } } else { pushbacktoken(); } break; /* control statement check */
case C_BREAK: case C_CASE: case C_CONTINUE: case C_DEFAULT: case C_DO: case C_ELSE: case C_FOR: case C_GOTO: case C_IF: case C_RETURN: case C_SWITCH: case C_WHILE: if (wflag && !startmacro && level == 0) warning("Out of function. %8s [+%d %s]", token, lineno, curfile); break; case C_TYPEDEF: { /* * This parser is too complex to maintain. * We should rewrite the whole. */
char savetok[MAXTOKEN]; int savelineno = 0; int typedef_savelevel = level; savetok[0] = 0; /* skip type qualifiers */
do { c = nexttoken("{}(),;", c_reserved_word); } while (IS_TYPE_QUALIFIER(c) || c == '\n'); if (wflag && c == EOF) { warning("unexpected eof. [+%d %s]", lineno, curfile); break; } else if (c == C_ENUM || c == C_STRUCT || c == C_UNION) { char *interest_enum = "{},;"; int c_ = c; c = nexttoken(interest_enum, c_reserved_word); /* read enum name if exist */
if (c == SYMBOL) { if (peekc(0) == '{') /* } */
{ if (target == DEF) PUT(token, lineno, sp); } else if (target == REF) { if (defined(token)) PUT(token, lineno, sp); } else if (target == SYM) { if (!defined(token)) PUT(token, lineno, sp); } c = nexttoken(interest_enum, c_reserved_word); } for (; c != EOF; c = nexttoken(interest_enum, c_reserved_word)) { switch (c) { case SHARP_IFDEF: case SHARP_IFNDEF: case SHARP_IF: case SHARP_ELIF: case SHARP_ELSE: case SHARP_ENDIF: condition_macro(c, target); continue; default: break; } if (c == ';' && level == typedef_savelevel) { if (savetok[0] && target == DEF) PUT(savetok, savelineno, sp); break; } else if (c == '{') level++; else if (c == '}') { if (--level == typedef_savelevel) break; } else if (c == SYMBOL) { if (c_ == C_ENUM) { if (target == DEF && level > typedef_savelevel) PUT(token, lineno, sp); if (target == SYM && level == typedef_savelevel && !defined(token)) PUT(token, lineno, sp); } else { if (target == REF) { if (level > typedef_savelevel && defined(token)) PUT(token, lineno, sp); } else if (target == SYM) { if (!defined(token)) PUT(token, lineno, sp); } else if (target == DEF) { /* save lastest token */
strlimcpy(savetok, token, sizeof(savetok)); savelineno = lineno; } } } } if (c == ';') break; if (wflag && c == EOF) { warning("unexpected eof. [+%d %s]", lineno, curfile); break; } } else if (c == SYMBOL) { if (target == REF && defined(token)) PUT(token, lineno, sp); if (target == SYM && !defined(token)) PUT(token, lineno, sp); } savetok[0] = 0; while ((c = nexttoken("(),;", c_reserved_word)) != EOF) { switch (c) { case SHARP_IFDEF: case SHARP_IFNDEF: case SHARP_IF: case SHARP_ELIF: case SHARP_ELSE: case SHARP_ENDIF: condition_macro(c, target); continue; default: break; } if (c == '(') level++; else if (c == ')') level--; else if (c == SYMBOL) { if (level > typedef_savelevel) { if (target == SYM) PUT(token, lineno, sp); } else { /* put latest token if any */
if (savetok[0]) { if (target == SYM) PUT(savetok, savelineno, sp); } /* save lastest token */
strlimcpy(savetok, token, sizeof(savetok)); savelineno = lineno; } } else if (c == ',' || c == ';') { if (savetok[0]) { if (target == DEF) PUT(savetok, lineno, sp); savetok[0] = 0; } } if (level == typedef_savelevel && c == ';') break; } if (wflag) { if (c == EOF) warning("unexpected eof. [+%d %s]", lineno, curfile); else if (level != typedef_savelevel) warning("() block unmatched. (last at level %d.)[+%d %s]", level, lineno, curfile); } } break; case C___ATTRIBUTE__: process_attribute(target); break; default: break; } } strbuf_close(sb); if (wflag) { if (level != 0) warning("{} block unmatched. (last at level %d.)[+%d %s]", level, lineno, curfile); if (piflevel != 0) warning("#if block unmatched. (last at level %d.)[+%d %s]", piflevel, lineno, curfile); } closetoken(); } /* * process_attribute: skip attributes in __attribute__((...)). * * r) target type */
static void process_attribute(int target) { int brace = 0; int c; /* * Skip '...' in __attribute__((...)) * but pick up symbols in it. */
while ((c = nexttoken("()", c_reserved_word)) != EOF) { if (c == '(') brace++; else if (c == ')') brace--; else if (c == SYMBOL) { if (target == REF) { if (defined(token)) PUT(token, lineno, sp); } else if (target == SYM) { if (!defined(token)) PUT(token, lineno, sp); } } if (brace == 0) break; } } /* * function_definition: return if function definition or not. * * i) target DEF, REF, SYMBOL * o) arg1 the first argument * r) target type */
static int function_definition(int target, char arg1[MAXTOKEN]) { int c; int brace_level, isdefine; int accept_arg1 = 0; brace_level = isdefine = 0; while ((c = nexttoken("()", c_reserved_word)) != EOF) { switch (c) { case SHARP_IFDEF: case SHARP_IFNDEF: case SHARP_IF: case SHARP_ELIF: case SHARP_ELSE: case SHARP_ENDIF: condition_macro(c, target); continue; default: break; } if (c == '('/* ) */
) brace_level++; else if (c == /* ( */
')') { if (--brace_level == 0) break; } /* pick up symbol */
if (c == SYMBOL) { if (accept_arg1 == 0) { accept_arg1 = 1; strlimcpy(arg1, token, MAXTOKEN); } if (target == REF) { if (seems_datatype(token) && defined(token)) PUT(token, lineno, sp); } else if (target == SYM) { if (!seems_datatype(token) || !defined(token)) PUT(token, lineno, sp); } } } if (c == EOF) return 0; brace_level = 0; while ((c = nexttoken(",;[](){}=", c_reserved_word)) != EOF) { switch (c) { case SHARP_IFDEF: case SHARP_IFNDEF: case SHARP_IF: case SHARP_ELIF: case SHARP_ELSE: case SHARP_ENDIF: condition_macro(c, target); continue; case C___ATTRIBUTE__: process_attribute(target); continue; default: break; } if (c == '('/* ) */
|| c == '[') brace_level++; else if (c == /* ( */
')' || c == ']') brace_level--; else if (brace_level == 0 && ((c == SYMBOL && strcmp(token, "__THROW")) || IS_RESERVED_WORD(c))) isdefine = 1; else if (c == ';' || c == ',') { if (!isdefine) break; } else if (c == '{' /* } */
) { pushbacktoken(); return 1; } else if (c == /* { */
'}') break; else if (c == '=') break; /* pick up symbol */
if (c == SYMBOL) { if (target == REF) { if (seems_datatype(token) && defined(token)) PUT(token, lineno, sp); } else if (target == SYM) { if (!seems_datatype(token) || !defined(token)) PUT(token, lineno, sp); } } } return 0; } /* * condition_macro: * * i) cc token * i) target current target */
static void condition_macro(int cc, int target) { cur = &stack[piflevel]; if (cc == SHARP_IFDEF || cc == SHARP_IFNDEF || cc == SHARP_IF) { DBG_PRINT(piflevel, "#if"); if (++piflevel >= MAXPIFSTACK) die("#if stack over flow. [%s]", curfile); ++cur; cur->start = level; cur->end = -1; cur->if0only = 0; if (peekc(0) == '0') cur->if0only = 1; else if ((cc = nexttoken(NULL, c_reserved_word)) == SYMBOL && !strcmp(token, "notdef")) cur->if0only = 1; else pushbacktoken(); } else if (cc == SHARP_ELIF || cc == SHARP_ELSE) { DBG_PRINT(piflevel - 1, "#else"); if (cur->end == -1) cur->end = level; else if (cur->end != level && wflag) warning("uneven level. [+%d %s]", lineno, curfile); level = cur->start; cur->if0only = 0; } else if (cc == SHARP_ENDIF) { int minus = 0; --piflevel; if (piflevel < 0) { minus = 1; piflevel = 0; } DBG_PRINT(piflevel, "#endif"); if (minus) { if (wflag) warning("#if block unmatched. reseted. [+%d %s]", lineno, curfile); } else { if (cur->if0only) level = cur->start; else if (cur->end != -1) { if (cur->end != level && wflag) warning("uneven level. [+%d %s]", lineno, curfile); level = cur->end; } } } while ((cc = nexttoken(NULL, c_reserved_word)) != EOF && cc != '\n') { if (cc == SYMBOL && strcmp(token, "defined") != 0) { if (target == REF) { if (defined(token)) PUT(token, lineno, sp); } else if (target == SYM) { if (!defined(token)) PUT(token, lineno, sp); } } } } /* * seems_datatype: decide whether or not it is a data type. * * i) token token * r) 0: not data type, 1: data type */
static int seems_datatype(const char *token) { int length = strlen(token); const char *p = token + length; if (length > 2 && strcmp(p - 2, "_t") == 0) return 1; for (p = token; *p; p++) if (islower(*p)) return 0; return 1; }

/* [<][>][^][v][top][bottom][index][help] */