📄 fortran.c
字号:
/** $Id: fortran.c,v 1.41 2004/03/15 04:17:36 darren Exp $** Copyright (c) 1998-2003, Darren Hiebert** This source code is released for free distribution under the terms of the* GNU General Public License.** This module contains functions for generating tags for Fortran language* files.*//** INCLUDE FILES*/#include "general.h" /* must always come first */#include <string.h>#include <limits.h>#include <ctype.h> /* to define tolower () */#include <setjmp.h>#include "debug.h"#include "entry.h"#include "keyword.h"#include "options.h"#include "parse.h"#include "read.h"#include "routines.h"#include "vstring.h"/** MACROS*/#define isident(c) (isalnum(c) || (c) == '_')#define isBlank(c) (boolean) (c == ' ' || c == '\t')#define isType(token,t) (boolean) ((token)->type == (t))#define isKeyword(token,k) (boolean) ((token)->keyword == (k))#define isSecondaryKeyword(token,k) (boolean) ((token)->secondary == NULL ? \ FALSE : (token)->secondary->keyword == (k))/** DATA DECLARATIONS*/typedef enum eException { ExceptionNone, ExceptionEOF, ExceptionFixedFormat, ExceptionLoop} exception_t;/* Used to designate type of line read in fixed source form. */typedef enum eFortranLineType { LTYPE_UNDETERMINED, LTYPE_INVALID, LTYPE_COMMENT, LTYPE_CONTINUATION, LTYPE_EOF, LTYPE_INITIAL, LTYPE_SHORT} lineType;/* Used to specify type of keyword. */typedef enum eKeywordId { KEYWORD_NONE = -1, KEYWORD_allocatable, KEYWORD_assignment, KEYWORD_automatic, KEYWORD_block, KEYWORD_byte, KEYWORD_cexternal, KEYWORD_cglobal, KEYWORD_character, KEYWORD_common, KEYWORD_complex, KEYWORD_contains, KEYWORD_data, KEYWORD_dimension, KEYWORD_dllexport, KEYWORD_dllimport, KEYWORD_do, KEYWORD_double, KEYWORD_elemental, KEYWORD_end, KEYWORD_entry, KEYWORD_equivalence, KEYWORD_external, KEYWORD_format, KEYWORD_function, KEYWORD_if, KEYWORD_implicit, KEYWORD_include, KEYWORD_inline, KEYWORD_integer, KEYWORD_intent, KEYWORD_interface, KEYWORD_intrinsic, KEYWORD_logical, KEYWORD_map, KEYWORD_module, KEYWORD_namelist, KEYWORD_operator, KEYWORD_optional, KEYWORD_parameter, KEYWORD_pascal, KEYWORD_pexternal, KEYWORD_pglobal, KEYWORD_pointer, KEYWORD_precision, KEYWORD_private, KEYWORD_program, KEYWORD_public, KEYWORD_pure, KEYWORD_real, KEYWORD_record, KEYWORD_recursive, KEYWORD_save, KEYWORD_select, KEYWORD_sequence, KEYWORD_static, KEYWORD_stdcall, KEYWORD_structure, KEYWORD_subroutine, KEYWORD_target, KEYWORD_then, KEYWORD_type, KEYWORD_union, KEYWORD_use, KEYWORD_value, KEYWORD_virtual, KEYWORD_volatile, KEYWORD_where, KEYWORD_while} keywordId;/* Used to determine whether keyword is valid for the token language and * what its ID is. */typedef struct sKeywordDesc { const char *name; keywordId id;} keywordDesc;typedef enum eTokenType { TOKEN_UNDEFINED, TOKEN_COMMA, TOKEN_DOUBLE_COLON, TOKEN_IDENTIFIER, TOKEN_KEYWORD, TOKEN_LABEL, TOKEN_NUMERIC, TOKEN_OPERATOR, TOKEN_PAREN_CLOSE, TOKEN_PAREN_OPEN, TOKEN_PERCENT, TOKEN_STATEMENT_END, TOKEN_STRING} tokenType;typedef enum eTagType { TAG_UNDEFINED = -1, TAG_BLOCK_DATA, TAG_COMMON_BLOCK, TAG_ENTRY_POINT, TAG_FUNCTION, TAG_INTERFACE, TAG_COMPONENT, TAG_LABEL, TAG_LOCAL, TAG_MODULE, TAG_NAMELIST, TAG_PROGRAM, TAG_SUBROUTINE, TAG_DERIVED_TYPE, TAG_VARIABLE, TAG_COUNT /* must be last */} tagType;typedef struct sTokenInfo { tokenType type; keywordId keyword; tagType tag; vString* string; struct sTokenInfo *secondary; unsigned long lineNumber; fpos_t filePosition;} tokenInfo;/** DATA DEFINITIONS*/static langType Lang_fortran;static jmp_buf Exception;static int Ungetc;static unsigned int Column;static boolean FreeSourceForm;static boolean ParsingString;static tokenInfo *Parent;/* indexed by tagType */static kindOption FortranKinds [] = { { TRUE, 'b', "block data", "block data"}, { TRUE, 'c', "common", "common blocks"}, { TRUE, 'e', "entry", "entry points"}, { TRUE, 'f', "function", "functions"}, { FALSE, 'i', "interface", "interface contents, generic names, and operators"}, { TRUE, 'k', "component", "type and structure components"}, { TRUE, 'l', "label", "labels"}, { FALSE, 'L', "local", "local, common block, and namelist variables"}, { TRUE, 'm', "module", "modules"}, { TRUE, 'n', "namelist", "namelists"}, { TRUE, 'p', "program", "programs"}, { TRUE, 's', "subroutine", "subroutines"}, { TRUE, 't', "type", "derived types and structures"}, { TRUE, 'v', "variable", "program (global) and module variables"}};/* For a definition of Fortran 77 with extensions: * http://scienide.uwaterloo.ca/MIPSpro7/007-2362-004/sgi_html/index.html * * For the Compaq Fortran Reference Manual: * http://h18009.www1.hp.com/fortran/docs/lrm/dflrm.htm */static const keywordDesc FortranKeywordTable [] = { /* keyword keyword ID */ { "allocatable", KEYWORD_allocatable }, { "assignment", KEYWORD_assignment }, { "automatic", KEYWORD_automatic }, { "block", KEYWORD_block }, { "byte", KEYWORD_byte }, { "cexternal", KEYWORD_cexternal }, { "cglobal", KEYWORD_cglobal }, { "character", KEYWORD_character }, { "common", KEYWORD_common }, { "complex", KEYWORD_complex }, { "contains", KEYWORD_contains }, { "data", KEYWORD_data }, { "dimension", KEYWORD_dimension }, { "dll_export", KEYWORD_dllexport }, { "dll_import", KEYWORD_dllimport }, { "do", KEYWORD_do }, { "double", KEYWORD_double }, { "elemental", KEYWORD_elemental }, { "end", KEYWORD_end }, { "entry", KEYWORD_entry }, { "equivalence", KEYWORD_equivalence }, { "external", KEYWORD_external }, { "format", KEYWORD_format }, { "function", KEYWORD_function }, { "if", KEYWORD_if }, { "implicit", KEYWORD_implicit }, { "include", KEYWORD_include }, { "inline", KEYWORD_inline }, { "integer", KEYWORD_integer }, { "intent", KEYWORD_intent }, { "interface", KEYWORD_interface }, { "intrinsic", KEYWORD_intrinsic }, { "logical", KEYWORD_logical }, { "map", KEYWORD_map }, { "module", KEYWORD_module }, { "namelist", KEYWORD_namelist }, { "operator", KEYWORD_operator }, { "optional", KEYWORD_optional }, { "parameter", KEYWORD_parameter }, { "pascal", KEYWORD_pascal }, { "pexternal", KEYWORD_pexternal }, { "pglobal", KEYWORD_pglobal }, { "pointer", KEYWORD_pointer }, { "precision", KEYWORD_precision }, { "private", KEYWORD_private }, { "program", KEYWORD_program }, { "public", KEYWORD_public }, { "pure", KEYWORD_pure }, { "real", KEYWORD_real }, { "record", KEYWORD_record }, { "recursive", KEYWORD_recursive }, { "save", KEYWORD_save }, { "select", KEYWORD_select }, { "sequence", KEYWORD_sequence }, { "static", KEYWORD_static }, { "stdcall", KEYWORD_stdcall }, { "structure", KEYWORD_structure }, { "subroutine", KEYWORD_subroutine }, { "target", KEYWORD_target }, { "then", KEYWORD_then }, { "type", KEYWORD_type }, { "union", KEYWORD_union }, { "use", KEYWORD_use }, { "value", KEYWORD_value }, { "virtual", KEYWORD_virtual }, { "volatile", KEYWORD_volatile }, { "where", KEYWORD_where }, { "while", KEYWORD_while }};static struct { unsigned int count; unsigned int max; tokenInfo* list;} Ancestors = { 0, 0, NULL };/** FUNCTION PROTOTYPES*/static void parseStructureStmt (tokenInfo *const token);static void parseUnionStmt (tokenInfo *const token);static void parseDerivedTypeDef (tokenInfo *const token);static void parseFunctionSubprogram (tokenInfo *const token);static void parseSubroutineSubprogram (tokenInfo *const token);/** FUNCTION DEFINITIONS*/static void ancestorPush (tokenInfo *const token){ enum { incrementalIncrease = 10 }; if (Ancestors.list == NULL) { Assert (Ancestors.max == 0); Ancestors.count = 0; Ancestors.max = incrementalIncrease; Ancestors.list = xMalloc (Ancestors.max, tokenInfo); } else if (Ancestors.count == Ancestors.max) { Ancestors.max += incrementalIncrease; Ancestors.list = xRealloc (Ancestors.list, Ancestors.max, tokenInfo); } Ancestors.list [Ancestors.count] = *token; Ancestors.list [Ancestors.count].string = vStringNewCopy (token->string); Ancestors.count++;}static void ancestorPop (void){ Assert (Ancestors.count > 0); --Ancestors.count; vStringDelete (Ancestors.list [Ancestors.count].string); Ancestors.list [Ancestors.count].type = TOKEN_UNDEFINED; Ancestors.list [Ancestors.count].keyword = KEYWORD_NONE; Ancestors.list [Ancestors.count].secondary = NULL; Ancestors.list [Ancestors.count].tag = TAG_UNDEFINED; Ancestors.list [Ancestors.count].string = NULL; Ancestors.list [Ancestors.count].lineNumber = 0L;}static const tokenInfo* ancestorScope (void){ tokenInfo *result = NULL; unsigned int i; for (i = Ancestors.count ; i > 0 && result == NULL ; --i) { tokenInfo *const token = Ancestors.list + i - 1; if (token->type == TOKEN_IDENTIFIER && token->tag != TAG_UNDEFINED && token->tag != TAG_INTERFACE) result = token; } return result;}static const tokenInfo* ancestorTop (void){ Assert (Ancestors.count > 0); return &Ancestors.list [Ancestors.count - 1];}#define ancestorCount() (Ancestors.count)static void ancestorClear (void){ while (Ancestors.count > 0) ancestorPop (); if (Ancestors.list != NULL) eFree (Ancestors.list); Ancestors.list = NULL; Ancestors.count = 0; Ancestors.max = 0;}static boolean insideInterface (void){ boolean result = FALSE; unsigned int i; for (i = 0 ; i < Ancestors.count && !result ; ++i) { if (Ancestors.list [i].tag == TAG_INTERFACE) result = TRUE; } return result;}static void buildFortranKeywordHash (void){ const size_t count = sizeof (FortranKeywordTable) / sizeof (FortranKeywordTable [0]); size_t i; for (i = 0 ; i < count ; ++i) { const keywordDesc* const p = &FortranKeywordTable [i]; addKeyword (p->name, Lang_fortran, (int) p->id); }}/** Tag generation functions*/static tokenInfo *newToken (void){ tokenInfo *const token = xMalloc (1, tokenInfo); token->type = TOKEN_UNDEFINED; token->keyword = KEYWORD_NONE; token->tag = TAG_UNDEFINED; token->string = vStringNew (); token->secondary = NULL; token->lineNumber = getSourceLineNumber (); token->filePosition = getInputFilePosition (); return token;}static tokenInfo *newTokenFrom (tokenInfo *const token){ tokenInfo *result = newToken (); *result = *token; result->string = vStringNewCopy (token->string); token->secondary = NULL; return result;}static void deleteToken (tokenInfo *const token){ if (token != NULL) { vStringDelete (token->string); deleteToken (token->secondary); token->secondary = NULL; eFree (token); }}static boolean isFileScope (const tagType type){ return (boolean) (type == TAG_LABEL || type == TAG_LOCAL);}static boolean includeTag (const tagType type){ boolean include; Assert (type != TAG_UNDEFINED); include = FortranKinds [(int) type].enabled; if (include && isFileScope (type)) include = Option.include.fileScope; return include;}static void makeFortranTag (tokenInfo *const token, tagType tag){ token->tag = tag; if (includeTag (token->tag)) { const char *const name = vStringValue (token->string); tagEntryInfo e; initTagEntry (&e, name); if (token->tag == TAG_COMMON_BLOCK) e.lineNumberEntry = (boolean) (Option.locate != EX_PATTERN); e.lineNumber = token->lineNumber; e.filePosition = token->filePosition; e.isFileScope = isFileScope (token->tag); e.kindName = FortranKinds [token->tag].name; e.kind = FortranKinds [token->tag].letter; e.truncateLine = (boolean) (token->tag != TAG_LABEL); if (ancestorCount () > 0) { const tokenInfo* const scope = ancestorScope (); if (scope != NULL) { e.extensionFields.scope [0] = FortranKinds [scope->tag].name; e.extensionFields.scope [1] = vStringValue (scope->string); } } if (! insideInterface () || includeTag (TAG_INTERFACE)) makeTagEntry (&e); }}/** Parsing functions*/static int skipLine (void){ int c; do c = fileGetc (); while (c != EOF && c != '\n'); return c;}static void makeLabelTag (vString *const label){ tokenInfo *token = newToken (); token->type = TOKEN_LABEL; vStringCopy (token->string, label); makeFortranTag (token, TAG_LABEL); deleteToken (token);}static lineType getLineType (void){ static vString *label = NULL; int column = 0; lineType type = LTYPE_UNDETERMINED; if (label == NULL) label = vStringNew (); do /* read in first 6 "margin" characters */ { int c = fileGetc (); /* 3.2.1 Comment_Line. A comment line is any line that contains * a C or an asterisk in column 1, or contains only blank characters * in columns 1 through 72. A comment line that contains a C or * an asterisk in column 1 may contain any character capable of * representation in the processor in columns 2 through 72. */ /* EXCEPTION! Some compilers permit '!' as a commment character here. * * Treat # and $ in column 1 as comment to permit preprocessor directives. * Treat D and d in column 1 as comment for HP debug statements. */ if (column == 0 && strchr ("*Cc!#$Dd", c) != NULL) type = LTYPE_COMMENT; else if (c == '\t') /* EXCEPTION! Some compilers permit a tab here */ { column = 8; type = LTYPE_INITIAL; } else if (column == 5) { /* 3.2.2 Initial_Line. An initial line is any line that is not * a comment line and contains the character blank or the digit 0 * in column 6. Columns 1 through 5 may contain a statement label * (3.4), or each of the columns 1 through 5 must contain the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -