From e5f89d372ca33321c14d028fca25e13d621f2862 Mon Sep 17 00:00:00 2001 From: Qingming He <906459647@qq.com> Date: Sat, 4 Jul 2015 01:38:03 +0800 Subject: [PATCH 1/2] Fortran: parse Fortran 2003 enums Allow for not-yet-standard enum naming using `:: name` syntax, see http://docs.cray.com/books/S-3692-51/html-S-3692-51/z970507905n9123.html Authored by Colomban Wendling The difference from that of Geany is that the kind of enumerator is 'N' rather than 'F'. This is because KIND_FILE_DEFAULT is 'F' defined in parse.h. If kind of enumerator is 'F' then doesParserUseKind will return TRUE which will make an assertion. --- parsers/fortran.c | 88 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 79 insertions(+), 9 deletions(-) diff --git a/parsers/fortran.c b/parsers/fortran.c index 76586ce5f1..804a47775f 100644 --- a/parsers/fortran.c +++ b/parsers/fortran.c @@ -81,6 +81,8 @@ typedef enum eKeywordId { KEYWORD_elemental, KEYWORD_end, KEYWORD_entry, + KEYWORD_enum, + KEYWORD_enumerator, KEYWORD_equivalence, KEYWORD_extends, KEYWORD_external, @@ -172,6 +174,7 @@ typedef enum eTagType { TAG_BLOCK_DATA, TAG_COMMON_BLOCK, TAG_ENTRY_POINT, + TAG_ENUM, TAG_FUNCTION, TAG_INTERFACE, TAG_COMPONENT, @@ -180,6 +183,7 @@ typedef enum eTagType { TAG_MODULE, TAG_METHOD, TAG_NAMELIST, + TAG_ENUMERATOR, TAG_PROGRAM, TAG_PROTOTYPE, TAG_SUBROUTINE, @@ -226,6 +230,7 @@ static kindOption FortranKinds [] = { { TRUE, 'b', "block data", "block data"}, { TRUE, 'c', "common", "common blocks"}, { TRUE, 'e', "entry", "entry points"}, + { TRUE, 'E', "enum", "enumerations"}, { TRUE, 'f', "function", "functions"}, { TRUE, 'i', "interface", "interface contents, generic names, and operators"}, { TRUE, 'k', "component", "type and structure components"}, @@ -234,6 +239,7 @@ static kindOption FortranKinds [] = { { TRUE, 'm', "module", "modules"}, { TRUE, 'M', "method", "type bound procedures"}, { TRUE, 'n', "namelist", "namelists"}, + { TRUE, 'N', "enumerator", "enumeration values"}, { TRUE, 'p', "program", "programs"}, { FALSE, 'P', "prototype", "subprogram prototypes"}, { TRUE, 's', "subroutine", "subroutines"}, @@ -277,6 +283,8 @@ static const keywordDesc FortranKeywordTable [] = { { "elemental", KEYWORD_elemental }, { "end", KEYWORD_end }, { "entry", KEYWORD_entry }, + { "enum", KEYWORD_enum }, + { "enumerator", KEYWORD_enumerator }, { "equivalence", KEYWORD_equivalence }, { "extends", KEYWORD_extends }, { "external", KEYWORD_external }, @@ -400,7 +408,8 @@ static const tokenInfo* ancestorScope (void) { tokenInfo *const token = Ancestors.list + i - 1; if (token->type == TOKEN_IDENTIFIER && - token->tag != TAG_UNDEFINED && token->tag != TAG_INTERFACE) + token->tag != TAG_UNDEFINED && token->tag != TAG_INTERFACE && + token->tag != TAG_ENUM) result = token; } return result; @@ -1221,6 +1230,7 @@ static boolean isTypeSpec (tokenInfo *const token) case KEYWORD_final: case KEYWORD_generic: case KEYWORD_class: + case KEYWORD_enumerator: result = TRUE; break; default: @@ -1248,6 +1258,21 @@ static boolean isSubprogramPrefix (tokenInfo *const token) return result; } +static void parseKindSelector (tokenInfo *const token) +{ + if (isType (token, TOKEN_PAREN_OPEN)) + skipOverParens (token); /* skip kind-selector */ + if (isType (token, TOKEN_OPERATOR) && + strcmp (vStringValue (token->string), "*") == 0) + { + readToken (token); + if (isType (token, TOKEN_PAREN_OPEN)) + skipOverParens (token); + else + readToken (token); + } +} + /* type-spec * is INTEGER [kind-selector] * or REAL [kind-selector] is ( etc. ) @@ -1286,14 +1311,7 @@ static void parseTypeSpec (tokenInfo *const token) case KEYWORD_procedure: case KEYWORD_class: readToken (token); - if (isType (token, TOKEN_PAREN_OPEN)) - skipOverParens (token); /* skip kind-selector */ - if (isType (token, TOKEN_OPERATOR) && - strcmp (vStringValue (token->string), "*") == 0) - { - readToken (token); - readToken (token); - } + parseKindSelector (token); break; case KEYWORD_double: @@ -1326,6 +1344,7 @@ static void parseTypeSpec (tokenInfo *const token) case KEYWORD_final: case KEYWORD_generic: + case KEYWORD_enumerator: readToken (token); break; @@ -1500,6 +1519,7 @@ static tagType variableTagType (tokenInfo *const st) case TAG_FUNCTION: result = TAG_LOCAL; break; case TAG_SUBROUTINE: result = TAG_LOCAL; break; case TAG_PROTOTYPE: result = TAG_LOCAL; break; + case TAG_ENUM: result = TAG_ENUMERATOR; break; default: result = TAG_VARIABLE; break; } } @@ -2023,6 +2043,54 @@ static void parseInterfaceBlock (tokenInfo *const token) deleteToken (name); } +/* enum-block + * enum-stmt (is ENUM, BIND(C) [ :: type-alias-name ] + * or ENUM [ kind-selector ] [ :: ] [ type-alias-name ]) + * [ enum-body (is ENUMERATOR [ :: ] enumerator-list) ] + * end-enum-stmt (is END ENUM) + */ +static void parseEnumBlock (tokenInfo *const token) +{ + tokenInfo *name = NULL; + Assert (isKeyword (token, KEYWORD_enum)); + readToken (token); + if (isType (token, TOKEN_COMMA)) + { + readToken (token); + if (isType (token, TOKEN_KEYWORD)) + readToken (token); + if (isType (token, TOKEN_PAREN_OPEN)) + skipOverParens (token); + } + parseKindSelector (token); + if (isType (token, TOKEN_DOUBLE_COLON)) + readToken (token); + if (isType (token, TOKEN_IDENTIFIER)) + name = newTokenFrom (token); + if (name == NULL) + { + name = newToken (); + name->type = TOKEN_IDENTIFIER; + name->tag = TAG_ENUM; + } + else + makeFortranTag (name, TAG_ENUM); + skipToNextStatement (token); + ancestorPush (name); + while (! isKeyword (token, KEYWORD_end)) + { + if (isTypeSpec (token)) + parseTypeDeclarationStmt (token); + else + skipToNextStatement (token); + } + readSubToken (token); + /* secondary token should be KEYWORD_enum token */ + skipToNextStatement (token); + ancestorPop (); + deleteToken (name); +} + /* entry-stmt is * ENTRY entry-name [ ( dummy-arg-list ) ] */ @@ -2104,6 +2172,7 @@ static boolean parseDeclarationConstruct (tokenInfo *const token) { case KEYWORD_entry: parseEntryStmt (token); break; case KEYWORD_interface: parseInterfaceBlock (token); break; + case KEYWORD_enum: parseEnumBlock (token); break; case KEYWORD_stdcall: readToken (token); break; /* derived type handled by parseTypeDeclarationStmt(); */ @@ -2324,6 +2393,7 @@ static boolean parseExecutionPart (tokenInfo *const token) case KEYWORD_end: readSubToken (token); if (isSecondaryKeyword (token, KEYWORD_do) || + isSecondaryKeyword (token, KEYWORD_enum) || isSecondaryKeyword (token, KEYWORD_if) || isSecondaryKeyword (token, KEYWORD_select) || isSecondaryKeyword (token, KEYWORD_where) || From 2635a2c8c2c0ac464ab2d8a9ab1ccf18b5463ba2 Mon Sep 17 00:00:00 2001 From: Qingming He <906459647@qq.com> Date: Sat, 4 Jul 2015 01:46:20 +0800 Subject: [PATCH 2/2] test for Fortran enum Test cases contributed by Adam Hirst --- .../fortran-enum.d/expected.tags | 45 ++++++++++++++++ .../parser-fortran.r/fortran-enum.d/input.f90 | 52 +++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 Units/parser-fortran.r/fortran-enum.d/expected.tags create mode 100644 Units/parser-fortran.r/fortran-enum.d/input.f90 diff --git a/Units/parser-fortran.r/fortran-enum.d/expected.tags b/Units/parser-fortran.r/fortran-enum.d/expected.tags new file mode 100644 index 0000000000..c2da696718 --- /dev/null +++ b/Units/parser-fortran.r/fortran-enum.d/expected.tags @@ -0,0 +1,45 @@ +Constants input.f90 /^module Constants$/;" m +E_e input.f90 /^ real, parameter :: E_e /;" v module:Constants +Named1 input.f90 /^ enum :: Named1$/;" E module:Constants +Named2 input.f90 /^ enum Named2$/;" E module:Constants +Named3 input.f90 /^ enum(8) Named3$/;" E module:Constants +Named4 input.f90 /^ enum*8 Named4$/;" E module:Constants +Named5 input.f90 /^ enum(8) :: Named5$/;" E module:Constants +Named6 input.f90 /^ enum*8 :: Named6$/;" E module:Constants +Named7 input.f90 /^ enum, bind(c) :: Named7$/;" E module:Constants +a input.f90 /^ enumerat/;" N module:Constants +b input.f90 /^ enumerator :: a, b,/;" N module:Constants +black input.f90 /^ enumerator :: red =1, blue, black /;" N module:Constants +blue input.f90 /^ enumerator :: red =1, blue,/;" N module:Constants +bronze input.f90 /^ enumerator gold, silver, bronze$/;" N module:Constants +c input.f90 /^ enumerator :: a, b, c$/;" N module:Constants +gold input.f90 /^ enumerator gold,/;" N module:Constants +hc input.f90 /^ real, parameter :: hc /;" v module:Constants +lavender input.f90 /^ enumerator :: pink, lavender$/;" N module:Constants +pi input.f90 /^ real, parameter :: pi /;" v module:Constants +pink input.f90 /^ enumerator :: pink,/;" N module:Constants +purple input.f90 /^ enumerator :: purple$/;" N module:Constants +red input.f90 /^ enumerator :: red /;" N module:Constants +silver input.f90 /^ enumerator gold, silver,/;" N module:Constants +x1 input.f90 /^ enumerator :: x1,/;" N module:Constants +x2 input.f90 /^ enumerator :: x2,/;" N module:Constants +x3 input.f90 /^ enumerator :: x3,/;" N module:Constants +x4 input.f90 /^ enumerator :: x4,/;" N module:Constants +x5 input.f90 /^ enumerator :: x5,/;" N module:Constants +x6 input.f90 /^ enumerator :: x6,/;" N module:Constants +x7 input.f90 /^ enumerator :: x7,/;" N module:Constants +y1 input.f90 /^ enumerator :: x1, y1,/;" N module:Constants +y2 input.f90 /^ enumerator :: x2, y2,/;" N module:Constants +y3 input.f90 /^ enumerator :: x3, y3,/;" N module:Constants +y4 input.f90 /^ enumerator :: x4, y4,/;" N module:Constants +y5 input.f90 /^ enumerator :: x5, y5,/;" N module:Constants +y6 input.f90 /^ enumerator :: x6, y6,/;" N module:Constants +y7 input.f90 /^ enumerator :: x7, y7,/;" N module:Constants +yellow input.f90 /^ enumerator yellow$/;" N module:Constants +z1 input.f90 /^ enumerator :: x1, y1, z1$/;" N module:Constants +z2 input.f90 /^ enumerator :: x2, y2, z2$/;" N module:Constants +z3 input.f90 /^ enumerator :: x3, y3, z3$/;" N module:Constants +z4 input.f90 /^ enumerator :: x4, y4, z4$/;" N module:Constants +z5 input.f90 /^ enumerator :: x5, y5, z5$/;" N module:Constants +z6 input.f90 /^ enumerator :: x6, y6, z6$/;" N module:Constants +z7 input.f90 /^ enumerator :: x7, y7, z7$/;" N module:Constants diff --git a/Units/parser-fortran.r/fortran-enum.d/input.f90 b/Units/parser-fortran.r/fortran-enum.d/input.f90 new file mode 100644 index 0000000000..90ef81315e --- /dev/null +++ b/Units/parser-fortran.r/fortran-enum.d/input.f90 @@ -0,0 +1,52 @@ +module Constants + implicit none + + real, parameter :: pi = 4 * atan(1.0) + real, parameter :: E_e = 510998.91013 + + ! we now have enumerators in F2003/8, for the sake of interop with C + enum, bind(c) ! unnamed 1 + enumerator :: red =1, blue, black =5 + enumerator yellow + enumerator gold, silver, bronze + enumerator :: purple + enumerator :: pink, lavender + end enum + + enum ! unnamed 2 + enumerator :: a, b, c + end enum + + enum :: Named1 + enumerator :: x1, y1, z1 + end enum + + enum Named2 + enumerator :: x2, y2, z2 + end enum + + enum(8) Named3 + enumerator :: x3, y3, z3 + end enum + + enum*8 Named4 + enumerator :: x4, y4, z4 + end enum + + enum(8) :: Named5 + enumerator :: x5, y5, z5 + end enum + + enum*8 :: Named6 + enumerator :: x6, y6, z6 + end enum + + enum, bind(c) :: Named7 + enumerator :: x7, y7, z7 + end enum + + real, parameter :: hc = 12398.4193 + + public + +end module Constants