2 * Copyright (c) 1998-2003, Darren Hiebert
4 * This source code is released for free distribution under the terms of the
5 * GNU General Public License version 2 or (at your option) any later version.
7 * This module contains functions for generating tags for Fortran language
14 #include "general.h" /* must always come first */
18 #include <ctype.h> /* to define tolower () */
36 #define isident(c) (isalnum(c) || (c) == '_')
37 #define isBlank(c) (boolean) (c == ' ' || c == '\t')
38 #define isType(token,t) (boolean) ((token)->type == (t))
39 #define isKeyword(token,k) (boolean) ((token)->keyword == (k))
40 #define isSecondaryKeyword(token,k) (boolean) ((token)->secondary == NULL ? \
41 FALSE : (token)->secondary->keyword == (k))
47 typedef enum eException
{
48 ExceptionNone
, ExceptionEOF
, ExceptionFixedFormat
, ExceptionLoop
51 /* Used to designate type of line read in fixed source form.
53 typedef enum eFortranLineType
{
63 /* Used to specify type of keyword.
65 typedef enum eKeywordId
{
147 /* Used to determine whether keyword is valid for the token language and
150 typedef struct sKeywordDesc
{
155 typedef enum eTokenType
{
173 typedef enum eTagType
{
191 TAG_COUNT
/* must be last */
194 typedef struct sTokenInfo
{
199 struct sTokenInfo
*secondary
;
200 unsigned long lineNumber
;
208 static langType Lang_fortran
;
209 static langType Lang_f77
;
210 static jmp_buf Exception
;
211 static int Ungetc
= '\0';
212 static unsigned int Column
= 0;
213 static boolean FreeSourceForm
= FALSE
;
214 static boolean ParsingString
;
215 static tokenInfo
*Parent
= NULL
;
216 static boolean NewLine
= TRUE
;
217 static unsigned int contextual_fake_count
= 0;
219 /* indexed by tagType */
220 static kindOption FortranKinds
[TAG_COUNT
] = {
221 { TRUE
, 'b', "blockData", "block data"},
222 { TRUE
, 'c', "common", "common blocks"},
223 { TRUE
, 'e', "entry", "entry points"},
224 { TRUE
, 'f', "function", "functions"},
225 { TRUE
, 'i', "interface", "interface contents, generic names, and operators"},
226 { TRUE
, 'k', "component", "type and structure components"},
227 { TRUE
, 'l', "label", "labels"},
228 { FALSE
, 'L', "local", "local, common block, and namelist variables"},
229 { TRUE
, 'm', "module", "modules"},
230 { TRUE
, 'n', "namelist", "namelists"},
231 { TRUE
, 'p', "program", "programs"},
232 { TRUE
, 's', "subroutine", "subroutines"},
233 { TRUE
, 't', "type", "derived types and structures"},
234 { TRUE
, 'v', "variable", "program (global) and module variables"},
235 { TRUE
, 'E', "enum", "enumerations"},
236 { TRUE
, 'N', "enumerator", "enumeration values"},
239 /* For efinitions of Fortran 77 with extensions:
240 * http://www.fortran.com/fortran/F77_std/rjcnf0001.html
241 * http://scienide.uwaterloo.ca/MIPSpro7/007-2362-004/sgi_html/index.html
243 * For the Compaq Fortran Reference Manual:
244 * http://h18009.www1.hp.com/fortran/docs/lrm/dflrm.htm
247 static const keywordDesc FortranKeywordTable
[] = {
248 /* keyword keyword ID */
249 { "allocatable", KEYWORD_allocatable
},
250 { "assignment", KEYWORD_assignment
},
251 { "associate", KEYWORD_associate
},
252 { "automatic", KEYWORD_automatic
},
253 { "bind", KEYWORD_bind
},
254 { "block", KEYWORD_block
},
255 { "byte", KEYWORD_byte
},
256 { "cexternal", KEYWORD_cexternal
},
257 { "cglobal", KEYWORD_cglobal
},
258 { "character", KEYWORD_character
},
259 { "codimension", KEYWORD_codimension
},
260 { "common", KEYWORD_common
},
261 { "complex", KEYWORD_complex
},
262 { "contains", KEYWORD_contains
},
263 { "data", KEYWORD_data
},
264 { "dimension", KEYWORD_dimension
},
265 { "dll_export", KEYWORD_dllexport
},
266 { "dll_import", KEYWORD_dllimport
},
267 { "do", KEYWORD_do
},
268 { "double", KEYWORD_double
},
269 { "elemental", KEYWORD_elemental
},
270 { "end", KEYWORD_end
},
271 { "entry", KEYWORD_entry
},
272 { "enum", KEYWORD_enum
},
273 { "enumerator", KEYWORD_enumerator
},
274 { "equivalence", KEYWORD_equivalence
},
275 { "extends", KEYWORD_extends
},
276 { "external", KEYWORD_external
},
277 { "forall", KEYWORD_forall
},
278 { "format", KEYWORD_format
},
279 { "function", KEYWORD_function
},
280 { "if", KEYWORD_if
},
281 { "implicit", KEYWORD_implicit
},
282 { "include", KEYWORD_include
},
283 { "inline", KEYWORD_inline
},
284 { "integer", KEYWORD_integer
},
285 { "intent", KEYWORD_intent
},
286 { "interface", KEYWORD_interface
},
287 { "intrinsic", KEYWORD_intrinsic
},
288 { "kind", KEYWORD_kind
},
289 { "len", KEYWORD_len
},
290 { "logical", KEYWORD_logical
},
291 { "map", KEYWORD_map
},
292 { "module", KEYWORD_module
},
293 { "namelist", KEYWORD_namelist
},
294 { "operator", KEYWORD_operator
},
295 { "optional", KEYWORD_optional
},
296 { "parameter", KEYWORD_parameter
},
297 { "pascal", KEYWORD_pascal
},
298 { "pexternal", KEYWORD_pexternal
},
299 { "pglobal", KEYWORD_pglobal
},
300 { "pointer", KEYWORD_pointer
},
301 { "precision", KEYWORD_precision
},
302 { "private", KEYWORD_private
},
303 { "procedure", KEYWORD_procedure
},
304 { "program", KEYWORD_program
},
305 { "public", KEYWORD_public
},
306 { "pure", KEYWORD_pure
},
307 { "real", KEYWORD_real
},
308 { "record", KEYWORD_record
},
309 { "recursive", KEYWORD_recursive
},
310 { "save", KEYWORD_save
},
311 { "select", KEYWORD_select
},
312 { "sequence", KEYWORD_sequence
},
313 { "static", KEYWORD_static
},
314 { "stdcall", KEYWORD_stdcall
},
315 { "structure", KEYWORD_structure
},
316 { "subroutine", KEYWORD_subroutine
},
317 { "target", KEYWORD_target
},
318 { "then", KEYWORD_then
},
319 { "type", KEYWORD_type
},
320 { "union", KEYWORD_union
},
321 { "use", KEYWORD_use
},
322 { "value", KEYWORD_value
},
323 { "virtual", KEYWORD_virtual
},
324 { "volatile", KEYWORD_volatile
},
325 { "where", KEYWORD_where
},
326 { "while", KEYWORD_while
}
333 } Ancestors
= { 0, 0, NULL
};
336 * FUNCTION PROTOTYPES
338 static void parseStructureStmt (tokenInfo
*const token
);
339 static void parseUnionStmt (tokenInfo
*const token
);
340 static void parseDerivedTypeDef (tokenInfo
*const token
);
341 static void parseFunctionSubprogram (tokenInfo
*const token
);
342 static void parseSubroutineSubprogram (tokenInfo
*const token
);
345 * FUNCTION DEFINITIONS
348 static void ancestorPush (tokenInfo
*const token
)
350 enum { incrementalIncrease
= 10 };
351 if (Ancestors
.list
== NULL
)
353 Assert (Ancestors
.max
== 0);
355 Ancestors
.max
= incrementalIncrease
;
356 Ancestors
.list
= xMalloc (Ancestors
.max
, tokenInfo
);
358 else if (Ancestors
.count
== Ancestors
.max
)
360 Ancestors
.max
+= incrementalIncrease
;
361 Ancestors
.list
= xRealloc (Ancestors
.list
, Ancestors
.max
, tokenInfo
);
363 Ancestors
.list
[Ancestors
.count
] = *token
;
364 Ancestors
.list
[Ancestors
.count
].string
= vStringNewCopy (token
->string
);
368 static void ancestorPop (void)
370 Assert (Ancestors
.count
> 0);
372 vStringDelete (Ancestors
.list
[Ancestors
.count
].string
);
374 Ancestors
.list
[Ancestors
.count
].type
= TOKEN_UNDEFINED
;
375 Ancestors
.list
[Ancestors
.count
].keyword
= KEYWORD_NONE
;
376 Ancestors
.list
[Ancestors
.count
].secondary
= NULL
;
377 Ancestors
.list
[Ancestors
.count
].tag
= TAG_UNDEFINED
;
378 Ancestors
.list
[Ancestors
.count
].string
= NULL
;
379 Ancestors
.list
[Ancestors
.count
].lineNumber
= 0L;
382 static const tokenInfo
* ancestorScope (void)
384 tokenInfo
*result
= NULL
;
386 for (i
= Ancestors
.count
; i
> 0 && result
== NULL
; --i
)
388 tokenInfo
*const token
= Ancestors
.list
+ i
- 1;
389 if (token
->type
== TOKEN_IDENTIFIER
&&
390 token
->tag
!= TAG_UNDEFINED
)
396 static const tokenInfo
* ancestorTop (void)
398 Assert (Ancestors
.count
> 0);
399 return &Ancestors
.list
[Ancestors
.count
- 1];
402 #define ancestorCount() (Ancestors.count)
404 static void ancestorClear (void)
406 while (Ancestors
.count
> 0)
408 if (Ancestors
.list
!= NULL
)
409 eFree (Ancestors
.list
);
410 Ancestors
.list
= NULL
;
415 static boolean
insideInterface (void)
417 boolean result
= FALSE
;
419 for (i
= 0 ; i
< Ancestors
.count
&& !result
; ++i
)
421 if (Ancestors
.list
[i
].tag
== TAG_INTERFACE
)
427 static void buildFortranKeywordHash (const langType language
)
430 sizeof (FortranKeywordTable
) / sizeof (FortranKeywordTable
[0]);
432 for (i
= 0 ; i
< count
; ++i
)
434 const keywordDesc
* const p
= &FortranKeywordTable
[i
];
435 addKeyword (p
->name
, language
, (int) p
->id
);
440 * Tag generation functions
443 static tokenInfo
*newToken (void)
445 tokenInfo
*const token
= xMalloc (1, tokenInfo
);
447 token
->type
= TOKEN_UNDEFINED
;
448 token
->keyword
= KEYWORD_NONE
;
449 token
->tag
= TAG_UNDEFINED
;
450 token
->string
= vStringNew ();
451 token
->secondary
= NULL
;
452 token
->lineNumber
= getSourceLineNumber ();
453 token
->filePosition
= getInputFilePosition ();
458 static tokenInfo
*newTokenFrom (tokenInfo
*const token
)
460 tokenInfo
*result
= newToken ();
462 result
->string
= vStringNewCopy (token
->string
);
463 token
->secondary
= NULL
;
467 static tokenInfo
*newAnonTokenFrom (tokenInfo
*const token
, const char *type
)
470 tokenInfo
*result
= newTokenFrom (token
);
471 sprintf (buffer
, "%s#%u", type
, contextual_fake_count
++);
472 vStringClear (result
->string
);
473 vStringCatS (result
->string
, buffer
);
477 static void deleteToken (tokenInfo
*const token
)
481 vStringDelete (token
->string
);
482 deleteToken (token
->secondary
);
483 token
->secondary
= NULL
;
488 static boolean
isFileScope (const tagType type
)
490 return (boolean
) (type
== TAG_LABEL
|| type
== TAG_LOCAL
);
493 static boolean
includeTag (const tagType type
)
496 Assert (type
> TAG_UNDEFINED
&& type
< TAG_COUNT
);
497 include
= FortranKinds
[(int) type
].enabled
;
498 if (include
&& isFileScope (type
))
499 include
= Option
.include
.fileScope
;
503 static void makeFortranTag (tokenInfo
*const token
, tagType tag
)
506 if (includeTag (token
->tag
))
508 const char *const name
= vStringValue (token
->string
);
511 initTagEntry (&e
, name
);
513 if (token
->tag
== TAG_COMMON_BLOCK
)
514 e
.lineNumberEntry
= (boolean
) (Option
.locate
!= EX_PATTERN
);
516 e
.lineNumber
= token
->lineNumber
;
517 e
.filePosition
= token
->filePosition
;
518 e
.isFileScope
= isFileScope (token
->tag
);
519 e
.kindName
= FortranKinds
[token
->tag
].name
;
520 e
.kind
= FortranKinds
[token
->tag
].letter
;
521 e
.truncateLine
= (boolean
) (token
->tag
!= TAG_LABEL
);
523 if (ancestorCount () > 0)
525 const tokenInfo
* const scope
= ancestorScope ();
528 e
.extensionFields
.scope
[0] = FortranKinds
[scope
->tag
].name
;
529 e
.extensionFields
.scope
[1] = vStringValue (scope
->string
);
532 if (! insideInterface () /*|| includeTag (TAG_INTERFACE)*/)
541 static int skipLine (void)
547 while (c
!= EOF
&& c
!= '\n');
552 static void makeLabelTag (vString
*const label
)
554 tokenInfo
*token
= newToken ();
555 token
->type
= TOKEN_LABEL
;
556 vStringCopy (token
->string
, label
);
557 makeFortranTag (token
, TAG_LABEL
);
561 static lineType
getLineType (void)
563 vString
*label
= vStringNew ();
565 lineType type
= LTYPE_UNDETERMINED
;
567 do /* read in first 6 "margin" characters */
571 /* 3.2.1 Comment_Line. A comment line is any line that contains
572 * a C or an asterisk in column 1, or contains only blank characters
573 * in columns 1 through 72. A comment line that contains a C or
574 * an asterisk in column 1 may contain any character capable of
575 * representation in the processor in columns 2 through 72.
577 /* EXCEPTION! Some compilers permit '!' as a commment character here.
579 * Treat # and $ in column 1 as comment to permit preprocessor directives.
580 * Treat D and d in column 1 as comment for HP debug statements.
582 if (column
== 0 && strchr ("*Cc!#$Dd", c
) != NULL
)
583 type
= LTYPE_COMMENT
;
584 else if (c
== '\t') /* EXCEPTION! Some compilers permit a tab here */
587 type
= LTYPE_INITIAL
;
589 else if (column
== 5)
591 /* 3.2.2 Initial_Line. An initial line is any line that is not
592 * a comment line and contains the character blank or the digit 0
593 * in column 6. Columns 1 through 5 may contain a statement label
594 * (3.4), or each of the columns 1 through 5 must contain the
597 if (c
== ' ' || c
== '0')
598 type
= LTYPE_INITIAL
;
600 /* 3.2.3 Continuation_Line. A continuation line is any line that
601 * contains any character of the FORTRAN character set other than
602 * the character blank or the digit 0 in column 6 and contains
603 * only blank characters in columns 1 through 5.
605 else if (vStringLength (label
) == 0)
606 type
= LTYPE_CONTINUATION
;
608 type
= LTYPE_INVALID
;
616 else if (isdigit (c
))
617 vStringPut (label
, c
);
619 type
= LTYPE_INVALID
;
622 } while (column
< 6 && type
== LTYPE_UNDETERMINED
);
624 Assert (type
!= LTYPE_UNDETERMINED
);
626 if (vStringLength (label
) > 0)
628 vStringTerminate (label
);
629 makeLabelTag (label
);
631 vStringDelete (label
);
635 static int getFixedFormChar (void)
637 boolean newline
= FALSE
;
643 #ifdef STRICT_FIXED_FORM
644 /* EXCEPTION! Some compilers permit more than 72 characters per line.
656 newline
= TRUE
; /* need to check for continuation line */
659 else if (c
== '!' && ! ParsingString
)
662 newline
= TRUE
; /* need to check for continuation line */
665 else if (c
== '&') /* check for free source form */
667 const int c2
= fileGetc ();
669 longjmp (Exception
, (int) ExceptionFixedFormat
);
676 type
= getLineType ();
679 case LTYPE_UNDETERMINED
:
681 longjmp (Exception
, (int) ExceptionFixedFormat
);
684 case LTYPE_SHORT
: break;
685 case LTYPE_COMMENT
: skipLine (); break;
702 /* fall through to next case */
703 case LTYPE_CONTINUATION
:
709 } while (isBlank (c
));
720 Assert ("Unexpected line type" == NULL
);
726 static int skipToNextLine (void)
734 static int getFreeFormChar (boolean inComment
)
736 boolean advanceLine
= FALSE
;
739 /* If the last nonblank, non-comment character of a FORTRAN 90
740 * free-format text line is an ampersand then the next non-comment
741 * line is a continuation line.
743 if (! inComment
&& c
== '&')
747 while (isspace (c
) && c
!= '\n');
761 else if (NewLine
&& (c
== '!' || c
== '#'))
767 if (c
== '!' || (NewLine
&& c
== '#'))
769 c
= skipToNextLine ();
778 NewLine
= (boolean
) (c
== '\n');
782 static int getChar (void)
791 else if (FreeSourceForm
)
792 c
= getFreeFormChar (FALSE
);
794 c
= getFixedFormChar ();
798 static void ungetChar (const int c
)
803 /* If a numeric is passed in 'c', this is used as the first digit of the
804 * numeric being parsed.
806 static vString
*parseInteger (int c
)
808 vString
*string
= vStringNew ();
812 vStringPut (string
, c
);
815 else if (! isdigit (c
))
817 while (c
!= EOF
&& isdigit (c
))
819 vStringPut (string
, c
);
822 vStringTerminate (string
);
828 while (c
!= EOF
&& isalpha (c
));
835 static vString
*parseNumeric (int c
)
837 vString
*string
= vStringNew ();
838 vString
*integer
= parseInteger (c
);
839 vStringCopy (string
, integer
);
840 vStringDelete (integer
);
845 integer
= parseInteger ('\0');
846 vStringPut (string
, c
);
847 vStringCat (string
, integer
);
848 vStringDelete (integer
);
851 if (tolower (c
) == 'e')
853 integer
= parseInteger ('\0');
854 vStringPut (string
, c
);
855 vStringCat (string
, integer
);
856 vStringDelete (integer
);
861 vStringTerminate (string
);
866 static void parseString (vString
*const string
, const int delimiter
)
868 const unsigned long inputLineNumber
= getInputLineNumber ();
870 ParsingString
= TRUE
;
872 while (c
!= delimiter
&& c
!= '\n' && c
!= EOF
)
874 vStringPut (string
, c
);
877 if (c
== '\n' || c
== EOF
)
879 verbose ("%s: unterminated character string at line %lu\n",
880 getInputFileName (), inputLineNumber
);
882 longjmp (Exception
, (int) ExceptionEOF
);
883 else if (! FreeSourceForm
)
884 longjmp (Exception
, (int) ExceptionFixedFormat
);
886 vStringTerminate (string
);
887 ParsingString
= FALSE
;
890 /* Read a C identifier beginning with "firstChar" and places it into "name".
892 static void parseIdentifier (vString
*const string
, const int firstChar
)
898 vStringPut (string
, c
);
900 } while (isident (c
));
902 vStringTerminate (string
);
903 ungetChar (c
); /* unget non-identifier character */
906 static void checkForLabel (void)
908 tokenInfo
* token
= NULL
;
916 for (length
= 0 ; isdigit (c
) && length
< 5 ; ++length
)
921 token
->type
= TOKEN_LABEL
;
923 vStringPut (token
->string
, c
);
926 if (length
> 0 && token
!= NULL
)
928 vStringTerminate (token
->string
);
929 makeFortranTag (token
, TAG_LABEL
);
935 /* Analyzes the identifier contained in a statement described by the
936 * statement structure and adjusts the structure according the significance
939 static keywordId
analyzeToken (vString
*const name
, langType language
)
941 static vString
*keyword
= NULL
;
945 keyword
= vStringNew ();
946 vStringCopyToLower (keyword
, name
);
947 id
= (keywordId
) lookupKeyword (vStringValue (keyword
), language
);
952 static void readIdentifier (tokenInfo
*const token
, const int c
)
954 parseIdentifier (token
->string
, c
);
955 token
->keyword
= analyzeToken (token
->string
, Lang_fortran
);
956 if (! isKeyword (token
, KEYWORD_NONE
))
957 token
->type
= TOKEN_KEYWORD
;
960 token
->type
= TOKEN_IDENTIFIER
;
961 if (strncmp (vStringValue (token
->string
), "end", 3) == 0)
963 vString
*const sub
= vStringNewInit (vStringValue (token
->string
) + 3);
964 const keywordId kw
= analyzeToken (sub
, Lang_fortran
);
966 if (kw
!= KEYWORD_NONE
)
968 token
->secondary
= newToken ();
969 token
->secondary
->type
= TOKEN_KEYWORD
;
970 token
->secondary
->keyword
= kw
;
971 token
->keyword
= KEYWORD_end
;
977 static void readToken (tokenInfo
*const token
)
981 deleteToken (token
->secondary
);
982 token
->type
= TOKEN_UNDEFINED
;
983 token
->tag
= TAG_UNDEFINED
;
984 token
->keyword
= KEYWORD_NONE
;
985 token
->secondary
= NULL
;
986 vStringClear (token
->string
);
991 token
->lineNumber
= getSourceLineNumber ();
992 token
->filePosition
= getInputFilePosition ();
996 case EOF
: longjmp (Exception
, (int) ExceptionEOF
); break;
997 case ' ': goto getNextChar
;
998 case '\t': goto getNextChar
;
999 case ',': token
->type
= TOKEN_COMMA
; break;
1000 case '(': token
->type
= TOKEN_PAREN_OPEN
; break;
1001 case ')': token
->type
= TOKEN_PAREN_CLOSE
; break;
1002 case '[': token
->type
= TOKEN_SQUARE_OPEN
; break;
1003 case ']': token
->type
= TOKEN_SQUARE_CLOSE
; break;
1004 case '%': token
->type
= TOKEN_PERCENT
; break;
1014 const char *const operatorChars
= "*/+=<>";
1016 vStringPut (token
->string
, c
);
1018 } while (strchr (operatorChars
, c
) != NULL
);
1020 vStringTerminate (token
->string
);
1021 token
->type
= TOKEN_OPERATOR
;
1029 c
= getFreeFormChar (TRUE
);
1030 while (c
!= '\n' && c
!= EOF
);
1037 /* fall through to newline case */
1039 token
->type
= TOKEN_STATEMENT_END
;
1045 parseIdentifier (token
->string
, c
);
1049 vStringPut (token
->string
, c
);
1050 vStringTerminate (token
->string
);
1051 token
->type
= TOKEN_OPERATOR
;
1056 token
->type
= TOKEN_UNDEFINED
;
1062 parseString (token
->string
, c
);
1063 token
->type
= TOKEN_STRING
;
1067 token
->type
= TOKEN_STATEMENT_END
;
1073 token
->type
= TOKEN_DOUBLE_COLON
;
1077 token
->type
= TOKEN_UNDEFINED
;
1083 readIdentifier (token
, c
);
1084 else if (isdigit (c
))
1086 vString
*numeric
= parseNumeric (c
);
1087 vStringCat (token
->string
, numeric
);
1088 vStringDelete (numeric
);
1089 token
->type
= TOKEN_NUMERIC
;
1092 token
->type
= TOKEN_UNDEFINED
;
1097 static void readSubToken (tokenInfo
*const token
)
1099 if (token
->secondary
== NULL
)
1101 token
->secondary
= newToken ();
1102 readToken (token
->secondary
);
1107 * Scanning functions
1110 static void skipToToken (tokenInfo
*const token
, tokenType type
)
1112 while (! isType (token
, type
) && ! isType (token
, TOKEN_STATEMENT_END
) &&
1113 !(token
->secondary
!= NULL
&& isType (token
->secondary
, TOKEN_STATEMENT_END
)))
1117 static void skipPast (tokenInfo
*const token
, tokenType type
)
1119 skipToToken (token
, type
);
1120 if (! isType (token
, TOKEN_STATEMENT_END
))
1124 static void skipToNextStatement (tokenInfo
*const token
)
1128 skipToToken (token
, TOKEN_STATEMENT_END
);
1130 } while (isType (token
, TOKEN_STATEMENT_END
));
1133 /* skip over paired tokens, managing nested pairs and stopping at statement end
1134 * or right after closing token, whatever comes first.
1136 static void skipOverPair (tokenInfo
*const token
, tokenType topen
, tokenType tclose
)
1140 if (isType (token
, TOKEN_STATEMENT_END
))
1142 else if (isType (token
, topen
))
1144 else if (isType (token
, tclose
))
1147 } while (level
> 0);
1150 static void skipOverParens (tokenInfo
*const token
)
1152 skipOverPair (token
, TOKEN_PAREN_OPEN
, TOKEN_PAREN_CLOSE
);
1155 static void skipOverSquares (tokenInfo
*const token
)
1157 skipOverPair (token
, TOKEN_SQUARE_OPEN
, TOKEN_SQUARE_CLOSE
);
1160 static boolean
isTypeSpec (tokenInfo
*const token
)
1163 switch (token
->keyword
)
1166 case KEYWORD_integer
:
1168 case KEYWORD_double
:
1169 case KEYWORD_complex
:
1170 case KEYWORD_character
:
1171 case KEYWORD_logical
:
1172 case KEYWORD_record
:
1174 case KEYWORD_procedure
:
1175 case KEYWORD_enumerator
:
1185 static boolean
isSubprogramPrefix (tokenInfo
*const token
)
1188 switch (token
->keyword
)
1190 case KEYWORD_elemental
:
1192 case KEYWORD_recursive
:
1193 case KEYWORD_stdcall
:
1203 static void parseKindSelector (tokenInfo
*const token
)
1205 if (isType (token
, TOKEN_PAREN_OPEN
))
1206 skipOverParens (token
); /* skip kind-selector */
1207 if (isType (token
, TOKEN_OPERATOR
) &&
1208 strcmp (vStringValue (token
->string
), "*") == 0)
1211 if (isType (token
, TOKEN_PAREN_OPEN
))
1212 skipOverParens (token
);
1219 * is INTEGER [kind-selector]
1220 * or REAL [kind-selector] is ( etc. )
1221 * or DOUBLE PRECISION
1222 * or COMPLEX [kind-selector]
1223 * or CHARACTER [kind-selector]
1224 * or LOGICAL [kind-selector]
1225 * or TYPE ( type-name )
1227 * Note that INTEGER and REAL may be followed by "*N" where "N" is an integer
1229 static void parseTypeSpec (tokenInfo
*const token
)
1231 /* parse type-spec, leaving `token' at first token following type-spec */
1232 Assert (isTypeSpec (token
));
1233 switch (token
->keyword
)
1235 case KEYWORD_character
:
1236 /* skip char-selector */
1238 if (isType (token
, TOKEN_OPERATOR
) &&
1239 strcmp (vStringValue (token
->string
), "*") == 0)
1241 if (isType (token
, TOKEN_PAREN_OPEN
))
1242 skipOverParens (token
);
1243 else if (isType (token
, TOKEN_NUMERIC
))
1249 case KEYWORD_complex
:
1250 case KEYWORD_integer
:
1251 case KEYWORD_logical
:
1253 case KEYWORD_procedure
:
1255 parseKindSelector (token
);
1258 case KEYWORD_double
:
1260 if (isKeyword (token
, KEYWORD_complex
) ||
1261 isKeyword (token
, KEYWORD_precision
))
1264 skipToToken (token
, TOKEN_STATEMENT_END
);
1267 case KEYWORD_record
:
1269 if (isType (token
, TOKEN_OPERATOR
) &&
1270 strcmp (vStringValue (token
->string
), "/") == 0)
1272 readToken (token
); /* skip to structure name */
1273 readToken (token
); /* skip to '/' */
1274 readToken (token
); /* skip to variable name */
1280 if (isType (token
, TOKEN_PAREN_OPEN
))
1281 skipOverParens (token
); /* skip type-name */
1283 parseDerivedTypeDef (token
);
1286 case KEYWORD_enumerator
:
1291 skipToToken (token
, TOKEN_STATEMENT_END
);
1296 static boolean
skipStatementIfKeyword (tokenInfo
*const token
, keywordId keyword
)
1298 boolean result
= FALSE
;
1299 if (isKeyword (token
, keyword
))
1302 skipToNextStatement (token
);
1307 /* parse a list of qualifying specifiers, leaving `token' at first token
1308 * following list. Examples of such specifiers are:
1309 * [[, attr-spec] ::]
1310 * [[, component-attr-spec-list] ::]
1314 * or access-spec (is PUBLIC or PRIVATE)
1316 * or DIMENSION ( array-spec )
1318 * or INTENT ( intent-spec )
1325 * component-attr-spec
1327 * or DIMENSION ( component-array-spec )
1328 * or EXTENDS ( type name )
1330 static void parseQualifierSpecList (tokenInfo
*const token
)
1334 readToken (token
); /* should be an attr-spec */
1335 switch (token
->keyword
)
1337 case KEYWORD_parameter
:
1338 case KEYWORD_allocatable
:
1339 case KEYWORD_external
:
1340 case KEYWORD_intrinsic
:
1343 case KEYWORD_optional
:
1344 case KEYWORD_private
:
1345 case KEYWORD_pointer
:
1346 case KEYWORD_public
:
1348 case KEYWORD_target
:
1352 case KEYWORD_codimension
:
1354 skipOverSquares (token
);
1357 case KEYWORD_dimension
:
1358 case KEYWORD_extends
:
1359 case KEYWORD_intent
:
1361 skipOverParens (token
);
1364 default: skipToToken (token
, TOKEN_STATEMENT_END
); break;
1366 } while (isType (token
, TOKEN_COMMA
));
1367 if (! isType (token
, TOKEN_DOUBLE_COLON
))
1368 skipToToken (token
, TOKEN_STATEMENT_END
);
1371 static tagType
variableTagType (void)
1373 tagType result
= TAG_VARIABLE
;
1374 if (ancestorCount () > 0)
1376 const tokenInfo
* const parent
= ancestorTop ();
1377 switch (parent
->tag
)
1379 case TAG_MODULE
: result
= TAG_VARIABLE
; break;
1380 case TAG_DERIVED_TYPE
: result
= TAG_COMPONENT
; break;
1381 case TAG_FUNCTION
: result
= TAG_LOCAL
; break;
1382 case TAG_SUBROUTINE
: result
= TAG_LOCAL
; break;
1383 case TAG_ENUM
: result
= TAG_ENUMERATOR
; break;
1384 default: result
= TAG_VARIABLE
; break;
1390 static void parseEntityDecl (tokenInfo
*const token
)
1392 Assert (isType (token
, TOKEN_IDENTIFIER
));
1393 makeFortranTag (token
, variableTagType ());
1395 /* we check for both '()' and '[]'
1396 * coarray syntax permits variable(), variable[], or variable()[]
1398 if (isType (token
, TOKEN_PAREN_OPEN
))
1399 skipOverParens (token
);
1400 if (isType (token
, TOKEN_SQUARE_OPEN
))
1401 skipOverSquares (token
);
1402 if (isType (token
, TOKEN_OPERATOR
) &&
1403 strcmp (vStringValue (token
->string
), "*") == 0)
1405 readToken (token
); /* read char-length */
1406 if (isType (token
, TOKEN_PAREN_OPEN
))
1407 skipOverParens (token
);
1411 if (isType (token
, TOKEN_OPERATOR
))
1413 if (strcmp (vStringValue (token
->string
), "/") == 0)
1414 { /* skip over initializations of structure field */
1416 skipPast (token
, TOKEN_OPERATOR
);
1418 else if (strcmp (vStringValue (token
->string
), "=") == 0 ||
1419 strcmp (vStringValue (token
->string
), "=>") == 0)
1421 while (! isType (token
, TOKEN_COMMA
) &&
1422 ! isType (token
, TOKEN_STATEMENT_END
))
1425 /* another coarray check, for () and [] */
1426 if (isType (token
, TOKEN_PAREN_OPEN
))
1427 skipOverParens (token
);
1428 if (isType (token
, TOKEN_SQUARE_OPEN
))
1429 skipOverSquares (token
);
1433 /* token left at either comma or statement end */
1436 static void parseEntityDeclList (tokenInfo
*const token
)
1438 if (isType (token
, TOKEN_PERCENT
))
1439 skipToNextStatement (token
);
1440 else while (isType (token
, TOKEN_IDENTIFIER
) ||
1441 (isType (token
, TOKEN_KEYWORD
) &&
1442 !isKeyword (token
, KEYWORD_function
) &&
1443 !isKeyword (token
, KEYWORD_subroutine
)))
1445 /* compilers accept keywoeds as identifiers */
1446 if (isType (token
, TOKEN_KEYWORD
))
1447 token
->type
= TOKEN_IDENTIFIER
;
1448 parseEntityDecl (token
);
1449 if (isType (token
, TOKEN_COMMA
))
1451 else if (isType (token
, TOKEN_STATEMENT_END
))
1453 skipToNextStatement (token
);
1459 /* type-declaration-stmt is
1460 * type-spec [[, attr-spec] ... ::] entity-decl-list
1462 static void parseTypeDeclarationStmt (tokenInfo
*const token
)
1464 Assert (isTypeSpec (token
));
1465 parseTypeSpec (token
);
1466 if (!isType (token
, TOKEN_STATEMENT_END
)) /* if not end of derived type... */
1468 if (isType (token
, TOKEN_COMMA
))
1469 parseQualifierSpecList (token
);
1470 if (isType (token
, TOKEN_DOUBLE_COLON
))
1472 parseEntityDeclList (token
);
1474 if (isType (token
, TOKEN_STATEMENT_END
))
1475 skipToNextStatement (token
);
1479 * NAMELIST /namelist-group-name/ namelist-group-object-list
1480 * [[,]/[namelist-group-name]/ namelist-block-object-list] ...
1482 * namelist-group-object is
1486 * COMMON [/[common-block-name]/] common-block-object-list
1487 * [[,]/[common-block-name]/ common-block-object-list] ...
1489 * common-block-object is
1490 * variable-name [ ( explicit-shape-spec-list ) ]
1492 static void parseCommonNamelistStmt (tokenInfo
*const token
, tagType type
)
1494 Assert (isKeyword (token
, KEYWORD_common
) ||
1495 isKeyword (token
, KEYWORD_namelist
));
1499 if (isType (token
, TOKEN_OPERATOR
) &&
1500 strcmp (vStringValue (token
->string
), "/") == 0)
1503 if (isType (token
, TOKEN_IDENTIFIER
))
1505 makeFortranTag (token
, type
);
1508 skipPast (token
, TOKEN_OPERATOR
);
1510 if (isType (token
, TOKEN_IDENTIFIER
))
1511 makeFortranTag (token
, TAG_LOCAL
);
1513 if (isType (token
, TOKEN_PAREN_OPEN
))
1514 skipOverParens (token
); /* skip explicit-shape-spec-list */
1515 if (isType (token
, TOKEN_COMMA
))
1517 } while (! isType (token
, TOKEN_STATEMENT_END
));
1518 skipToNextStatement (token
);
1521 static void parseFieldDefinition (tokenInfo
*const token
)
1523 if (isTypeSpec (token
))
1524 parseTypeDeclarationStmt (token
);
1525 else if (isKeyword (token
, KEYWORD_structure
))
1526 parseStructureStmt (token
);
1527 else if (isKeyword (token
, KEYWORD_union
))
1528 parseUnionStmt (token
);
1530 skipToNextStatement (token
);
1533 static void parseMap (tokenInfo
*const token
)
1535 Assert (isKeyword (token
, KEYWORD_map
));
1536 skipToNextStatement (token
);
1537 while (! isKeyword (token
, KEYWORD_end
))
1538 parseFieldDefinition (token
);
1539 readSubToken (token
);
1540 /* should be at KEYWORD_map token */
1541 skipToNextStatement (token
);
1546 * [field-definition] [field-definition] ...
1549 * [field-definition] [field-definition] ...
1552 * [field-definition]
1553 * [field-definition] ...
1558 * Typed data declarations (variables or arrays) in structure declarations
1559 * have the form of normal Fortran typed data declarations. Data items with
1560 * different types can be freely intermixed within a structure declaration.
1562 * Unnamed fields can be declared in a structure by specifying the pseudo
1563 * name %FILL in place of an actual field name. You can use this mechanism to
1564 * generate empty space in a record for purposes such as alignment.
1566 * All mapped field declarations that are made within a UNION declaration
1567 * share a common location within the containing structure. When initializing
1568 * the fields within a UNION, the final initialization value assigned
1569 * overlays any value previously assigned to a field definition that shares
1572 static void parseUnionStmt (tokenInfo
*const token
)
1574 Assert (isKeyword (token
, KEYWORD_union
));
1575 skipToNextStatement (token
);
1576 while (isKeyword (token
, KEYWORD_map
))
1578 /* should be at KEYWORD_end token */
1579 readSubToken (token
);
1580 /* secondary token should be KEYWORD_end token */
1581 skipToNextStatement (token
);
1584 /* STRUCTURE [/structure-name/] [field-names]
1585 * [field-definition]
1586 * [field-definition] ...
1590 * identifies the structure in a subsequent RECORD statement.
1591 * Substructures can be established within a structure by means of either
1592 * a nested STRUCTURE declaration or a RECORD statement.
1595 * (for substructure declarations only) one or more names having the
1596 * structure of the substructure being defined.
1599 * can be one or more of the following:
1601 * Typed data declarations, which can optionally include one or more
1602 * data initialization values.
1604 * Substructure declarations (defined by either RECORD statements or
1605 * subsequent STRUCTURE statements).
1607 * UNION declarations, which are mapped fields defined by a block of
1608 * statements. The syntax of a UNION declaration is described below.
1610 * PARAMETER statements, which do not affect the form of the
1613 static void parseStructureStmt (tokenInfo
*const token
)
1615 tokenInfo
*name
= NULL
;
1616 Assert (isKeyword (token
, KEYWORD_structure
));
1618 if (isType (token
, TOKEN_OPERATOR
) &&
1619 strcmp (vStringValue (token
->string
), "/") == 0)
1620 { /* read structure name */
1622 if (isType (token
, TOKEN_IDENTIFIER
) || isType (token
, TOKEN_KEYWORD
))
1624 name
= newTokenFrom (token
);
1625 name
->type
= TOKEN_IDENTIFIER
;
1627 skipPast (token
, TOKEN_OPERATOR
);
1630 { /* fake out anonymous structure */
1631 name
= newAnonTokenFrom (token
, "Structure");
1632 name
->type
= TOKEN_IDENTIFIER
;
1633 name
->tag
= TAG_DERIVED_TYPE
;
1635 makeFortranTag (name
, TAG_DERIVED_TYPE
);
1636 while (isType (token
, TOKEN_IDENTIFIER
))
1637 { /* read field names */
1638 makeFortranTag (token
, TAG_COMPONENT
);
1640 if (isType (token
, TOKEN_COMMA
))
1643 skipToNextStatement (token
);
1644 ancestorPush (name
);
1645 while (! isKeyword (token
, KEYWORD_end
))
1646 parseFieldDefinition (token
);
1647 readSubToken (token
);
1648 /* secondary token should be KEYWORD_structure token */
1649 skipToNextStatement (token
);
1654 /* specification-stmt
1655 * is access-stmt (is access-spec [[::] access-id-list)
1656 * or allocatable-stmt (is ALLOCATABLE [::] array-name etc.)
1657 * or common-stmt (is COMMON [ / [common-block-name] /] etc.)
1658 * or data-stmt (is DATA data-stmt-list [[,] data-stmt-set] ...)
1659 * or dimension-stmt (is DIMENSION [::] array-name etc.)
1660 * or equivalence-stmt (is EQUIVALENCE equivalence-set-list)
1661 * or external-stmt (is EXTERNAL etc.)
1662 * or intent-stmt (is INTENT ( intent-spec ) [::] etc.)
1663 * or instrinsic-stmt (is INTRINSIC etc.)
1664 * or namelist-stmt (is NAMELIST / namelist-group-name / etc.)
1665 * or optional-stmt (is OPTIONAL [::] etc.)
1666 * or pointer-stmt (is POINTER [::] object-name etc.)
1667 * or save-stmt (is SAVE etc.)
1668 * or target-stmt (is TARGET [::] object-name etc.)
1670 * access-spec is PUBLIC or PRIVATE
1672 static boolean
parseSpecificationStmt (tokenInfo
*const token
)
1674 boolean result
= TRUE
;
1675 switch (token
->keyword
)
1677 case KEYWORD_common
:
1678 parseCommonNamelistStmt (token
, TAG_COMMON_BLOCK
);
1681 case KEYWORD_namelist
:
1682 parseCommonNamelistStmt (token
, TAG_NAMELIST
);
1685 case KEYWORD_structure
:
1686 parseStructureStmt (token
);
1689 case KEYWORD_allocatable
:
1691 case KEYWORD_dimension
:
1692 case KEYWORD_equivalence
:
1693 case KEYWORD_extends
:
1694 case KEYWORD_external
:
1695 case KEYWORD_intent
:
1696 case KEYWORD_intrinsic
:
1697 case KEYWORD_optional
:
1698 case KEYWORD_pointer
:
1699 case KEYWORD_private
:
1700 case KEYWORD_public
:
1702 case KEYWORD_target
:
1703 skipToNextStatement (token
);
1713 /* component-def-stmt is
1714 * type-spec [[, component-attr-spec-list] ::] component-decl-list
1717 * component-name [ ( component-array-spec ) ] [ * char-length ]
1719 static void parseComponentDefStmt (tokenInfo
*const token
)
1721 Assert (isTypeSpec (token
));
1722 parseTypeSpec (token
);
1723 if (isType (token
, TOKEN_COMMA
))
1724 parseQualifierSpecList (token
);
1725 if (isType (token
, TOKEN_DOUBLE_COLON
))
1727 parseEntityDeclList (token
);
1730 /* derived-type-def is
1731 * derived-type-stmt is (TYPE [[, access-spec] ::] type-name
1732 * [private-sequence-stmt] ... (is PRIVATE or SEQUENCE)
1733 * component-def-stmt
1734 * [component-def-stmt] ...
1737 static void parseDerivedTypeDef (tokenInfo
*const token
)
1739 if (isType (token
, TOKEN_COMMA
))
1740 parseQualifierSpecList (token
);
1741 if (isType (token
, TOKEN_DOUBLE_COLON
))
1743 if (isType (token
, TOKEN_IDENTIFIER
) || isType (token
, TOKEN_KEYWORD
))
1745 token
->type
= TOKEN_IDENTIFIER
;
1746 makeFortranTag (token
, TAG_DERIVED_TYPE
);
1748 ancestorPush (token
);
1749 skipToNextStatement (token
);
1750 if (isKeyword (token
, KEYWORD_private
) ||
1751 isKeyword (token
, KEYWORD_sequence
))
1753 skipToNextStatement (token
);
1755 while (! isKeyword (token
, KEYWORD_end
))
1757 if (isTypeSpec (token
))
1758 parseComponentDefStmt (token
);
1760 skipToNextStatement (token
);
1762 readSubToken (token
);
1763 /* secondary token should be KEYWORD_type token */
1764 skipToToken (token
, TOKEN_STATEMENT_END
);
1769 * interface-stmt (is INTERFACE [generic-spec])
1771 * [module-procedure-stmt] ...
1772 * end-interface-stmt (is END INTERFACE)
1776 * or OPERATOR ( defined-operator )
1777 * or ASSIGNMENT ( = )
1781 * [specification-part]
1783 * or subroutine-stmt
1784 * [specification-part]
1785 * end-subroutine-stmt
1787 * module-procedure-stmt is
1788 * MODULE PROCEDURE procedure-name-list
1790 static void parseInterfaceBlock (tokenInfo
*const token
)
1792 tokenInfo
*name
= NULL
;
1793 Assert (isKeyword (token
, KEYWORD_interface
));
1795 if (isKeyword (token
, KEYWORD_assignment
) ||
1796 isKeyword (token
, KEYWORD_operator
))
1799 if (isType (token
, TOKEN_PAREN_OPEN
))
1801 if (isType (token
, TOKEN_OPERATOR
))
1802 name
= newTokenFrom (token
);
1804 else if (isType (token
, TOKEN_IDENTIFIER
) || isType (token
, TOKEN_KEYWORD
))
1806 name
= newTokenFrom (token
);
1807 name
->type
= TOKEN_IDENTIFIER
;
1811 name
= newAnonTokenFrom (token
, "Interface");
1812 name
->type
= TOKEN_IDENTIFIER
;
1813 name
->tag
= TAG_INTERFACE
;
1815 makeFortranTag (name
, TAG_INTERFACE
);
1816 ancestorPush (name
);
1817 while (! isKeyword (token
, KEYWORD_end
))
1819 switch (token
->keyword
)
1821 case KEYWORD_function
: parseFunctionSubprogram (token
); break;
1822 case KEYWORD_subroutine
: parseSubroutineSubprogram (token
); break;
1825 if (isSubprogramPrefix (token
))
1827 else if (isTypeSpec (token
))
1828 parseTypeSpec (token
);
1830 skipToNextStatement (token
);
1834 readSubToken (token
);
1835 /* secondary token should be KEYWORD_interface token */
1836 skipToNextStatement (token
);
1842 * enum-stmt (is ENUM, BIND(C) [ :: type-alias-name ]
1843 * or ENUM [ kind-selector ] [ :: ] [ type-alias-name ])
1844 * [ enum-body (is ENUMERATOR [ :: ] enumerator-list) ]
1845 * end-enum-stmt (is END ENUM)
1847 static void parseEnumBlock (tokenInfo
*const token
)
1849 tokenInfo
*name
= NULL
;
1850 Assert (isKeyword (token
, KEYWORD_enum
));
1852 if (isType (token
, TOKEN_COMMA
))
1855 if (isType (token
, TOKEN_KEYWORD
))
1857 if (isType (token
, TOKEN_PAREN_OPEN
))
1858 skipOverParens (token
);
1860 parseKindSelector (token
);
1861 if (isType (token
, TOKEN_DOUBLE_COLON
))
1863 if (isType (token
, TOKEN_IDENTIFIER
) || isType (token
, TOKEN_KEYWORD
))
1865 name
= newTokenFrom (token
);
1866 name
->type
= TOKEN_IDENTIFIER
;
1870 name
= newAnonTokenFrom (token
, "Enum");
1871 name
->type
= TOKEN_IDENTIFIER
;
1872 name
->tag
= TAG_ENUM
;
1874 makeFortranTag (name
, TAG_ENUM
);
1875 skipToNextStatement (token
);
1876 ancestorPush (name
);
1877 while (! isKeyword (token
, KEYWORD_end
))
1879 if (isTypeSpec (token
))
1880 parseTypeDeclarationStmt (token
);
1882 skipToNextStatement (token
);
1884 readSubToken (token
);
1885 /* secondary token should be KEYWORD_enum token */
1886 skipToNextStatement (token
);
1892 * ENTRY entry-name [ ( dummy-arg-list ) ]
1894 static void parseEntryStmt (tokenInfo
*const token
)
1896 Assert (isKeyword (token
, KEYWORD_entry
));
1898 if (isType (token
, TOKEN_IDENTIFIER
))
1899 makeFortranTag (token
, TAG_ENTRY_POINT
);
1900 skipToNextStatement (token
);
1903 /* stmt-function-stmt is
1904 * function-name ([dummy-arg-name-list]) = scalar-expr
1906 static boolean
parseStmtFunctionStmt (tokenInfo
*const token
)
1908 boolean result
= FALSE
;
1909 Assert (isType (token
, TOKEN_IDENTIFIER
));
1910 #if 0 /* cannot reliably parse this yet */
1911 makeFortranTag (token
, TAG_FUNCTION
);
1914 if (isType (token
, TOKEN_PAREN_OPEN
))
1916 skipOverParens (token
);
1917 result
= (boolean
) (isType (token
, TOKEN_OPERATOR
) &&
1918 strcmp (vStringValue (token
->string
), "=") == 0);
1920 skipToNextStatement (token
);
1924 static boolean
isIgnoredDeclaration (tokenInfo
*const token
)
1927 switch (token
->keyword
)
1929 case KEYWORD_cexternal
:
1930 case KEYWORD_cglobal
:
1931 case KEYWORD_dllexport
:
1932 case KEYWORD_dllimport
:
1933 case KEYWORD_external
:
1934 case KEYWORD_format
:
1935 case KEYWORD_include
:
1936 case KEYWORD_inline
:
1937 case KEYWORD_parameter
:
1938 case KEYWORD_pascal
:
1939 case KEYWORD_pexternal
:
1940 case KEYWORD_pglobal
:
1941 case KEYWORD_static
:
1943 case KEYWORD_virtual
:
1944 case KEYWORD_volatile
:
1955 /* declaration-construct
1956 * [derived-type-def]
1958 * [type-declaration-stmt]
1959 * [specification-stmt]
1960 * [parameter-stmt] (is PARAMETER ( named-constant-def-list )
1961 * [format-stmt] (is FORMAT format-specification)
1963 * [stmt-function-stmt]
1965 static boolean
parseDeclarationConstruct (tokenInfo
*const token
)
1967 boolean result
= TRUE
;
1968 switch (token
->keyword
)
1970 case KEYWORD_entry
: parseEntryStmt (token
); break;
1971 case KEYWORD_interface
: parseInterfaceBlock (token
); break;
1972 case KEYWORD_enum
: parseEnumBlock (token
); break;
1973 case KEYWORD_stdcall
: readToken (token
); break;
1974 /* derived type handled by parseTypeDeclarationStmt(); */
1976 case KEYWORD_automatic
:
1978 if (isTypeSpec (token
))
1979 parseTypeDeclarationStmt (token
);
1981 skipToNextStatement (token
);
1986 if (isIgnoredDeclaration (token
))
1987 skipToNextStatement (token
);
1988 else if (isTypeSpec (token
))
1990 parseTypeDeclarationStmt (token
);
1993 else if (isType (token
, TOKEN_IDENTIFIER
))
1994 result
= parseStmtFunctionStmt (token
);
1996 result
= parseSpecificationStmt (token
);
2002 /* implicit-part-stmt
2003 * is [implicit-stmt] (is IMPLICIT etc.)
2004 * or [parameter-stmt] (is PARAMETER etc.)
2005 * or [format-stmt] (is FORMAT etc.)
2006 * or [entry-stmt] (is ENTRY entry-name etc.)
2008 static boolean
parseImplicitPartStmt (tokenInfo
*const token
)
2010 boolean result
= TRUE
;
2011 switch (token
->keyword
)
2013 case KEYWORD_entry
: parseEntryStmt (token
); break;
2015 case KEYWORD_implicit
:
2016 case KEYWORD_include
:
2017 case KEYWORD_parameter
:
2018 case KEYWORD_format
:
2019 skipToNextStatement (token
);
2022 default: result
= FALSE
; break;
2027 /* specification-part is
2028 * [use-stmt] ... (is USE module-name etc.)
2029 * [implicit-part] (is [implicit-part-stmt] ... [implicit-stmt])
2030 * [declaration-construct] ...
2032 static boolean
parseSpecificationPart (tokenInfo
*const token
)
2034 boolean result
= FALSE
;
2035 while (skipStatementIfKeyword (token
, KEYWORD_use
))
2037 while (parseImplicitPartStmt (token
))
2039 while (parseDeclarationConstruct (token
))
2045 * block-data-stmt (is BLOCK DATA [block-data-name]
2046 * [specification-part]
2047 * end-block-data-stmt (is END [BLOCK DATA [block-data-name]])
2049 static void parseBlockData (tokenInfo
*const token
)
2051 Assert (isKeyword (token
, KEYWORD_block
));
2053 if (isKeyword (token
, KEYWORD_data
))
2056 if (isType (token
, TOKEN_IDENTIFIER
))
2057 makeFortranTag (token
, TAG_BLOCK_DATA
);
2059 ancestorPush (token
);
2060 skipToNextStatement (token
);
2061 parseSpecificationPart (token
);
2062 while (! isKeyword (token
, KEYWORD_end
))
2063 skipToNextStatement (token
);
2064 readSubToken (token
);
2065 /* secondary token should be KEYWORD_NONE or KEYWORD_block token */
2066 skipToNextStatement (token
);
2070 /* internal-subprogram-part is
2071 * contains-stmt (is CONTAINS)
2072 * internal-subprogram
2073 * [internal-subprogram] ...
2075 * internal-subprogram
2076 * is function-subprogram
2077 * or subroutine-subprogram
2079 static void parseInternalSubprogramPart (tokenInfo
*const token
)
2081 boolean done
= FALSE
;
2082 if (isKeyword (token
, KEYWORD_contains
))
2083 skipToNextStatement (token
);
2086 switch (token
->keyword
)
2088 case KEYWORD_function
: parseFunctionSubprogram (token
); break;
2089 case KEYWORD_subroutine
: parseSubroutineSubprogram (token
); break;
2090 case KEYWORD_end
: done
= TRUE
; break;
2093 if (isSubprogramPrefix (token
))
2095 else if (isTypeSpec (token
))
2096 parseTypeSpec (token
);
2105 * module-stmt (is MODULE module-name)
2106 * [specification-part]
2107 * [module-subprogram-part]
2108 * end-module-stmt (is END [MODULE [module-name]])
2110 * module-subprogram-part
2111 * contains-stmt (is CONTAINS)
2113 * [module-subprogram] ...
2116 * is function-subprogram
2117 * or subroutine-subprogram
2119 static void parseModule (tokenInfo
*const token
)
2121 Assert (isKeyword (token
, KEYWORD_module
));
2123 if (isType (token
, TOKEN_IDENTIFIER
) || isType (token
, TOKEN_KEYWORD
))
2125 token
->type
= TOKEN_IDENTIFIER
;
2126 makeFortranTag (token
, TAG_MODULE
);
2128 ancestorPush (token
);
2129 skipToNextStatement (token
);
2130 parseSpecificationPart (token
);
2131 if (isKeyword (token
, KEYWORD_contains
))
2132 parseInternalSubprogramPart (token
);
2133 while (! isKeyword (token
, KEYWORD_end
))
2134 skipToNextStatement (token
);
2135 readSubToken (token
);
2136 /* secondary token should be KEYWORD_NONE or KEYWORD_module token */
2137 skipToNextStatement (token
);
2142 * executable-construct
2144 * executable-contstruct is
2145 * execution-part-construct [execution-part-construct]
2147 * execution-part-construct
2148 * is executable-construct
2153 static boolean
parseExecutionPart (tokenInfo
*const token
)
2155 boolean result
= FALSE
;
2156 boolean done
= FALSE
;
2159 switch (token
->keyword
)
2162 if (isSubprogramPrefix (token
))
2165 skipToNextStatement (token
);
2170 parseEntryStmt (token
);
2174 case KEYWORD_contains
:
2175 case KEYWORD_function
:
2176 case KEYWORD_subroutine
:
2181 readSubToken (token
);
2182 if (isSecondaryKeyword (token
, KEYWORD_do
) ||
2183 isSecondaryKeyword (token
, KEYWORD_enum
) ||
2184 isSecondaryKeyword (token
, KEYWORD_if
) ||
2185 isSecondaryKeyword (token
, KEYWORD_select
) ||
2186 isSecondaryKeyword (token
, KEYWORD_where
) ||
2187 isSecondaryKeyword (token
, KEYWORD_forall
) ||
2188 isSecondaryKeyword (token
, KEYWORD_associate
))
2190 skipToNextStatement (token
);
2201 static void parseSubprogram (tokenInfo
*const token
, const tagType tag
)
2203 Assert (isKeyword (token
, KEYWORD_program
) ||
2204 isKeyword (token
, KEYWORD_function
) ||
2205 isKeyword (token
, KEYWORD_subroutine
));
2207 if (isType (token
, TOKEN_IDENTIFIER
) || isType (token
, TOKEN_KEYWORD
))
2209 token
->type
= TOKEN_IDENTIFIER
;
2210 makeFortranTag (token
, tag
);
2212 ancestorPush (token
);
2213 skipToNextStatement (token
);
2214 parseSpecificationPart (token
);
2215 parseExecutionPart (token
);
2216 if (isKeyword (token
, KEYWORD_contains
))
2217 parseInternalSubprogramPart (token
);
2218 /* should be at KEYWORD_end token */
2219 readSubToken (token
);
2220 /* secondary token should be one of KEYWORD_NONE, KEYWORD_program,
2221 * KEYWORD_function, KEYWORD_function
2223 skipToNextStatement (token
);
2228 /* function-subprogram is
2229 * function-stmt (is [prefix] FUNCTION function-name etc.)
2230 * [specification-part]
2232 * [internal-subprogram-part]
2233 * end-function-stmt (is END [FUNCTION [function-name]])
2236 * is type-spec [RECURSIVE]
2237 * or [RECURSIVE] type-spec
2239 static void parseFunctionSubprogram (tokenInfo
*const token
)
2241 parseSubprogram (token
, TAG_FUNCTION
);
2244 /* subroutine-subprogram is
2245 * subroutine-stmt (is [RECURSIVE] SUBROUTINE subroutine-name etc.)
2246 * [specification-part]
2248 * [internal-subprogram-part]
2249 * end-subroutine-stmt (is END [SUBROUTINE [function-name]])
2251 static void parseSubroutineSubprogram (tokenInfo
*const token
)
2253 parseSubprogram (token
, TAG_SUBROUTINE
);
2257 * [program-stmt] (is PROGRAM program-name)
2258 * [specification-part]
2260 * [internal-subprogram-part ]
2263 static void parseMainProgram (tokenInfo
*const token
)
2265 parseSubprogram (token
, TAG_PROGRAM
);
2270 * or external-subprogram (is function-subprogram or subroutine-subprogram)
2274 static void parseProgramUnit (tokenInfo
*const token
)
2279 if (isType (token
, TOKEN_STATEMENT_END
))
2281 else switch (token
->keyword
)
2283 case KEYWORD_block
: parseBlockData (token
); break;
2284 case KEYWORD_end
: skipToNextStatement (token
); break;
2285 case KEYWORD_function
: parseFunctionSubprogram (token
); break;
2286 case KEYWORD_module
: parseModule (token
); break;
2287 case KEYWORD_program
: parseMainProgram (token
); break;
2288 case KEYWORD_subroutine
: parseSubroutineSubprogram (token
); break;
2291 if (isSubprogramPrefix (token
))
2295 boolean one
= parseSpecificationPart (token
);
2296 boolean two
= parseExecutionPart (token
);
2305 static boolean
findFortranTags (const unsigned int passCount
)
2308 exception_t exception
;
2311 Assert (passCount
< 3);
2312 Parent
= newToken ();
2313 token
= newToken ();
2314 FreeSourceForm
= (boolean
) (passCount
> 1);
2315 contextual_fake_count
= 0;
2318 exception
= (exception_t
) setjmp (Exception
);
2319 if (exception
== ExceptionEOF
)
2321 else if (exception
== ExceptionFixedFormat
&& ! FreeSourceForm
)
2323 verbose ("%s: not fixed source form; retry as free source form\n",
2324 getInputFileName ());
2329 parseProgramUnit (token
);
2333 deleteToken (token
);
2334 deleteToken (Parent
);
2339 static void initializeFortran (const langType language
)
2341 Lang_fortran
= language
;
2342 buildFortranKeywordHash (language
);
2345 static void initializeF77 (const langType language
)
2347 Lang_f77
= language
;
2348 buildFortranKeywordHash (language
);
2351 extern parserDefinition
* FortranParser (void)
2353 static const char *const extensions
[] = {
2354 "f90", "f95", "f03",
2355 #ifndef CASE_INSENSITIVE_FILENAMES
2356 "F90", "F95", "F03",
2360 parserDefinition
* def
= parserNew ("Fortran");
2361 def
->kinds
= FortranKinds
;
2362 def
->kindCount
= KIND_COUNT (FortranKinds
);
2363 def
->extensions
= extensions
;
2364 def
->parser2
= findFortranTags
;
2365 def
->initialize
= initializeFortran
;
2369 extern parserDefinition
* F77Parser (void)
2371 static const char *const extensions
[] = {
2372 "f", "for", "ftn", "f77",
2373 #ifndef CASE_INSENSITIVE_FILENAMES
2374 "F", "FOR", "FTN", "F77",
2378 parserDefinition
* def
= parserNew ("F77");
2379 def
->kinds
= FortranKinds
;
2380 def
->kindCount
= KIND_COUNT (FortranKinds
);
2381 def
->extensions
= extensions
;
2382 def
->parser2
= findFortranTags
;
2383 def
->initialize
= initializeF77
;
2386 /* vi:set tabstop=4 shiftwidth=4: */