2 * $Id: fortran.c 660 2008-04-20 23:30:12Z elliotth $
4 * Copyright (c) 1998-2003, Darren Hiebert
6 * This source code is released for free distribution under the terms of the
7 * GNU General Public License.
9 * This module contains functions for generating tags for Fortran language
16 #include "general.h" /* must always come first */
20 #include <ctype.h> /* to define tolower () */
35 #define isident(c) (isalnum(c) || (c) == '_')
36 #define isBlank(c) (boolean) (c == ' ' || c == '\t')
37 #define isType(token,t) (boolean) ((token)->type == (t))
38 #define isKeyword(token,k) (boolean) ((token)->keyword == (k))
39 #define isSecondaryKeyword(token,k) (boolean) ((token)->secondary == NULL ? \
40 FALSE : (token)->secondary->keyword == (k))
46 typedef enum eException
{
47 ExceptionNone
, ExceptionEOF
, ExceptionFixedFormat
, ExceptionLoop
50 /* Used to designate type of line read in fixed source form.
52 typedef enum eFortranLineType
{
62 /* Used to specify type of keyword.
64 typedef enum eKeywordId
{
136 /* Used to determine whether keyword is valid for the token language and
139 typedef struct sKeywordDesc
{
144 typedef enum eTokenType
{
160 typedef enum eTagType
{
176 TAG_COUNT
/* must be last */
179 typedef struct sTokenInfo
{
184 struct sTokenInfo
*secondary
;
185 unsigned long lineNumber
;
193 static langType Lang_fortran
;
194 static jmp_buf Exception
;
196 static unsigned int Column
;
197 static boolean FreeSourceForm
;
198 static boolean ParsingString
;
199 static tokenInfo
*Parent
;
201 /* indexed by tagType */
202 static kindOption FortranKinds
[] = {
203 { TRUE
, 'b', "block data", "block data"},
204 { TRUE
, 'c', "common", "common blocks"},
205 { TRUE
, 'e', "entry", "entry points"},
206 { TRUE
, 'f', "function", "functions"},
207 { FALSE
, 'i', "interface", "interface contents, generic names, and operators"},
208 { TRUE
, 'k', "component", "type and structure components"},
209 { TRUE
, 'l', "label", "labels"},
210 { FALSE
, 'L', "local", "local, common block, and namelist variables"},
211 { TRUE
, 'm', "module", "modules"},
212 { TRUE
, 'n', "namelist", "namelists"},
213 { TRUE
, 'p', "program", "programs"},
214 { TRUE
, 's', "subroutine", "subroutines"},
215 { TRUE
, 't', "type", "derived types and structures"},
216 { TRUE
, 'v', "variable", "program (global) and module variables"}
219 /* For efinitions of Fortran 77 with extensions:
220 * http://www.fortran.com/fortran/F77_std/rjcnf0001.html
221 * http://scienide.uwaterloo.ca/MIPSpro7/007-2362-004/sgi_html/index.html
223 * For the Compaq Fortran Reference Manual:
224 * http://h18009.www1.hp.com/fortran/docs/lrm/dflrm.htm
227 static const keywordDesc FortranKeywordTable
[] = {
228 /* keyword keyword ID */
229 { "allocatable", KEYWORD_allocatable
},
230 { "assignment", KEYWORD_assignment
},
231 { "automatic", KEYWORD_automatic
},
232 { "block", KEYWORD_block
},
233 { "byte", KEYWORD_byte
},
234 { "cexternal", KEYWORD_cexternal
},
235 { "cglobal", KEYWORD_cglobal
},
236 { "character", KEYWORD_character
},
237 { "common", KEYWORD_common
},
238 { "complex", KEYWORD_complex
},
239 { "contains", KEYWORD_contains
},
240 { "data", KEYWORD_data
},
241 { "dimension", KEYWORD_dimension
},
242 { "dll_export", KEYWORD_dllexport
},
243 { "dll_import", KEYWORD_dllimport
},
244 { "do", KEYWORD_do
},
245 { "double", KEYWORD_double
},
246 { "elemental", KEYWORD_elemental
},
247 { "end", KEYWORD_end
},
248 { "entry", KEYWORD_entry
},
249 { "equivalence", KEYWORD_equivalence
},
250 { "external", KEYWORD_external
},
251 { "format", KEYWORD_format
},
252 { "function", KEYWORD_function
},
253 { "if", KEYWORD_if
},
254 { "implicit", KEYWORD_implicit
},
255 { "include", KEYWORD_include
},
256 { "inline", KEYWORD_inline
},
257 { "integer", KEYWORD_integer
},
258 { "intent", KEYWORD_intent
},
259 { "interface", KEYWORD_interface
},
260 { "intrinsic", KEYWORD_intrinsic
},
261 { "logical", KEYWORD_logical
},
262 { "map", KEYWORD_map
},
263 { "module", KEYWORD_module
},
264 { "namelist", KEYWORD_namelist
},
265 { "operator", KEYWORD_operator
},
266 { "optional", KEYWORD_optional
},
267 { "parameter", KEYWORD_parameter
},
268 { "pascal", KEYWORD_pascal
},
269 { "pexternal", KEYWORD_pexternal
},
270 { "pglobal", KEYWORD_pglobal
},
271 { "pointer", KEYWORD_pointer
},
272 { "precision", KEYWORD_precision
},
273 { "private", KEYWORD_private
},
274 { "program", KEYWORD_program
},
275 { "public", KEYWORD_public
},
276 { "pure", KEYWORD_pure
},
277 { "real", KEYWORD_real
},
278 { "record", KEYWORD_record
},
279 { "recursive", KEYWORD_recursive
},
280 { "save", KEYWORD_save
},
281 { "select", KEYWORD_select
},
282 { "sequence", KEYWORD_sequence
},
283 { "static", KEYWORD_static
},
284 { "stdcall", KEYWORD_stdcall
},
285 { "structure", KEYWORD_structure
},
286 { "subroutine", KEYWORD_subroutine
},
287 { "target", KEYWORD_target
},
288 { "then", KEYWORD_then
},
289 { "type", KEYWORD_type
},
290 { "union", KEYWORD_union
},
291 { "use", KEYWORD_use
},
292 { "value", KEYWORD_value
},
293 { "virtual", KEYWORD_virtual
},
294 { "volatile", KEYWORD_volatile
},
295 { "where", KEYWORD_where
},
296 { "while", KEYWORD_while
}
303 } Ancestors
= { 0, 0, NULL
};
306 * FUNCTION PROTOTYPES
308 static void parseStructureStmt (tokenInfo
*const token
);
309 static void parseUnionStmt (tokenInfo
*const token
);
310 static void parseDerivedTypeDef (tokenInfo
*const token
);
311 static void parseFunctionSubprogram (tokenInfo
*const token
);
312 static void parseSubroutineSubprogram (tokenInfo
*const token
);
315 * FUNCTION DEFINITIONS
318 static void ancestorPush (tokenInfo
*const token
)
320 enum { incrementalIncrease
= 10 };
321 if (Ancestors
.list
== NULL
)
323 Assert (Ancestors
.max
== 0);
325 Ancestors
.max
= incrementalIncrease
;
326 Ancestors
.list
= xMalloc (Ancestors
.max
, tokenInfo
);
328 else if (Ancestors
.count
== Ancestors
.max
)
330 Ancestors
.max
+= incrementalIncrease
;
331 Ancestors
.list
= xRealloc (Ancestors
.list
, Ancestors
.max
, tokenInfo
);
333 Ancestors
.list
[Ancestors
.count
] = *token
;
334 Ancestors
.list
[Ancestors
.count
].string
= vStringNewCopy (token
->string
);
338 static void ancestorPop (void)
340 Assert (Ancestors
.count
> 0);
342 vStringDelete (Ancestors
.list
[Ancestors
.count
].string
);
344 Ancestors
.list
[Ancestors
.count
].type
= TOKEN_UNDEFINED
;
345 Ancestors
.list
[Ancestors
.count
].keyword
= KEYWORD_NONE
;
346 Ancestors
.list
[Ancestors
.count
].secondary
= NULL
;
347 Ancestors
.list
[Ancestors
.count
].tag
= TAG_UNDEFINED
;
348 Ancestors
.list
[Ancestors
.count
].string
= NULL
;
349 Ancestors
.list
[Ancestors
.count
].lineNumber
= 0L;
352 static const tokenInfo
* ancestorScope (void)
354 tokenInfo
*result
= NULL
;
356 for (i
= Ancestors
.count
; i
> 0 && result
== NULL
; --i
)
358 tokenInfo
*const token
= Ancestors
.list
+ i
- 1;
359 if (token
->type
== TOKEN_IDENTIFIER
&&
360 token
->tag
!= TAG_UNDEFINED
&& token
->tag
!= TAG_INTERFACE
)
366 static const tokenInfo
* ancestorTop (void)
368 Assert (Ancestors
.count
> 0);
369 return &Ancestors
.list
[Ancestors
.count
- 1];
372 #define ancestorCount() (Ancestors.count)
374 static void ancestorClear (void)
376 while (Ancestors
.count
> 0)
378 if (Ancestors
.list
!= NULL
)
379 eFree (Ancestors
.list
);
380 Ancestors
.list
= NULL
;
385 static boolean
insideInterface (void)
387 boolean result
= FALSE
;
389 for (i
= 0 ; i
< Ancestors
.count
&& !result
; ++i
)
391 if (Ancestors
.list
[i
].tag
== TAG_INTERFACE
)
397 static void buildFortranKeywordHash (void)
400 sizeof (FortranKeywordTable
) / sizeof (FortranKeywordTable
[0]);
402 for (i
= 0 ; i
< count
; ++i
)
404 const keywordDesc
* const p
= &FortranKeywordTable
[i
];
405 addKeyword (p
->name
, Lang_fortran
, (int) p
->id
);
410 * Tag generation functions
413 static tokenInfo
*newToken (void)
415 tokenInfo
*const token
= xMalloc (1, tokenInfo
);
417 token
->type
= TOKEN_UNDEFINED
;
418 token
->keyword
= KEYWORD_NONE
;
419 token
->tag
= TAG_UNDEFINED
;
420 token
->string
= vStringNew ();
421 token
->secondary
= NULL
;
422 token
->lineNumber
= getSourceLineNumber ();
423 token
->filePosition
= getInputFilePosition ();
428 static tokenInfo
*newTokenFrom (tokenInfo
*const token
)
430 tokenInfo
*result
= newToken ();
432 result
->string
= vStringNewCopy (token
->string
);
433 token
->secondary
= NULL
;
437 static void deleteToken (tokenInfo
*const token
)
441 vStringDelete (token
->string
);
442 deleteToken (token
->secondary
);
443 token
->secondary
= NULL
;
448 static boolean
isFileScope (const tagType type
)
450 return (boolean
) (type
== TAG_LABEL
|| type
== TAG_LOCAL
);
453 static boolean
includeTag (const tagType type
)
456 Assert (type
!= TAG_UNDEFINED
);
457 include
= FortranKinds
[(int) type
].enabled
;
458 if (include
&& isFileScope (type
))
459 include
= Option
.include
.fileScope
;
463 static void makeFortranTag (tokenInfo
*const token
, tagType tag
)
466 if (includeTag (token
->tag
))
468 const char *const name
= vStringValue (token
->string
);
471 initTagEntry (&e
, name
);
473 if (token
->tag
== TAG_COMMON_BLOCK
)
474 e
.lineNumberEntry
= (boolean
) (Option
.locate
!= EX_PATTERN
);
476 e
.lineNumber
= token
->lineNumber
;
477 e
.filePosition
= token
->filePosition
;
478 e
.isFileScope
= isFileScope (token
->tag
);
479 e
.kindName
= FortranKinds
[token
->tag
].name
;
480 e
.kind
= FortranKinds
[token
->tag
].letter
;
481 e
.truncateLine
= (boolean
) (token
->tag
!= TAG_LABEL
);
483 if (ancestorCount () > 0)
485 const tokenInfo
* const scope
= ancestorScope ();
488 e
.extensionFields
.scope
[0] = FortranKinds
[scope
->tag
].name
;
489 e
.extensionFields
.scope
[1] = vStringValue (scope
->string
);
492 if (! insideInterface () || includeTag (TAG_INTERFACE
))
501 static int skipLine (void)
507 while (c
!= EOF
&& c
!= '\n');
512 static void makeLabelTag (vString
*const label
)
514 tokenInfo
*token
= newToken ();
515 token
->type
= TOKEN_LABEL
;
516 vStringCopy (token
->string
, label
);
517 makeFortranTag (token
, TAG_LABEL
);
521 static lineType
getLineType (void)
523 vString
*label
= vStringNew ();
525 lineType type
= LTYPE_UNDETERMINED
;
527 do /* read in first 6 "margin" characters */
531 /* 3.2.1 Comment_Line. A comment line is any line that contains
532 * a C or an asterisk in column 1, or contains only blank characters
533 * in columns 1 through 72. A comment line that contains a C or
534 * an asterisk in column 1 may contain any character capable of
535 * representation in the processor in columns 2 through 72.
537 /* EXCEPTION! Some compilers permit '!' as a commment character here.
539 * Treat # and $ in column 1 as comment to permit preprocessor directives.
540 * Treat D and d in column 1 as comment for HP debug statements.
542 if (column
== 0 && strchr ("*Cc!#$Dd", c
) != NULL
)
543 type
= LTYPE_COMMENT
;
544 else if (c
== '\t') /* EXCEPTION! Some compilers permit a tab here */
547 type
= LTYPE_INITIAL
;
549 else if (column
== 5)
551 /* 3.2.2 Initial_Line. An initial line is any line that is not
552 * a comment line and contains the character blank or the digit 0
553 * in column 6. Columns 1 through 5 may contain a statement label
554 * (3.4), or each of the columns 1 through 5 must contain the
557 if (c
== ' ' || c
== '0')
558 type
= LTYPE_INITIAL
;
560 /* 3.2.3 Continuation_Line. A continuation line is any line that
561 * contains any character of the FORTRAN character set other than
562 * the character blank or the digit 0 in column 6 and contains
563 * only blank characters in columns 1 through 5.
565 else if (vStringLength (label
) == 0)
566 type
= LTYPE_CONTINUATION
;
568 type
= LTYPE_INVALID
;
576 else if (isdigit (c
))
577 vStringPut (label
, c
);
579 type
= LTYPE_INVALID
;
582 } while (column
< 6 && type
== LTYPE_UNDETERMINED
);
584 Assert (type
!= LTYPE_UNDETERMINED
);
586 if (vStringLength (label
) > 0)
588 vStringTerminate (label
);
589 makeLabelTag (label
);
591 vStringDelete (label
);
595 static int getFixedFormChar (void)
597 boolean newline
= FALSE
;
603 #ifdef STRICT_FIXED_FORM
604 /* EXCEPTION! Some compilers permit more than 72 characters per line.
616 newline
= TRUE
; /* need to check for continuation line */
619 else if (c
== '!' && ! ParsingString
)
622 newline
= TRUE
; /* need to check for continuation line */
625 else if (c
== '&') /* check for free source form */
627 const int c2
= fileGetc ();
629 longjmp (Exception
, (int) ExceptionFixedFormat
);
636 type
= getLineType ();
639 case LTYPE_UNDETERMINED
:
641 longjmp (Exception
, (int) ExceptionFixedFormat
);
644 case LTYPE_SHORT
: break;
645 case LTYPE_COMMENT
: skipLine (); break;
662 /* fall through to next case */
663 case LTYPE_CONTINUATION
:
669 } while (isBlank (c
));
680 Assert ("Unexpected line type" == NULL
);
686 static int skipToNextLine (void)
694 static int getFreeFormChar (void)
696 static boolean newline
= TRUE
;
697 boolean advanceLine
= FALSE
;
700 /* If the last nonblank, non-comment character of a FORTRAN 90
701 * free-format text line is an ampersand then the next non-comment
702 * line is a continuation line.
708 while (isspace (c
) && c
!= '\n');
722 else if (newline
&& (c
== '!' || c
== '#'))
728 if (c
== '!' || (newline
&& c
== '#'))
730 c
= skipToNextLine ();
739 newline
= (boolean
) (c
== '\n');
743 static int getChar (void)
752 else if (FreeSourceForm
)
753 c
= getFreeFormChar ();
755 c
= getFixedFormChar ();
759 static void ungetChar (const int c
)
764 /* If a numeric is passed in 'c', this is used as the first digit of the
765 * numeric being parsed.
767 static vString
*parseInteger (int c
)
769 vString
*string
= vStringNew ();
773 vStringPut (string
, c
);
776 else if (! isdigit (c
))
778 while (c
!= EOF
&& isdigit (c
))
780 vStringPut (string
, c
);
783 vStringTerminate (string
);
789 while (c
!= EOF
&& isalpha (c
));
796 static vString
*parseNumeric (int c
)
798 vString
*string
= vStringNew ();
799 vString
*integer
= parseInteger (c
);
800 vStringCopy (string
, integer
);
801 vStringDelete (integer
);
806 integer
= parseInteger ('\0');
807 vStringPut (string
, c
);
808 vStringCat (string
, integer
);
809 vStringDelete (integer
);
812 if (tolower (c
) == 'e')
814 integer
= parseInteger ('\0');
815 vStringPut (string
, c
);
816 vStringCat (string
, integer
);
817 vStringDelete (integer
);
822 vStringTerminate (string
);
827 static void parseString (vString
*const string
, const int delimiter
)
829 const unsigned long inputLineNumber
= getInputLineNumber ();
831 ParsingString
= TRUE
;
833 while (c
!= delimiter
&& c
!= '\n' && c
!= EOF
)
835 vStringPut (string
, c
);
838 if (c
== '\n' || c
== EOF
)
840 verbose ("%s: unterminated character string at line %lu\n",
841 getInputFileName (), inputLineNumber
);
843 longjmp (Exception
, (int) ExceptionEOF
);
844 else if (! FreeSourceForm
)
845 longjmp (Exception
, (int) ExceptionFixedFormat
);
847 vStringTerminate (string
);
848 ParsingString
= FALSE
;
851 /* Read a C identifier beginning with "firstChar" and places it into "name".
853 static void parseIdentifier (vString
*const string
, const int firstChar
)
859 vStringPut (string
, c
);
861 } while (isident (c
));
863 vStringTerminate (string
);
864 ungetChar (c
); /* unget non-identifier character */
867 static void checkForLabel (void)
869 tokenInfo
* token
= NULL
;
877 for (length
= 0 ; isdigit (c
) && length
< 5 ; ++length
)
882 token
->type
= TOKEN_LABEL
;
884 vStringPut (token
->string
, c
);
887 if (length
> 0 && token
!= NULL
)
889 vStringTerminate (token
->string
);
890 makeFortranTag (token
, TAG_LABEL
);
896 static void readIdentifier (tokenInfo
*const token
, const int c
)
898 parseIdentifier (token
->string
, c
);
899 token
->keyword
= analyzeToken (token
->string
, Lang_fortran
);
900 if (! isKeyword (token
, KEYWORD_NONE
))
901 token
->type
= TOKEN_KEYWORD
;
904 token
->type
= TOKEN_IDENTIFIER
;
905 if (strncmp (vStringValue (token
->string
), "end", 3) == 0)
907 vString
*const sub
= vStringNewInit (vStringValue (token
->string
) + 3);
908 const keywordId kw
= analyzeToken (sub
, Lang_fortran
);
910 if (kw
!= KEYWORD_NONE
)
912 token
->secondary
= newToken ();
913 token
->secondary
->type
= TOKEN_KEYWORD
;
914 token
->secondary
->keyword
= kw
;
915 token
->keyword
= KEYWORD_end
;
921 static void readToken (tokenInfo
*const token
)
925 deleteToken (token
->secondary
);
926 token
->type
= TOKEN_UNDEFINED
;
927 token
->tag
= TAG_UNDEFINED
;
928 token
->keyword
= KEYWORD_NONE
;
929 token
->secondary
= NULL
;
930 vStringClear (token
->string
);
935 token
->lineNumber
= getSourceLineNumber ();
936 token
->filePosition
= getInputFilePosition ();
940 case EOF
: longjmp (Exception
, (int) ExceptionEOF
); break;
941 case ' ': goto getNextChar
;
942 case '\t': goto getNextChar
;
943 case ',': token
->type
= TOKEN_COMMA
; break;
944 case '(': token
->type
= TOKEN_PAREN_OPEN
; break;
945 case ')': token
->type
= TOKEN_PAREN_CLOSE
; break;
946 case '%': token
->type
= TOKEN_PERCENT
; break;
956 const char *const operatorChars
= "*/+=<>";
958 vStringPut (token
->string
, c
);
960 } while (strchr (operatorChars
, c
) != NULL
);
962 vStringTerminate (token
->string
);
963 token
->type
= TOKEN_OPERATOR
;
972 while (c
!= '\n' && c
!= EOF
);
979 /* fall through to newline case */
981 token
->type
= TOKEN_STATEMENT_END
;
987 parseIdentifier (token
->string
, c
);
991 vStringPut (token
->string
, c
);
992 vStringTerminate (token
->string
);
993 token
->type
= TOKEN_OPERATOR
;
998 token
->type
= TOKEN_UNDEFINED
;
1004 parseString (token
->string
, c
);
1005 token
->type
= TOKEN_STRING
;
1009 token
->type
= TOKEN_STATEMENT_END
;
1015 token
->type
= TOKEN_DOUBLE_COLON
;
1019 token
->type
= TOKEN_UNDEFINED
;
1025 readIdentifier (token
, c
);
1026 else if (isdigit (c
))
1028 vString
*numeric
= parseNumeric (c
);
1029 vStringCat (token
->string
, numeric
);
1030 vStringDelete (numeric
);
1031 token
->type
= TOKEN_NUMERIC
;
1034 token
->type
= TOKEN_UNDEFINED
;
1039 static void readSubToken (tokenInfo
*const token
)
1041 if (token
->secondary
== NULL
)
1043 token
->secondary
= newToken ();
1044 readToken (token
->secondary
);
1049 * Scanning functions
1052 static void skipToToken (tokenInfo
*const token
, tokenType type
)
1054 while (! isType (token
, type
) && ! isType (token
, TOKEN_STATEMENT_END
) &&
1055 !(token
->secondary
!= NULL
&& isType (token
->secondary
, TOKEN_STATEMENT_END
)))
1059 static void skipPast (tokenInfo
*const token
, tokenType type
)
1061 skipToToken (token
, type
);
1062 if (! isType (token
, TOKEN_STATEMENT_END
))
1066 static void skipToNextStatement (tokenInfo
*const token
)
1070 skipToToken (token
, TOKEN_STATEMENT_END
);
1072 } while (isType (token
, TOKEN_STATEMENT_END
));
1075 /* skip over parenthesis enclosed contents starting at next token.
1076 * Token is left at the first token following closing parenthesis. If an
1077 * opening parenthesis is not found, `token' is moved to the end of the
1080 static void skipOverParens (tokenInfo
*const token
)
1084 if (isType (token
, TOKEN_STATEMENT_END
))
1086 else if (isType (token
, TOKEN_PAREN_OPEN
))
1088 else if (isType (token
, TOKEN_PAREN_CLOSE
))
1091 } while (level
> 0);
1094 static boolean
isTypeSpec (tokenInfo
*const token
)
1097 switch (token
->keyword
)
1100 case KEYWORD_integer
:
1102 case KEYWORD_double
:
1103 case KEYWORD_complex
:
1104 case KEYWORD_character
:
1105 case KEYWORD_logical
:
1106 case KEYWORD_record
:
1117 static boolean
isSubprogramPrefix (tokenInfo
*const token
)
1120 switch (token
->keyword
)
1122 case KEYWORD_elemental
:
1124 case KEYWORD_recursive
:
1125 case KEYWORD_stdcall
:
1136 * is INTEGER [kind-selector]
1137 * or REAL [kind-selector] is ( etc. )
1138 * or DOUBLE PRECISION
1139 * or COMPLEX [kind-selector]
1140 * or CHARACTER [kind-selector]
1141 * or LOGICAL [kind-selector]
1142 * or TYPE ( type-name )
1144 * Note that INTEGER and REAL may be followed by "*N" where "N" is an integer
1146 static void parseTypeSpec (tokenInfo
*const token
)
1148 /* parse type-spec, leaving `token' at first token following type-spec */
1149 Assert (isTypeSpec (token
));
1150 switch (token
->keyword
)
1152 case KEYWORD_character
:
1153 /* skip char-selector */
1155 if (isType (token
, TOKEN_OPERATOR
) &&
1156 strcmp (vStringValue (token
->string
), "*") == 0)
1158 if (isType (token
, TOKEN_PAREN_OPEN
))
1159 skipOverParens (token
);
1160 else if (isType (token
, TOKEN_NUMERIC
))
1166 case KEYWORD_complex
:
1167 case KEYWORD_integer
:
1168 case KEYWORD_logical
:
1171 if (isType (token
, TOKEN_PAREN_OPEN
))
1172 skipOverParens (token
); /* skip kind-selector */
1173 if (isType (token
, TOKEN_OPERATOR
) &&
1174 strcmp (vStringValue (token
->string
), "*") == 0)
1181 case KEYWORD_double
:
1183 if (isKeyword (token
, KEYWORD_complex
) ||
1184 isKeyword (token
, KEYWORD_precision
))
1187 skipToToken (token
, TOKEN_STATEMENT_END
);
1190 case KEYWORD_record
:
1192 if (isType (token
, TOKEN_OPERATOR
) &&
1193 strcmp (vStringValue (token
->string
), "/") == 0)
1195 readToken (token
); /* skip to structure name */
1196 readToken (token
); /* skip to '/' */
1197 readToken (token
); /* skip to variable name */
1203 if (isType (token
, TOKEN_PAREN_OPEN
))
1204 skipOverParens (token
); /* skip type-name */
1206 parseDerivedTypeDef (token
);
1210 skipToToken (token
, TOKEN_STATEMENT_END
);
1215 static boolean
skipStatementIfKeyword (tokenInfo
*const token
, keywordId keyword
)
1217 boolean result
= FALSE
;
1218 if (isKeyword (token
, keyword
))
1221 skipToNextStatement (token
);
1226 /* parse a list of qualifying specifiers, leaving `token' at first token
1227 * following list. Examples of such specifiers are:
1228 * [[, attr-spec] ::]
1229 * [[, component-attr-spec-list] ::]
1233 * or access-spec (is PUBLIC or PRIVATE)
1235 * or DIMENSION ( array-spec )
1237 * or INTENT ( intent-spec )
1244 * component-attr-spec
1246 * or DIMENSION ( component-array-spec )
1248 static void parseQualifierSpecList (tokenInfo
*const token
)
1252 readToken (token
); /* should be an attr-spec */
1253 switch (token
->keyword
)
1255 case KEYWORD_parameter
:
1256 case KEYWORD_allocatable
:
1257 case KEYWORD_external
:
1258 case KEYWORD_intrinsic
:
1259 case KEYWORD_optional
:
1260 case KEYWORD_private
:
1261 case KEYWORD_pointer
:
1262 case KEYWORD_public
:
1264 case KEYWORD_target
:
1268 case KEYWORD_dimension
:
1269 case KEYWORD_intent
:
1271 skipOverParens (token
);
1274 default: skipToToken (token
, TOKEN_STATEMENT_END
); break;
1276 } while (isType (token
, TOKEN_COMMA
));
1277 if (! isType (token
, TOKEN_DOUBLE_COLON
))
1278 skipToToken (token
, TOKEN_STATEMENT_END
);
1281 static tagType
variableTagType (void)
1283 tagType result
= TAG_VARIABLE
;
1284 if (ancestorCount () > 0)
1286 const tokenInfo
* const parent
= ancestorTop ();
1287 switch (parent
->tag
)
1289 case TAG_MODULE
: result
= TAG_VARIABLE
; break;
1290 case TAG_DERIVED_TYPE
: result
= TAG_COMPONENT
; break;
1291 case TAG_FUNCTION
: result
= TAG_LOCAL
; break;
1292 case TAG_SUBROUTINE
: result
= TAG_LOCAL
; break;
1293 default: result
= TAG_VARIABLE
; break;
1299 static void parseEntityDecl (tokenInfo
*const token
)
1301 Assert (isType (token
, TOKEN_IDENTIFIER
));
1302 makeFortranTag (token
, variableTagType ());
1304 if (isType (token
, TOKEN_PAREN_OPEN
))
1305 skipOverParens (token
);
1306 if (isType (token
, TOKEN_OPERATOR
) &&
1307 strcmp (vStringValue (token
->string
), "*") == 0)
1309 readToken (token
); /* read char-length */
1310 if (isType (token
, TOKEN_PAREN_OPEN
))
1311 skipOverParens (token
);
1315 if (isType (token
, TOKEN_OPERATOR
))
1317 if (strcmp (vStringValue (token
->string
), "/") == 0)
1318 { /* skip over initializations of structure field */
1320 skipPast (token
, TOKEN_OPERATOR
);
1322 else if (strcmp (vStringValue (token
->string
), "=") == 0)
1324 while (! isType (token
, TOKEN_COMMA
) &&
1325 ! isType (token
, TOKEN_STATEMENT_END
))
1328 if (isType (token
, TOKEN_PAREN_OPEN
))
1329 skipOverParens (token
);
1333 /* token left at either comma or statement end */
1336 static void parseEntityDeclList (tokenInfo
*const token
)
1338 if (isType (token
, TOKEN_PERCENT
))
1339 skipToNextStatement (token
);
1340 else while (isType (token
, TOKEN_IDENTIFIER
) ||
1341 (isType (token
, TOKEN_KEYWORD
) &&
1342 !isKeyword (token
, KEYWORD_function
) &&
1343 !isKeyword (token
, KEYWORD_subroutine
)))
1345 /* compilers accept keywoeds as identifiers */
1346 if (isType (token
, TOKEN_KEYWORD
))
1347 token
->type
= TOKEN_IDENTIFIER
;
1348 parseEntityDecl (token
);
1349 if (isType (token
, TOKEN_COMMA
))
1351 else if (isType (token
, TOKEN_STATEMENT_END
))
1353 skipToNextStatement (token
);
1359 /* type-declaration-stmt is
1360 * type-spec [[, attr-spec] ... ::] entity-decl-list
1362 static void parseTypeDeclarationStmt (tokenInfo
*const token
)
1364 Assert (isTypeSpec (token
));
1365 parseTypeSpec (token
);
1366 if (!isType (token
, TOKEN_STATEMENT_END
)) /* if not end of derived type... */
1368 if (isType (token
, TOKEN_COMMA
))
1369 parseQualifierSpecList (token
);
1370 if (isType (token
, TOKEN_DOUBLE_COLON
))
1372 parseEntityDeclList (token
);
1374 if (isType (token
, TOKEN_STATEMENT_END
))
1375 skipToNextStatement (token
);
1379 * NAMELIST /namelist-group-name/ namelist-group-object-list
1380 * [[,]/[namelist-group-name]/ namelist-block-object-list] ...
1382 * namelist-group-object is
1386 * COMMON [/[common-block-name]/] common-block-object-list
1387 * [[,]/[common-block-name]/ common-block-object-list] ...
1389 * common-block-object is
1390 * variable-name [ ( explicit-shape-spec-list ) ]
1392 static void parseCommonNamelistStmt (tokenInfo
*const token
, tagType type
)
1394 Assert (isKeyword (token
, KEYWORD_common
) ||
1395 isKeyword (token
, KEYWORD_namelist
));
1399 if (isType (token
, TOKEN_OPERATOR
) &&
1400 strcmp (vStringValue (token
->string
), "/") == 0)
1403 if (isType (token
, TOKEN_IDENTIFIER
))
1405 makeFortranTag (token
, type
);
1408 skipPast (token
, TOKEN_OPERATOR
);
1410 if (isType (token
, TOKEN_IDENTIFIER
))
1411 makeFortranTag (token
, TAG_LOCAL
);
1413 if (isType (token
, TOKEN_PAREN_OPEN
))
1414 skipOverParens (token
); /* skip explicit-shape-spec-list */
1415 if (isType (token
, TOKEN_COMMA
))
1417 } while (! isType (token
, TOKEN_STATEMENT_END
));
1418 skipToNextStatement (token
);
1421 static void parseFieldDefinition (tokenInfo
*const token
)
1423 if (isTypeSpec (token
))
1424 parseTypeDeclarationStmt (token
);
1425 else if (isKeyword (token
, KEYWORD_structure
))
1426 parseStructureStmt (token
);
1427 else if (isKeyword (token
, KEYWORD_union
))
1428 parseUnionStmt (token
);
1430 skipToNextStatement (token
);
1433 static void parseMap (tokenInfo
*const token
)
1435 Assert (isKeyword (token
, KEYWORD_map
));
1436 skipToNextStatement (token
);
1437 while (! isKeyword (token
, KEYWORD_end
))
1438 parseFieldDefinition (token
);
1439 readSubToken (token
);
1440 /* should be at KEYWORD_map token */
1441 skipToNextStatement (token
);
1446 * [field-definition] [field-definition] ...
1449 * [field-definition] [field-definition] ...
1452 * [field-definition]
1453 * [field-definition] ...
1458 * Typed data declarations (variables or arrays) in structure declarations
1459 * have the form of normal Fortran typed data declarations. Data items with
1460 * different types can be freely intermixed within a structure declaration.
1462 * Unnamed fields can be declared in a structure by specifying the pseudo
1463 * name %FILL in place of an actual field name. You can use this mechanism to
1464 * generate empty space in a record for purposes such as alignment.
1466 * All mapped field declarations that are made within a UNION declaration
1467 * share a common location within the containing structure. When initializing
1468 * the fields within a UNION, the final initialization value assigned
1469 * overlays any value previously assigned to a field definition that shares
1472 static void parseUnionStmt (tokenInfo
*const token
)
1474 Assert (isKeyword (token
, KEYWORD_union
));
1475 skipToNextStatement (token
);
1476 while (isKeyword (token
, KEYWORD_map
))
1478 /* should be at KEYWORD_end token */
1479 readSubToken (token
);
1480 /* secondary token should be KEYWORD_end token */
1481 skipToNextStatement (token
);
1484 /* STRUCTURE [/structure-name/] [field-names]
1485 * [field-definition]
1486 * [field-definition] ...
1490 * identifies the structure in a subsequent RECORD statement.
1491 * Substructures can be established within a structure by means of either
1492 * a nested STRUCTURE declaration or a RECORD statement.
1495 * (for substructure declarations only) one or more names having the
1496 * structure of the substructure being defined.
1499 * can be one or more of the following:
1501 * Typed data declarations, which can optionally include one or more
1502 * data initialization values.
1504 * Substructure declarations (defined by either RECORD statements or
1505 * subsequent STRUCTURE statements).
1507 * UNION declarations, which are mapped fields defined by a block of
1508 * statements. The syntax of a UNION declaration is described below.
1510 * PARAMETER statements, which do not affect the form of the
1513 static void parseStructureStmt (tokenInfo
*const token
)
1516 Assert (isKeyword (token
, KEYWORD_structure
));
1518 if (isType (token
, TOKEN_OPERATOR
) &&
1519 strcmp (vStringValue (token
->string
), "/") == 0)
1520 { /* read structure name */
1522 if (isType (token
, TOKEN_IDENTIFIER
))
1523 makeFortranTag (token
, TAG_DERIVED_TYPE
);
1524 name
= newTokenFrom (token
);
1525 skipPast (token
, TOKEN_OPERATOR
);
1528 { /* fake out anonymous structure */
1530 name
->type
= TOKEN_IDENTIFIER
;
1531 name
->tag
= TAG_DERIVED_TYPE
;
1532 vStringCopyS (name
->string
, "anonymous");
1534 while (isType (token
, TOKEN_IDENTIFIER
))
1535 { /* read field names */
1536 makeFortranTag (token
, TAG_COMPONENT
);
1538 if (isType (token
, TOKEN_COMMA
))
1541 skipToNextStatement (token
);
1542 ancestorPush (name
);
1543 while (! isKeyword (token
, KEYWORD_end
))
1544 parseFieldDefinition (token
);
1545 readSubToken (token
);
1546 /* secondary token should be KEYWORD_structure token */
1547 skipToNextStatement (token
);
1552 /* specification-stmt
1553 * is access-stmt (is access-spec [[::] access-id-list)
1554 * or allocatable-stmt (is ALLOCATABLE [::] array-name etc.)
1555 * or common-stmt (is COMMON [ / [common-block-name] /] etc.)
1556 * or data-stmt (is DATA data-stmt-list [[,] data-stmt-set] ...)
1557 * or dimension-stmt (is DIMENSION [::] array-name etc.)
1558 * or equivalence-stmt (is EQUIVALENCE equivalence-set-list)
1559 * or external-stmt (is EXTERNAL etc.)
1560 * or intent-stmt (is INTENT ( intent-spec ) [::] etc.)
1561 * or instrinsic-stmt (is INTRINSIC etc.)
1562 * or namelist-stmt (is NAMELIST / namelist-group-name / etc.)
1563 * or optional-stmt (is OPTIONAL [::] etc.)
1564 * or pointer-stmt (is POINTER [::] object-name etc.)
1565 * or save-stmt (is SAVE etc.)
1566 * or target-stmt (is TARGET [::] object-name etc.)
1568 * access-spec is PUBLIC or PRIVATE
1570 static boolean
parseSpecificationStmt (tokenInfo
*const token
)
1572 boolean result
= TRUE
;
1573 switch (token
->keyword
)
1575 case KEYWORD_common
:
1576 parseCommonNamelistStmt (token
, TAG_COMMON_BLOCK
);
1579 case KEYWORD_namelist
:
1580 parseCommonNamelistStmt (token
, TAG_NAMELIST
);
1583 case KEYWORD_structure
:
1584 parseStructureStmt (token
);
1587 case KEYWORD_allocatable
:
1589 case KEYWORD_dimension
:
1590 case KEYWORD_equivalence
:
1591 case KEYWORD_external
:
1592 case KEYWORD_intent
:
1593 case KEYWORD_intrinsic
:
1594 case KEYWORD_optional
:
1595 case KEYWORD_pointer
:
1596 case KEYWORD_private
:
1597 case KEYWORD_public
:
1599 case KEYWORD_target
:
1600 skipToNextStatement (token
);
1610 /* component-def-stmt is
1611 * type-spec [[, component-attr-spec-list] ::] component-decl-list
1614 * component-name [ ( component-array-spec ) ] [ * char-length ]
1616 static void parseComponentDefStmt (tokenInfo
*const token
)
1618 Assert (isTypeSpec (token
));
1619 parseTypeSpec (token
);
1620 if (isType (token
, TOKEN_COMMA
))
1621 parseQualifierSpecList (token
);
1622 if (isType (token
, TOKEN_DOUBLE_COLON
))
1624 parseEntityDeclList (token
);
1627 /* derived-type-def is
1628 * derived-type-stmt is (TYPE [[, access-spec] ::] type-name
1629 * [private-sequence-stmt] ... (is PRIVATE or SEQUENCE)
1630 * component-def-stmt
1631 * [component-def-stmt] ...
1634 static void parseDerivedTypeDef (tokenInfo
*const token
)
1636 if (isType (token
, TOKEN_COMMA
))
1637 parseQualifierSpecList (token
);
1638 if (isType (token
, TOKEN_DOUBLE_COLON
))
1640 if (isType (token
, TOKEN_IDENTIFIER
))
1641 makeFortranTag (token
, TAG_DERIVED_TYPE
);
1642 ancestorPush (token
);
1643 skipToNextStatement (token
);
1644 if (isKeyword (token
, KEYWORD_private
) ||
1645 isKeyword (token
, KEYWORD_sequence
))
1647 skipToNextStatement (token
);
1649 while (! isKeyword (token
, KEYWORD_end
))
1651 if (isTypeSpec (token
))
1652 parseComponentDefStmt (token
);
1654 skipToNextStatement (token
);
1656 readSubToken (token
);
1657 /* secondary token should be KEYWORD_type token */
1658 skipToToken (token
, TOKEN_STATEMENT_END
);
1663 * interface-stmt (is INTERFACE [generic-spec])
1665 * [module-procedure-stmt] ...
1666 * end-interface-stmt (is END INTERFACE)
1670 * or OPERATOR ( defined-operator )
1671 * or ASSIGNMENT ( = )
1675 * [specification-part]
1677 * or subroutine-stmt
1678 * [specification-part]
1679 * end-subroutine-stmt
1681 * module-procedure-stmt is
1682 * MODULE PROCEDURE procedure-name-list
1684 static void parseInterfaceBlock (tokenInfo
*const token
)
1686 tokenInfo
*name
= NULL
;
1687 Assert (isKeyword (token
, KEYWORD_interface
));
1689 if (isType (token
, TOKEN_IDENTIFIER
))
1691 makeFortranTag (token
, TAG_INTERFACE
);
1692 name
= newTokenFrom (token
);
1694 else if (isKeyword (token
, KEYWORD_assignment
) ||
1695 isKeyword (token
, KEYWORD_operator
))
1698 if (isType (token
, TOKEN_PAREN_OPEN
))
1700 if (isType (token
, TOKEN_OPERATOR
))
1702 makeFortranTag (token
, TAG_INTERFACE
);
1703 name
= newTokenFrom (token
);
1709 name
->type
= TOKEN_IDENTIFIER
;
1710 name
->tag
= TAG_INTERFACE
;
1712 ancestorPush (name
);
1713 while (! isKeyword (token
, KEYWORD_end
))
1715 switch (token
->keyword
)
1717 case KEYWORD_function
: parseFunctionSubprogram (token
); break;
1718 case KEYWORD_subroutine
: parseSubroutineSubprogram (token
); break;
1721 if (isSubprogramPrefix (token
))
1723 else if (isTypeSpec (token
))
1724 parseTypeSpec (token
);
1726 skipToNextStatement (token
);
1730 readSubToken (token
);
1731 /* secondary token should be KEYWORD_interface token */
1732 skipToNextStatement (token
);
1738 * ENTRY entry-name [ ( dummy-arg-list ) ]
1740 static void parseEntryStmt (tokenInfo
*const token
)
1742 Assert (isKeyword (token
, KEYWORD_entry
));
1744 if (isType (token
, TOKEN_IDENTIFIER
))
1745 makeFortranTag (token
, TAG_ENTRY_POINT
);
1746 skipToNextStatement (token
);
1749 /* stmt-function-stmt is
1750 * function-name ([dummy-arg-name-list]) = scalar-expr
1752 static boolean
parseStmtFunctionStmt (tokenInfo
*const token
)
1754 boolean result
= FALSE
;
1755 Assert (isType (token
, TOKEN_IDENTIFIER
));
1756 #if 0 /* cannot reliably parse this yet */
1757 makeFortranTag (token
, TAG_FUNCTION
);
1760 if (isType (token
, TOKEN_PAREN_OPEN
))
1762 skipOverParens (token
);
1763 result
= (boolean
) (isType (token
, TOKEN_OPERATOR
) &&
1764 strcmp (vStringValue (token
->string
), "=") == 0);
1766 skipToNextStatement (token
);
1770 static boolean
isIgnoredDeclaration (tokenInfo
*const token
)
1773 switch (token
->keyword
)
1775 case KEYWORD_cexternal
:
1776 case KEYWORD_cglobal
:
1777 case KEYWORD_dllexport
:
1778 case KEYWORD_dllimport
:
1779 case KEYWORD_external
:
1780 case KEYWORD_format
:
1781 case KEYWORD_include
:
1782 case KEYWORD_inline
:
1783 case KEYWORD_parameter
:
1784 case KEYWORD_pascal
:
1785 case KEYWORD_pexternal
:
1786 case KEYWORD_pglobal
:
1787 case KEYWORD_static
:
1789 case KEYWORD_virtual
:
1790 case KEYWORD_volatile
:
1801 /* declaration-construct
1802 * [derived-type-def]
1804 * [type-declaration-stmt]
1805 * [specification-stmt]
1806 * [parameter-stmt] (is PARAMETER ( named-constant-def-list )
1807 * [format-stmt] (is FORMAT format-specification)
1809 * [stmt-function-stmt]
1811 static boolean
parseDeclarationConstruct (tokenInfo
*const token
)
1813 boolean result
= TRUE
;
1814 switch (token
->keyword
)
1816 case KEYWORD_entry
: parseEntryStmt (token
); break;
1817 case KEYWORD_interface
: parseInterfaceBlock (token
); break;
1818 case KEYWORD_stdcall
: readToken (token
); break;
1819 /* derived type handled by parseTypeDeclarationStmt(); */
1821 case KEYWORD_automatic
:
1823 if (isTypeSpec (token
))
1824 parseTypeDeclarationStmt (token
);
1826 skipToNextStatement (token
);
1831 if (isIgnoredDeclaration (token
))
1832 skipToNextStatement (token
);
1833 else if (isTypeSpec (token
))
1835 parseTypeDeclarationStmt (token
);
1838 else if (isType (token
, TOKEN_IDENTIFIER
))
1839 result
= parseStmtFunctionStmt (token
);
1841 result
= parseSpecificationStmt (token
);
1847 /* implicit-part-stmt
1848 * is [implicit-stmt] (is IMPLICIT etc.)
1849 * or [parameter-stmt] (is PARAMETER etc.)
1850 * or [format-stmt] (is FORMAT etc.)
1851 * or [entry-stmt] (is ENTRY entry-name etc.)
1853 static boolean
parseImplicitPartStmt (tokenInfo
*const token
)
1855 boolean result
= TRUE
;
1856 switch (token
->keyword
)
1858 case KEYWORD_entry
: parseEntryStmt (token
); break;
1860 case KEYWORD_implicit
:
1861 case KEYWORD_include
:
1862 case KEYWORD_parameter
:
1863 case KEYWORD_format
:
1864 skipToNextStatement (token
);
1867 default: result
= FALSE
; break;
1872 /* specification-part is
1873 * [use-stmt] ... (is USE module-name etc.)
1874 * [implicit-part] (is [implicit-part-stmt] ... [implicit-stmt])
1875 * [declaration-construct] ...
1877 static boolean
parseSpecificationPart (tokenInfo
*const token
)
1879 boolean result
= FALSE
;
1880 while (skipStatementIfKeyword (token
, KEYWORD_use
))
1882 while (parseImplicitPartStmt (token
))
1884 while (parseDeclarationConstruct (token
))
1890 * block-data-stmt (is BLOCK DATA [block-data-name]
1891 * [specification-part]
1892 * end-block-data-stmt (is END [BLOCK DATA [block-data-name]])
1894 static void parseBlockData (tokenInfo
*const token
)
1896 Assert (isKeyword (token
, KEYWORD_block
));
1898 if (isKeyword (token
, KEYWORD_data
))
1901 if (isType (token
, TOKEN_IDENTIFIER
))
1902 makeFortranTag (token
, TAG_BLOCK_DATA
);
1904 ancestorPush (token
);
1905 skipToNextStatement (token
);
1906 parseSpecificationPart (token
);
1907 while (! isKeyword (token
, KEYWORD_end
))
1908 skipToNextStatement (token
);
1909 readSubToken (token
);
1910 /* secondary token should be KEYWORD_NONE or KEYWORD_block token */
1911 skipToNextStatement (token
);
1915 /* internal-subprogram-part is
1916 * contains-stmt (is CONTAINS)
1917 * internal-subprogram
1918 * [internal-subprogram] ...
1920 * internal-subprogram
1921 * is function-subprogram
1922 * or subroutine-subprogram
1924 static void parseInternalSubprogramPart (tokenInfo
*const token
)
1926 boolean done
= FALSE
;
1927 if (isKeyword (token
, KEYWORD_contains
))
1928 skipToNextStatement (token
);
1931 switch (token
->keyword
)
1933 case KEYWORD_function
: parseFunctionSubprogram (token
); break;
1934 case KEYWORD_subroutine
: parseSubroutineSubprogram (token
); break;
1935 case KEYWORD_end
: done
= TRUE
; break;
1938 if (isSubprogramPrefix (token
))
1940 else if (isTypeSpec (token
))
1941 parseTypeSpec (token
);
1950 * module-stmt (is MODULE module-name)
1951 * [specification-part]
1952 * [module-subprogram-part]
1953 * end-module-stmt (is END [MODULE [module-name]])
1955 * module-subprogram-part
1956 * contains-stmt (is CONTAINS)
1958 * [module-subprogram] ...
1961 * is function-subprogram
1962 * or subroutine-subprogram
1964 static void parseModule (tokenInfo
*const token
)
1966 Assert (isKeyword (token
, KEYWORD_module
));
1968 if (isType (token
, TOKEN_IDENTIFIER
))
1969 makeFortranTag (token
, TAG_MODULE
);
1970 ancestorPush (token
);
1971 skipToNextStatement (token
);
1972 parseSpecificationPart (token
);
1973 if (isKeyword (token
, KEYWORD_contains
))
1974 parseInternalSubprogramPart (token
);
1975 while (! isKeyword (token
, KEYWORD_end
))
1976 skipToNextStatement (token
);
1977 readSubToken (token
);
1978 /* secondary token should be KEYWORD_NONE or KEYWORD_module token */
1979 skipToNextStatement (token
);
1984 * executable-construct
1986 * executable-contstruct is
1987 * execution-part-construct [execution-part-construct]
1989 * execution-part-construct
1990 * is executable-construct
1995 static boolean
parseExecutionPart (tokenInfo
*const token
)
1997 boolean result
= FALSE
;
1998 boolean done
= FALSE
;
2001 switch (token
->keyword
)
2004 if (isSubprogramPrefix (token
))
2007 skipToNextStatement (token
);
2012 parseEntryStmt (token
);
2016 case KEYWORD_contains
:
2017 case KEYWORD_function
:
2018 case KEYWORD_subroutine
:
2023 readSubToken (token
);
2024 if (isSecondaryKeyword (token
, KEYWORD_do
) ||
2025 isSecondaryKeyword (token
, KEYWORD_if
) ||
2026 isSecondaryKeyword (token
, KEYWORD_select
) ||
2027 isSecondaryKeyword (token
, KEYWORD_where
))
2029 skipToNextStatement (token
);
2040 static void parseSubprogram (tokenInfo
*const token
, const tagType tag
)
2042 Assert (isKeyword (token
, KEYWORD_program
) ||
2043 isKeyword (token
, KEYWORD_function
) ||
2044 isKeyword (token
, KEYWORD_subroutine
));
2046 if (isType (token
, TOKEN_IDENTIFIER
))
2047 makeFortranTag (token
, tag
);
2048 ancestorPush (token
);
2049 skipToNextStatement (token
);
2050 parseSpecificationPart (token
);
2051 parseExecutionPart (token
);
2052 if (isKeyword (token
, KEYWORD_contains
))
2053 parseInternalSubprogramPart (token
);
2054 /* should be at KEYWORD_end token */
2055 readSubToken (token
);
2056 /* secondary token should be one of KEYWORD_NONE, KEYWORD_program,
2057 * KEYWORD_function, KEYWORD_function
2059 skipToNextStatement (token
);
2064 /* function-subprogram is
2065 * function-stmt (is [prefix] FUNCTION function-name etc.)
2066 * [specification-part]
2068 * [internal-subprogram-part]
2069 * end-function-stmt (is END [FUNCTION [function-name]])
2072 * is type-spec [RECURSIVE]
2073 * or [RECURSIVE] type-spec
2075 static void parseFunctionSubprogram (tokenInfo
*const token
)
2077 parseSubprogram (token
, TAG_FUNCTION
);
2080 /* subroutine-subprogram is
2081 * subroutine-stmt (is [RECURSIVE] SUBROUTINE subroutine-name etc.)
2082 * [specification-part]
2084 * [internal-subprogram-part]
2085 * end-subroutine-stmt (is END [SUBROUTINE [function-name]])
2087 static void parseSubroutineSubprogram (tokenInfo
*const token
)
2089 parseSubprogram (token
, TAG_SUBROUTINE
);
2093 * [program-stmt] (is PROGRAM program-name)
2094 * [specification-part]
2096 * [internal-subprogram-part ]
2099 static void parseMainProgram (tokenInfo
*const token
)
2101 parseSubprogram (token
, TAG_PROGRAM
);
2106 * or external-subprogram (is function-subprogram or subroutine-subprogram)
2110 static void parseProgramUnit (tokenInfo
*const token
)
2115 if (isType (token
, TOKEN_STATEMENT_END
))
2117 else switch (token
->keyword
)
2119 case KEYWORD_block
: parseBlockData (token
); break;
2120 case KEYWORD_end
: skipToNextStatement (token
); break;
2121 case KEYWORD_function
: parseFunctionSubprogram (token
); break;
2122 case KEYWORD_module
: parseModule (token
); break;
2123 case KEYWORD_program
: parseMainProgram (token
); break;
2124 case KEYWORD_subroutine
: parseSubroutineSubprogram (token
); break;
2127 if (isSubprogramPrefix (token
))
2131 boolean one
= parseSpecificationPart (token
);
2132 boolean two
= parseExecutionPart (token
);
2141 static boolean
findFortranTags (const unsigned int passCount
)
2144 exception_t exception
;
2147 Assert (passCount
< 3);
2148 Parent
= newToken ();
2149 token
= newToken ();
2150 FreeSourceForm
= (boolean
) (passCount
> 1);
2152 exception
= (exception_t
) setjmp (Exception
);
2153 if (exception
== ExceptionEOF
)
2155 else if (exception
== ExceptionFixedFormat
&& ! FreeSourceForm
)
2157 verbose ("%s: not fixed source form; retry as free source form\n",
2158 getInputFileName ());
2163 parseProgramUnit (token
);
2167 deleteToken (token
);
2168 deleteToken (Parent
);
2173 static void initialize (const langType language
)
2175 Lang_fortran
= language
;
2176 buildFortranKeywordHash ();
2179 extern parserDefinition
* FortranParser (void)
2181 static const char *const extensions
[] = {
2182 "f", "for", "ftn", "f77", "f90", "f95",
2183 #ifndef CASE_INSENSITIVE_FILENAMES
2184 "F", "FOR", "FTN", "F77", "F90", "F95",
2188 parserDefinition
* def
= parserNew ("Fortran");
2189 def
->kinds
= FortranKinds
;
2190 def
->kindCount
= KIND_COUNT (FortranKinds
);
2191 def
->extensions
= extensions
;
2192 def
->parser2
= findFortranTags
;
2193 def
->initialize
= initialize
;
2197 /* vi:set tabstop=4 shiftwidth=4: */