ctags.rb 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. data/Gemfile +2 -0
  2. data/Rakefile +23 -0
  3. data/ctags.rb.gemspec +23 -0
  4. data/ext/.gitignore +3 -0
  5. data/ext/extconf.rb +15 -0
  6. data/ext/vendor/exuberant-ctags/.gitignore +6 -0
  7. data/ext/vendor/exuberant-ctags/.indent.pro +31 -0
  8. data/ext/vendor/exuberant-ctags/COPYING +340 -0
  9. data/ext/vendor/exuberant-ctags/EXTENDING.html +386 -0
  10. data/ext/vendor/exuberant-ctags/FAQ +371 -0
  11. data/ext/vendor/exuberant-ctags/INSTALL +215 -0
  12. data/ext/vendor/exuberant-ctags/INSTALL.oth +73 -0
  13. data/ext/vendor/exuberant-ctags/MAINTAINERS +88 -0
  14. data/ext/vendor/exuberant-ctags/Makefile.in +222 -0
  15. data/ext/vendor/exuberant-ctags/NEWS +871 -0
  16. data/ext/vendor/exuberant-ctags/README +73 -0
  17. data/ext/vendor/exuberant-ctags/ant.c +42 -0
  18. data/ext/vendor/exuberant-ctags/argproc.c +505 -0
  19. data/ext/vendor/exuberant-ctags/args.c +274 -0
  20. data/ext/vendor/exuberant-ctags/args.h +63 -0
  21. data/ext/vendor/exuberant-ctags/asm.c +387 -0
  22. data/ext/vendor/exuberant-ctags/asp.c +328 -0
  23. data/ext/vendor/exuberant-ctags/awk.c +81 -0
  24. data/ext/vendor/exuberant-ctags/basic.c +203 -0
  25. data/ext/vendor/exuberant-ctags/beta.c +321 -0
  26. data/ext/vendor/exuberant-ctags/c.c +2932 -0
  27. data/ext/vendor/exuberant-ctags/cobol.c +50 -0
  28. data/ext/vendor/exuberant-ctags/config.h.in +277 -0
  29. data/ext/vendor/exuberant-ctags/configure +7704 -0
  30. data/ext/vendor/exuberant-ctags/configure.ac +532 -0
  31. data/ext/vendor/exuberant-ctags/ctags.1 +1186 -0
  32. data/ext/vendor/exuberant-ctags/ctags.h +28 -0
  33. data/ext/vendor/exuberant-ctags/ctags.html +2087 -0
  34. data/ext/vendor/exuberant-ctags/ctags.spec +40 -0
  35. data/ext/vendor/exuberant-ctags/debug.c +113 -0
  36. data/ext/vendor/exuberant-ctags/debug.h +70 -0
  37. data/ext/vendor/exuberant-ctags/descrip.mms +68 -0
  38. data/ext/vendor/exuberant-ctags/dosbatch.c +42 -0
  39. data/ext/vendor/exuberant-ctags/e_amiga.h +24 -0
  40. data/ext/vendor/exuberant-ctags/e_djgpp.h +47 -0
  41. data/ext/vendor/exuberant-ctags/e_mac.h +143 -0
  42. data/ext/vendor/exuberant-ctags/e_msoft.h +76 -0
  43. data/ext/vendor/exuberant-ctags/e_os2.h +37 -0
  44. data/ext/vendor/exuberant-ctags/e_qdos.h +34 -0
  45. data/ext/vendor/exuberant-ctags/e_riscos.h +58 -0
  46. data/ext/vendor/exuberant-ctags/e_vms.h +31 -0
  47. data/ext/vendor/exuberant-ctags/eiffel.c +1352 -0
  48. data/ext/vendor/exuberant-ctags/entry.c +847 -0
  49. data/ext/vendor/exuberant-ctags/entry.h +103 -0
  50. data/ext/vendor/exuberant-ctags/erlang.c +189 -0
  51. data/ext/vendor/exuberant-ctags/flex.c +2243 -0
  52. data/ext/vendor/exuberant-ctags/fortran.c +2197 -0
  53. data/ext/vendor/exuberant-ctags/general.h +127 -0
  54. data/ext/vendor/exuberant-ctags/get.c +669 -0
  55. data/ext/vendor/exuberant-ctags/get.h +50 -0
  56. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/all-wcprops +47 -0
  57. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/entries +112 -0
  58. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/README.txt.svn-base +5 -0
  59. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regcomp.c.svn-base +3818 -0
  60. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex.c.svn-base +74 -0
  61. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex.h.svn-base +575 -0
  62. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex_internal.c.svn-base +1713 -0
  63. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex_internal.h.svn-base +773 -0
  64. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regexec.c.svn-base +4338 -0
  65. data/ext/vendor/exuberant-ctags/gnu_regex/README.txt +5 -0
  66. data/ext/vendor/exuberant-ctags/gnu_regex/regcomp.c +3818 -0
  67. data/ext/vendor/exuberant-ctags/gnu_regex/regex.c +74 -0
  68. data/ext/vendor/exuberant-ctags/gnu_regex/regex.h +575 -0
  69. data/ext/vendor/exuberant-ctags/gnu_regex/regex_internal.c +1713 -0
  70. data/ext/vendor/exuberant-ctags/gnu_regex/regex_internal.h +773 -0
  71. data/ext/vendor/exuberant-ctags/gnu_regex/regexec.c +4338 -0
  72. data/ext/vendor/exuberant-ctags/html.c +49 -0
  73. data/ext/vendor/exuberant-ctags/jscript.c +1572 -0
  74. data/ext/vendor/exuberant-ctags/keyword.c +258 -0
  75. data/ext/vendor/exuberant-ctags/keyword.h +34 -0
  76. data/ext/vendor/exuberant-ctags/lisp.c +139 -0
  77. data/ext/vendor/exuberant-ctags/lregex.c +704 -0
  78. data/ext/vendor/exuberant-ctags/lua.c +133 -0
  79. data/ext/vendor/exuberant-ctags/mac.c +273 -0
  80. data/ext/vendor/exuberant-ctags/magic.diff +21 -0
  81. data/ext/vendor/exuberant-ctags/main.c +584 -0
  82. data/ext/vendor/exuberant-ctags/main.h +32 -0
  83. data/ext/vendor/exuberant-ctags/maintainer.mak +476 -0
  84. data/ext/vendor/exuberant-ctags/make.c +217 -0
  85. data/ext/vendor/exuberant-ctags/matlab.c +44 -0
  86. data/ext/vendor/exuberant-ctags/mk_bc3.mak +46 -0
  87. data/ext/vendor/exuberant-ctags/mk_bc5.mak +49 -0
  88. data/ext/vendor/exuberant-ctags/mk_djg.mak +18 -0
  89. data/ext/vendor/exuberant-ctags/mk_manx.mak +65 -0
  90. data/ext/vendor/exuberant-ctags/mk_mingw.mak +31 -0
  91. data/ext/vendor/exuberant-ctags/mk_mpw.mak +130 -0
  92. data/ext/vendor/exuberant-ctags/mk_mvc.mak +40 -0
  93. data/ext/vendor/exuberant-ctags/mk_os2.mak +104 -0
  94. data/ext/vendor/exuberant-ctags/mk_qdos.mak +100 -0
  95. data/ext/vendor/exuberant-ctags/mk_sas.mak +63 -0
  96. data/ext/vendor/exuberant-ctags/mkinstalldirs +40 -0
  97. data/ext/vendor/exuberant-ctags/ocaml.c +1842 -0
  98. data/ext/vendor/exuberant-ctags/options.c +1842 -0
  99. data/ext/vendor/exuberant-ctags/options.h +155 -0
  100. data/ext/vendor/exuberant-ctags/parse.c +677 -0
  101. data/ext/vendor/exuberant-ctags/parse.h +129 -0
  102. data/ext/vendor/exuberant-ctags/parsers.h +63 -0
  103. data/ext/vendor/exuberant-ctags/pascal.c +267 -0
  104. data/ext/vendor/exuberant-ctags/perl.c +382 -0
  105. data/ext/vendor/exuberant-ctags/php.c +237 -0
  106. data/ext/vendor/exuberant-ctags/python.c +771 -0
  107. data/ext/vendor/exuberant-ctags/qdos.c +106 -0
  108. data/ext/vendor/exuberant-ctags/read.c +569 -0
  109. data/ext/vendor/exuberant-ctags/read.h +116 -0
  110. data/ext/vendor/exuberant-ctags/readtags.c +959 -0
  111. data/ext/vendor/exuberant-ctags/readtags.h +252 -0
  112. data/ext/vendor/exuberant-ctags/rexx.c +39 -0
  113. data/ext/vendor/exuberant-ctags/routines.c +891 -0
  114. data/ext/vendor/exuberant-ctags/routines.h +134 -0
  115. data/ext/vendor/exuberant-ctags/ruby.c +408 -0
  116. data/ext/vendor/exuberant-ctags/scheme.c +111 -0
  117. data/ext/vendor/exuberant-ctags/sh.c +115 -0
  118. data/ext/vendor/exuberant-ctags/slang.c +41 -0
  119. data/ext/vendor/exuberant-ctags/sml.c +212 -0
  120. data/ext/vendor/exuberant-ctags/sort.c +230 -0
  121. data/ext/vendor/exuberant-ctags/sort.h +32 -0
  122. data/ext/vendor/exuberant-ctags/source.mak +122 -0
  123. data/ext/vendor/exuberant-ctags/sql.c +2112 -0
  124. data/ext/vendor/exuberant-ctags/strlist.c +281 -0
  125. data/ext/vendor/exuberant-ctags/strlist.h +54 -0
  126. data/ext/vendor/exuberant-ctags/tcl.c +116 -0
  127. data/ext/vendor/exuberant-ctags/tex.c +524 -0
  128. data/ext/vendor/exuberant-ctags/verilog.c +340 -0
  129. data/ext/vendor/exuberant-ctags/vhdl.c +835 -0
  130. data/ext/vendor/exuberant-ctags/vim.c +636 -0
  131. data/ext/vendor/exuberant-ctags/vstring.c +232 -0
  132. data/ext/vendor/exuberant-ctags/vstring.h +85 -0
  133. data/ext/vendor/exuberant-ctags/yacc.c +40 -0
  134. data/lib/ctags/exuberant.rb +45 -0
  135. data/lib/ctags/version.rb +3 -0
  136. data/lib/ctags.rb +6 -0
  137. data/test/test_ctags.rb +24 -0
  138. metadata +233 -0
@@ -0,0 +1,2197 @@
1
+ /*
2
+ * $Id: fortran.c 660 2008-04-20 23:30:12Z elliotth $
3
+ *
4
+ * Copyright (c) 1998-2003, Darren Hiebert
5
+ *
6
+ * This source code is released for free distribution under the terms of the
7
+ * GNU General Public License.
8
+ *
9
+ * This module contains functions for generating tags for Fortran language
10
+ * files.
11
+ */
12
+
13
+ /*
14
+ * INCLUDE FILES
15
+ */
16
+ #include "general.h" /* must always come first */
17
+
18
+ #include <string.h>
19
+ #include <limits.h>
20
+ #include <ctype.h> /* to define tolower () */
21
+ #include <setjmp.h>
22
+
23
+ #include "debug.h"
24
+ #include "entry.h"
25
+ #include "keyword.h"
26
+ #include "options.h"
27
+ #include "parse.h"
28
+ #include "read.h"
29
+ #include "routines.h"
30
+ #include "vstring.h"
31
+
32
+ /*
33
+ * MACROS
34
+ */
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))
41
+
42
+ /*
43
+ * DATA DECLARATIONS
44
+ */
45
+
46
+ typedef enum eException {
47
+ ExceptionNone, ExceptionEOF, ExceptionFixedFormat, ExceptionLoop
48
+ } exception_t;
49
+
50
+ /* Used to designate type of line read in fixed source form.
51
+ */
52
+ typedef enum eFortranLineType {
53
+ LTYPE_UNDETERMINED,
54
+ LTYPE_INVALID,
55
+ LTYPE_COMMENT,
56
+ LTYPE_CONTINUATION,
57
+ LTYPE_EOF,
58
+ LTYPE_INITIAL,
59
+ LTYPE_SHORT
60
+ } lineType;
61
+
62
+ /* Used to specify type of keyword.
63
+ */
64
+ typedef enum eKeywordId {
65
+ KEYWORD_NONE = -1,
66
+ KEYWORD_allocatable,
67
+ KEYWORD_assignment,
68
+ KEYWORD_automatic,
69
+ KEYWORD_block,
70
+ KEYWORD_byte,
71
+ KEYWORD_cexternal,
72
+ KEYWORD_cglobal,
73
+ KEYWORD_character,
74
+ KEYWORD_common,
75
+ KEYWORD_complex,
76
+ KEYWORD_contains,
77
+ KEYWORD_data,
78
+ KEYWORD_dimension,
79
+ KEYWORD_dllexport,
80
+ KEYWORD_dllimport,
81
+ KEYWORD_do,
82
+ KEYWORD_double,
83
+ KEYWORD_elemental,
84
+ KEYWORD_end,
85
+ KEYWORD_entry,
86
+ KEYWORD_equivalence,
87
+ KEYWORD_external,
88
+ KEYWORD_format,
89
+ KEYWORD_function,
90
+ KEYWORD_if,
91
+ KEYWORD_implicit,
92
+ KEYWORD_include,
93
+ KEYWORD_inline,
94
+ KEYWORD_integer,
95
+ KEYWORD_intent,
96
+ KEYWORD_interface,
97
+ KEYWORD_intrinsic,
98
+ KEYWORD_logical,
99
+ KEYWORD_map,
100
+ KEYWORD_module,
101
+ KEYWORD_namelist,
102
+ KEYWORD_operator,
103
+ KEYWORD_optional,
104
+ KEYWORD_parameter,
105
+ KEYWORD_pascal,
106
+ KEYWORD_pexternal,
107
+ KEYWORD_pglobal,
108
+ KEYWORD_pointer,
109
+ KEYWORD_precision,
110
+ KEYWORD_private,
111
+ KEYWORD_program,
112
+ KEYWORD_public,
113
+ KEYWORD_pure,
114
+ KEYWORD_real,
115
+ KEYWORD_record,
116
+ KEYWORD_recursive,
117
+ KEYWORD_save,
118
+ KEYWORD_select,
119
+ KEYWORD_sequence,
120
+ KEYWORD_static,
121
+ KEYWORD_stdcall,
122
+ KEYWORD_structure,
123
+ KEYWORD_subroutine,
124
+ KEYWORD_target,
125
+ KEYWORD_then,
126
+ KEYWORD_type,
127
+ KEYWORD_union,
128
+ KEYWORD_use,
129
+ KEYWORD_value,
130
+ KEYWORD_virtual,
131
+ KEYWORD_volatile,
132
+ KEYWORD_where,
133
+ KEYWORD_while
134
+ } keywordId;
135
+
136
+ /* Used to determine whether keyword is valid for the token language and
137
+ * what its ID is.
138
+ */
139
+ typedef struct sKeywordDesc {
140
+ const char *name;
141
+ keywordId id;
142
+ } keywordDesc;
143
+
144
+ typedef enum eTokenType {
145
+ TOKEN_UNDEFINED,
146
+ TOKEN_COMMA,
147
+ TOKEN_DOUBLE_COLON,
148
+ TOKEN_IDENTIFIER,
149
+ TOKEN_KEYWORD,
150
+ TOKEN_LABEL,
151
+ TOKEN_NUMERIC,
152
+ TOKEN_OPERATOR,
153
+ TOKEN_PAREN_CLOSE,
154
+ TOKEN_PAREN_OPEN,
155
+ TOKEN_PERCENT,
156
+ TOKEN_STATEMENT_END,
157
+ TOKEN_STRING
158
+ } tokenType;
159
+
160
+ typedef enum eTagType {
161
+ TAG_UNDEFINED = -1,
162
+ TAG_BLOCK_DATA,
163
+ TAG_COMMON_BLOCK,
164
+ TAG_ENTRY_POINT,
165
+ TAG_FUNCTION,
166
+ TAG_INTERFACE,
167
+ TAG_COMPONENT,
168
+ TAG_LABEL,
169
+ TAG_LOCAL,
170
+ TAG_MODULE,
171
+ TAG_NAMELIST,
172
+ TAG_PROGRAM,
173
+ TAG_SUBROUTINE,
174
+ TAG_DERIVED_TYPE,
175
+ TAG_VARIABLE,
176
+ TAG_COUNT /* must be last */
177
+ } tagType;
178
+
179
+ typedef struct sTokenInfo {
180
+ tokenType type;
181
+ keywordId keyword;
182
+ tagType tag;
183
+ vString* string;
184
+ struct sTokenInfo *secondary;
185
+ unsigned long lineNumber;
186
+ fpos_t filePosition;
187
+ } tokenInfo;
188
+
189
+ /*
190
+ * DATA DEFINITIONS
191
+ */
192
+
193
+ static langType Lang_fortran;
194
+ static jmp_buf Exception;
195
+ static int Ungetc;
196
+ static unsigned int Column;
197
+ static boolean FreeSourceForm;
198
+ static boolean ParsingString;
199
+ static tokenInfo *Parent;
200
+
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"}
217
+ };
218
+
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
222
+ *
223
+ * For the Compaq Fortran Reference Manual:
224
+ * http://h18009.www1.hp.com/fortran/docs/lrm/dflrm.htm
225
+ */
226
+
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 }
297
+ };
298
+
299
+ static struct {
300
+ unsigned int count;
301
+ unsigned int max;
302
+ tokenInfo* list;
303
+ } Ancestors = { 0, 0, NULL };
304
+
305
+ /*
306
+ * FUNCTION PROTOTYPES
307
+ */
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);
313
+
314
+ /*
315
+ * FUNCTION DEFINITIONS
316
+ */
317
+
318
+ static void ancestorPush (tokenInfo *const token)
319
+ {
320
+ enum { incrementalIncrease = 10 };
321
+ if (Ancestors.list == NULL)
322
+ {
323
+ Assert (Ancestors.max == 0);
324
+ Ancestors.count = 0;
325
+ Ancestors.max = incrementalIncrease;
326
+ Ancestors.list = xMalloc (Ancestors.max, tokenInfo);
327
+ }
328
+ else if (Ancestors.count == Ancestors.max)
329
+ {
330
+ Ancestors.max += incrementalIncrease;
331
+ Ancestors.list = xRealloc (Ancestors.list, Ancestors.max, tokenInfo);
332
+ }
333
+ Ancestors.list [Ancestors.count] = *token;
334
+ Ancestors.list [Ancestors.count].string = vStringNewCopy (token->string);
335
+ Ancestors.count++;
336
+ }
337
+
338
+ static void ancestorPop (void)
339
+ {
340
+ Assert (Ancestors.count > 0);
341
+ --Ancestors.count;
342
+ vStringDelete (Ancestors.list [Ancestors.count].string);
343
+
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;
350
+ }
351
+
352
+ static const tokenInfo* ancestorScope (void)
353
+ {
354
+ tokenInfo *result = NULL;
355
+ unsigned int i;
356
+ for (i = Ancestors.count ; i > 0 && result == NULL ; --i)
357
+ {
358
+ tokenInfo *const token = Ancestors.list + i - 1;
359
+ if (token->type == TOKEN_IDENTIFIER &&
360
+ token->tag != TAG_UNDEFINED && token->tag != TAG_INTERFACE)
361
+ result = token;
362
+ }
363
+ return result;
364
+ }
365
+
366
+ static const tokenInfo* ancestorTop (void)
367
+ {
368
+ Assert (Ancestors.count > 0);
369
+ return &Ancestors.list [Ancestors.count - 1];
370
+ }
371
+
372
+ #define ancestorCount() (Ancestors.count)
373
+
374
+ static void ancestorClear (void)
375
+ {
376
+ while (Ancestors.count > 0)
377
+ ancestorPop ();
378
+ if (Ancestors.list != NULL)
379
+ eFree (Ancestors.list);
380
+ Ancestors.list = NULL;
381
+ Ancestors.count = 0;
382
+ Ancestors.max = 0;
383
+ }
384
+
385
+ static boolean insideInterface (void)
386
+ {
387
+ boolean result = FALSE;
388
+ unsigned int i;
389
+ for (i = 0 ; i < Ancestors.count && !result ; ++i)
390
+ {
391
+ if (Ancestors.list [i].tag == TAG_INTERFACE)
392
+ result = TRUE;
393
+ }
394
+ return result;
395
+ }
396
+
397
+ static void buildFortranKeywordHash (void)
398
+ {
399
+ const size_t count =
400
+ sizeof (FortranKeywordTable) / sizeof (FortranKeywordTable [0]);
401
+ size_t i;
402
+ for (i = 0 ; i < count ; ++i)
403
+ {
404
+ const keywordDesc* const p = &FortranKeywordTable [i];
405
+ addKeyword (p->name, Lang_fortran, (int) p->id);
406
+ }
407
+ }
408
+
409
+ /*
410
+ * Tag generation functions
411
+ */
412
+
413
+ static tokenInfo *newToken (void)
414
+ {
415
+ tokenInfo *const token = xMalloc (1, tokenInfo);
416
+
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 ();
424
+
425
+ return token;
426
+ }
427
+
428
+ static tokenInfo *newTokenFrom (tokenInfo *const token)
429
+ {
430
+ tokenInfo *result = newToken ();
431
+ *result = *token;
432
+ result->string = vStringNewCopy (token->string);
433
+ token->secondary = NULL;
434
+ return result;
435
+ }
436
+
437
+ static void deleteToken (tokenInfo *const token)
438
+ {
439
+ if (token != NULL)
440
+ {
441
+ vStringDelete (token->string);
442
+ deleteToken (token->secondary);
443
+ token->secondary = NULL;
444
+ eFree (token);
445
+ }
446
+ }
447
+
448
+ static boolean isFileScope (const tagType type)
449
+ {
450
+ return (boolean) (type == TAG_LABEL || type == TAG_LOCAL);
451
+ }
452
+
453
+ static boolean includeTag (const tagType type)
454
+ {
455
+ boolean include;
456
+ Assert (type != TAG_UNDEFINED);
457
+ include = FortranKinds [(int) type].enabled;
458
+ if (include && isFileScope (type))
459
+ include = Option.include.fileScope;
460
+ return include;
461
+ }
462
+
463
+ static void makeFortranTag (tokenInfo *const token, tagType tag)
464
+ {
465
+ token->tag = tag;
466
+ if (includeTag (token->tag))
467
+ {
468
+ const char *const name = vStringValue (token->string);
469
+ tagEntryInfo e;
470
+
471
+ initTagEntry (&e, name);
472
+
473
+ if (token->tag == TAG_COMMON_BLOCK)
474
+ e.lineNumberEntry = (boolean) (Option.locate != EX_PATTERN);
475
+
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);
482
+
483
+ if (ancestorCount () > 0)
484
+ {
485
+ const tokenInfo* const scope = ancestorScope ();
486
+ if (scope != NULL)
487
+ {
488
+ e.extensionFields.scope [0] = FortranKinds [scope->tag].name;
489
+ e.extensionFields.scope [1] = vStringValue (scope->string);
490
+ }
491
+ }
492
+ if (! insideInterface () || includeTag (TAG_INTERFACE))
493
+ makeTagEntry (&e);
494
+ }
495
+ }
496
+
497
+ /*
498
+ * Parsing functions
499
+ */
500
+
501
+ static int skipLine (void)
502
+ {
503
+ int c;
504
+
505
+ do
506
+ c = fileGetc ();
507
+ while (c != EOF && c != '\n');
508
+
509
+ return c;
510
+ }
511
+
512
+ static void makeLabelTag (vString *const label)
513
+ {
514
+ tokenInfo *token = newToken ();
515
+ token->type = TOKEN_LABEL;
516
+ vStringCopy (token->string, label);
517
+ makeFortranTag (token, TAG_LABEL);
518
+ deleteToken (token);
519
+ }
520
+
521
+ static lineType getLineType (void)
522
+ {
523
+ vString *label = vStringNew ();
524
+ int column = 0;
525
+ lineType type = LTYPE_UNDETERMINED;
526
+
527
+ do /* read in first 6 "margin" characters */
528
+ {
529
+ int c = fileGetc ();
530
+
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.
536
+ */
537
+ /* EXCEPTION! Some compilers permit '!' as a commment character here.
538
+ *
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.
541
+ */
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 */
545
+ {
546
+ column = 8;
547
+ type = LTYPE_INITIAL;
548
+ }
549
+ else if (column == 5)
550
+ {
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
555
+ * character blank.
556
+ */
557
+ if (c == ' ' || c == '0')
558
+ type = LTYPE_INITIAL;
559
+
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.
564
+ */
565
+ else if (vStringLength (label) == 0)
566
+ type = LTYPE_CONTINUATION;
567
+ else
568
+ type = LTYPE_INVALID;
569
+ }
570
+ else if (c == ' ')
571
+ ;
572
+ else if (c == EOF)
573
+ type = LTYPE_EOF;
574
+ else if (c == '\n')
575
+ type = LTYPE_SHORT;
576
+ else if (isdigit (c))
577
+ vStringPut (label, c);
578
+ else
579
+ type = LTYPE_INVALID;
580
+
581
+ ++column;
582
+ } while (column < 6 && type == LTYPE_UNDETERMINED);
583
+
584
+ Assert (type != LTYPE_UNDETERMINED);
585
+
586
+ if (vStringLength (label) > 0)
587
+ {
588
+ vStringTerminate (label);
589
+ makeLabelTag (label);
590
+ }
591
+ vStringDelete (label);
592
+ return type;
593
+ }
594
+
595
+ static int getFixedFormChar (void)
596
+ {
597
+ boolean newline = FALSE;
598
+ lineType type;
599
+ int c = '\0';
600
+
601
+ if (Column > 0)
602
+ {
603
+ #ifdef STRICT_FIXED_FORM
604
+ /* EXCEPTION! Some compilers permit more than 72 characters per line.
605
+ */
606
+ if (Column > 71)
607
+ c = skipLine ();
608
+ else
609
+ #endif
610
+ {
611
+ c = fileGetc ();
612
+ ++Column;
613
+ }
614
+ if (c == '\n')
615
+ {
616
+ newline = TRUE; /* need to check for continuation line */
617
+ Column = 0;
618
+ }
619
+ else if (c == '!' && ! ParsingString)
620
+ {
621
+ c = skipLine ();
622
+ newline = TRUE; /* need to check for continuation line */
623
+ Column = 0;
624
+ }
625
+ else if (c == '&') /* check for free source form */
626
+ {
627
+ const int c2 = fileGetc ();
628
+ if (c2 == '\n')
629
+ longjmp (Exception, (int) ExceptionFixedFormat);
630
+ else
631
+ fileUngetc (c2);
632
+ }
633
+ }
634
+ while (Column == 0)
635
+ {
636
+ type = getLineType ();
637
+ switch (type)
638
+ {
639
+ case LTYPE_UNDETERMINED:
640
+ case LTYPE_INVALID:
641
+ longjmp (Exception, (int) ExceptionFixedFormat);
642
+ break;
643
+
644
+ case LTYPE_SHORT: break;
645
+ case LTYPE_COMMENT: skipLine (); break;
646
+
647
+ case LTYPE_EOF:
648
+ Column = 6;
649
+ if (newline)
650
+ c = '\n';
651
+ else
652
+ c = EOF;
653
+ break;
654
+
655
+ case LTYPE_INITIAL:
656
+ if (newline)
657
+ {
658
+ c = '\n';
659
+ Column = 6;
660
+ break;
661
+ }
662
+ /* fall through to next case */
663
+ case LTYPE_CONTINUATION:
664
+ Column = 5;
665
+ do
666
+ {
667
+ c = fileGetc ();
668
+ ++Column;
669
+ } while (isBlank (c));
670
+ if (c == '\n')
671
+ Column = 0;
672
+ else if (Column > 6)
673
+ {
674
+ fileUngetc (c);
675
+ c = ' ';
676
+ }
677
+ break;
678
+
679
+ default:
680
+ Assert ("Unexpected line type" == NULL);
681
+ }
682
+ }
683
+ return c;
684
+ }
685
+
686
+ static int skipToNextLine (void)
687
+ {
688
+ int c = skipLine ();
689
+ if (c != EOF)
690
+ c = fileGetc ();
691
+ return c;
692
+ }
693
+
694
+ static int getFreeFormChar (void)
695
+ {
696
+ static boolean newline = TRUE;
697
+ boolean advanceLine = FALSE;
698
+ int c = fileGetc ();
699
+
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.
703
+ */
704
+ if (c == '&')
705
+ {
706
+ do
707
+ c = fileGetc ();
708
+ while (isspace (c) && c != '\n');
709
+ if (c == '\n')
710
+ {
711
+ newline = TRUE;
712
+ advanceLine = TRUE;
713
+ }
714
+ else if (c == '!')
715
+ advanceLine = TRUE;
716
+ else
717
+ {
718
+ fileUngetc (c);
719
+ c = '&';
720
+ }
721
+ }
722
+ else if (newline && (c == '!' || c == '#'))
723
+ advanceLine = TRUE;
724
+ while (advanceLine)
725
+ {
726
+ while (isspace (c))
727
+ c = fileGetc ();
728
+ if (c == '!' || (newline && c == '#'))
729
+ {
730
+ c = skipToNextLine ();
731
+ newline = TRUE;
732
+ continue;
733
+ }
734
+ if (c == '&')
735
+ c = fileGetc ();
736
+ else
737
+ advanceLine = FALSE;
738
+ }
739
+ newline = (boolean) (c == '\n');
740
+ return c;
741
+ }
742
+
743
+ static int getChar (void)
744
+ {
745
+ int c;
746
+
747
+ if (Ungetc != '\0')
748
+ {
749
+ c = Ungetc;
750
+ Ungetc = '\0';
751
+ }
752
+ else if (FreeSourceForm)
753
+ c = getFreeFormChar ();
754
+ else
755
+ c = getFixedFormChar ();
756
+ return c;
757
+ }
758
+
759
+ static void ungetChar (const int c)
760
+ {
761
+ Ungetc = c;
762
+ }
763
+
764
+ /* If a numeric is passed in 'c', this is used as the first digit of the
765
+ * numeric being parsed.
766
+ */
767
+ static vString *parseInteger (int c)
768
+ {
769
+ vString *string = vStringNew ();
770
+
771
+ if (c == '-')
772
+ {
773
+ vStringPut (string, c);
774
+ c = getChar ();
775
+ }
776
+ else if (! isdigit (c))
777
+ c = getChar ();
778
+ while (c != EOF && isdigit (c))
779
+ {
780
+ vStringPut (string, c);
781
+ c = getChar ();
782
+ }
783
+ vStringTerminate (string);
784
+
785
+ if (c == '_')
786
+ {
787
+ do
788
+ c = getChar ();
789
+ while (c != EOF && isalpha (c));
790
+ }
791
+ ungetChar (c);
792
+
793
+ return string;
794
+ }
795
+
796
+ static vString *parseNumeric (int c)
797
+ {
798
+ vString *string = vStringNew ();
799
+ vString *integer = parseInteger (c);
800
+ vStringCopy (string, integer);
801
+ vStringDelete (integer);
802
+
803
+ c = getChar ();
804
+ if (c == '.')
805
+ {
806
+ integer = parseInteger ('\0');
807
+ vStringPut (string, c);
808
+ vStringCat (string, integer);
809
+ vStringDelete (integer);
810
+ c = getChar ();
811
+ }
812
+ if (tolower (c) == 'e')
813
+ {
814
+ integer = parseInteger ('\0');
815
+ vStringPut (string, c);
816
+ vStringCat (string, integer);
817
+ vStringDelete (integer);
818
+ }
819
+ else
820
+ ungetChar (c);
821
+
822
+ vStringTerminate (string);
823
+
824
+ return string;
825
+ }
826
+
827
+ static void parseString (vString *const string, const int delimiter)
828
+ {
829
+ const unsigned long inputLineNumber = getInputLineNumber ();
830
+ int c;
831
+ ParsingString = TRUE;
832
+ c = getChar ();
833
+ while (c != delimiter && c != '\n' && c != EOF)
834
+ {
835
+ vStringPut (string, c);
836
+ c = getChar ();
837
+ }
838
+ if (c == '\n' || c == EOF)
839
+ {
840
+ verbose ("%s: unterminated character string at line %lu\n",
841
+ getInputFileName (), inputLineNumber);
842
+ if (c == EOF)
843
+ longjmp (Exception, (int) ExceptionEOF);
844
+ else if (! FreeSourceForm)
845
+ longjmp (Exception, (int) ExceptionFixedFormat);
846
+ }
847
+ vStringTerminate (string);
848
+ ParsingString = FALSE;
849
+ }
850
+
851
+ /* Read a C identifier beginning with "firstChar" and places it into "name".
852
+ */
853
+ static void parseIdentifier (vString *const string, const int firstChar)
854
+ {
855
+ int c = firstChar;
856
+
857
+ do
858
+ {
859
+ vStringPut (string, c);
860
+ c = getChar ();
861
+ } while (isident (c));
862
+
863
+ vStringTerminate (string);
864
+ ungetChar (c); /* unget non-identifier character */
865
+ }
866
+
867
+ static void checkForLabel (void)
868
+ {
869
+ tokenInfo* token = NULL;
870
+ int length;
871
+ int c;
872
+
873
+ do
874
+ c = getChar ();
875
+ while (isBlank (c));
876
+
877
+ for (length = 0 ; isdigit (c) && length < 5 ; ++length)
878
+ {
879
+ if (token == NULL)
880
+ {
881
+ token = newToken ();
882
+ token->type = TOKEN_LABEL;
883
+ }
884
+ vStringPut (token->string, c);
885
+ c = getChar ();
886
+ }
887
+ if (length > 0 && token != NULL)
888
+ {
889
+ vStringTerminate (token->string);
890
+ makeFortranTag (token, TAG_LABEL);
891
+ deleteToken (token);
892
+ }
893
+ ungetChar (c);
894
+ }
895
+
896
+ static void readIdentifier (tokenInfo *const token, const int c)
897
+ {
898
+ parseIdentifier (token->string, c);
899
+ token->keyword = analyzeToken (token->string, Lang_fortran);
900
+ if (! isKeyword (token, KEYWORD_NONE))
901
+ token->type = TOKEN_KEYWORD;
902
+ else
903
+ {
904
+ token->type = TOKEN_IDENTIFIER;
905
+ if (strncmp (vStringValue (token->string), "end", 3) == 0)
906
+ {
907
+ vString *const sub = vStringNewInit (vStringValue (token->string) + 3);
908
+ const keywordId kw = analyzeToken (sub, Lang_fortran);
909
+ vStringDelete (sub);
910
+ if (kw != KEYWORD_NONE)
911
+ {
912
+ token->secondary = newToken ();
913
+ token->secondary->type = TOKEN_KEYWORD;
914
+ token->secondary->keyword = kw;
915
+ token->keyword = KEYWORD_end;
916
+ }
917
+ }
918
+ }
919
+ }
920
+
921
+ static void readToken (tokenInfo *const token)
922
+ {
923
+ int c;
924
+
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);
931
+
932
+ getNextChar:
933
+ c = getChar ();
934
+
935
+ token->lineNumber = getSourceLineNumber ();
936
+ token->filePosition = getInputFilePosition ();
937
+
938
+ switch (c)
939
+ {
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;
947
+
948
+ case '*':
949
+ case '/':
950
+ case '+':
951
+ case '-':
952
+ case '=':
953
+ case '<':
954
+ case '>':
955
+ {
956
+ const char *const operatorChars = "*/+=<>";
957
+ do {
958
+ vStringPut (token->string, c);
959
+ c = getChar ();
960
+ } while (strchr (operatorChars, c) != NULL);
961
+ ungetChar (c);
962
+ vStringTerminate (token->string);
963
+ token->type = TOKEN_OPERATOR;
964
+ break;
965
+ }
966
+
967
+ case '!':
968
+ if (FreeSourceForm)
969
+ {
970
+ do
971
+ c = getChar ();
972
+ while (c != '\n' && c != EOF);
973
+ }
974
+ else
975
+ {
976
+ skipLine ();
977
+ Column = 0;
978
+ }
979
+ /* fall through to newline case */
980
+ case '\n':
981
+ token->type = TOKEN_STATEMENT_END;
982
+ if (FreeSourceForm)
983
+ checkForLabel ();
984
+ break;
985
+
986
+ case '.':
987
+ parseIdentifier (token->string, c);
988
+ c = getChar ();
989
+ if (c == '.')
990
+ {
991
+ vStringPut (token->string, c);
992
+ vStringTerminate (token->string);
993
+ token->type = TOKEN_OPERATOR;
994
+ }
995
+ else
996
+ {
997
+ ungetChar (c);
998
+ token->type = TOKEN_UNDEFINED;
999
+ }
1000
+ break;
1001
+
1002
+ case '"':
1003
+ case '\'':
1004
+ parseString (token->string, c);
1005
+ token->type = TOKEN_STRING;
1006
+ break;
1007
+
1008
+ case ';':
1009
+ token->type = TOKEN_STATEMENT_END;
1010
+ break;
1011
+
1012
+ case ':':
1013
+ c = getChar ();
1014
+ if (c == ':')
1015
+ token->type = TOKEN_DOUBLE_COLON;
1016
+ else
1017
+ {
1018
+ ungetChar (c);
1019
+ token->type = TOKEN_UNDEFINED;
1020
+ }
1021
+ break;
1022
+
1023
+ default:
1024
+ if (isalpha (c))
1025
+ readIdentifier (token, c);
1026
+ else if (isdigit (c))
1027
+ {
1028
+ vString *numeric = parseNumeric (c);
1029
+ vStringCat (token->string, numeric);
1030
+ vStringDelete (numeric);
1031
+ token->type = TOKEN_NUMERIC;
1032
+ }
1033
+ else
1034
+ token->type = TOKEN_UNDEFINED;
1035
+ break;
1036
+ }
1037
+ }
1038
+
1039
+ static void readSubToken (tokenInfo *const token)
1040
+ {
1041
+ if (token->secondary == NULL)
1042
+ {
1043
+ token->secondary = newToken ();
1044
+ readToken (token->secondary);
1045
+ }
1046
+ }
1047
+
1048
+ /*
1049
+ * Scanning functions
1050
+ */
1051
+
1052
+ static void skipToToken (tokenInfo *const token, tokenType type)
1053
+ {
1054
+ while (! isType (token, type) && ! isType (token, TOKEN_STATEMENT_END) &&
1055
+ !(token->secondary != NULL && isType (token->secondary, TOKEN_STATEMENT_END)))
1056
+ readToken (token);
1057
+ }
1058
+
1059
+ static void skipPast (tokenInfo *const token, tokenType type)
1060
+ {
1061
+ skipToToken (token, type);
1062
+ if (! isType (token, TOKEN_STATEMENT_END))
1063
+ readToken (token);
1064
+ }
1065
+
1066
+ static void skipToNextStatement (tokenInfo *const token)
1067
+ {
1068
+ do
1069
+ {
1070
+ skipToToken (token, TOKEN_STATEMENT_END);
1071
+ readToken (token);
1072
+ } while (isType (token, TOKEN_STATEMENT_END));
1073
+ }
1074
+
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
1078
+ * statement.
1079
+ */
1080
+ static void skipOverParens (tokenInfo *const token)
1081
+ {
1082
+ int level = 0;
1083
+ do {
1084
+ if (isType (token, TOKEN_STATEMENT_END))
1085
+ break;
1086
+ else if (isType (token, TOKEN_PAREN_OPEN))
1087
+ ++level;
1088
+ else if (isType (token, TOKEN_PAREN_CLOSE))
1089
+ --level;
1090
+ readToken (token);
1091
+ } while (level > 0);
1092
+ }
1093
+
1094
+ static boolean isTypeSpec (tokenInfo *const token)
1095
+ {
1096
+ boolean result;
1097
+ switch (token->keyword)
1098
+ {
1099
+ case KEYWORD_byte:
1100
+ case KEYWORD_integer:
1101
+ case KEYWORD_real:
1102
+ case KEYWORD_double:
1103
+ case KEYWORD_complex:
1104
+ case KEYWORD_character:
1105
+ case KEYWORD_logical:
1106
+ case KEYWORD_record:
1107
+ case KEYWORD_type:
1108
+ result = TRUE;
1109
+ break;
1110
+ default:
1111
+ result = FALSE;
1112
+ break;
1113
+ }
1114
+ return result;
1115
+ }
1116
+
1117
+ static boolean isSubprogramPrefix (tokenInfo *const token)
1118
+ {
1119
+ boolean result;
1120
+ switch (token->keyword)
1121
+ {
1122
+ case KEYWORD_elemental:
1123
+ case KEYWORD_pure:
1124
+ case KEYWORD_recursive:
1125
+ case KEYWORD_stdcall:
1126
+ result = TRUE;
1127
+ break;
1128
+ default:
1129
+ result = FALSE;
1130
+ break;
1131
+ }
1132
+ return result;
1133
+ }
1134
+
1135
+ /* type-spec
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 )
1143
+ *
1144
+ * Note that INTEGER and REAL may be followed by "*N" where "N" is an integer
1145
+ */
1146
+ static void parseTypeSpec (tokenInfo *const token)
1147
+ {
1148
+ /* parse type-spec, leaving `token' at first token following type-spec */
1149
+ Assert (isTypeSpec (token));
1150
+ switch (token->keyword)
1151
+ {
1152
+ case KEYWORD_character:
1153
+ /* skip char-selector */
1154
+ readToken (token);
1155
+ if (isType (token, TOKEN_OPERATOR) &&
1156
+ strcmp (vStringValue (token->string), "*") == 0)
1157
+ readToken (token);
1158
+ if (isType (token, TOKEN_PAREN_OPEN))
1159
+ skipOverParens (token);
1160
+ else if (isType (token, TOKEN_NUMERIC))
1161
+ readToken (token);
1162
+ break;
1163
+
1164
+
1165
+ case KEYWORD_byte:
1166
+ case KEYWORD_complex:
1167
+ case KEYWORD_integer:
1168
+ case KEYWORD_logical:
1169
+ case KEYWORD_real:
1170
+ readToken (token);
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)
1175
+ {
1176
+ readToken (token);
1177
+ readToken (token);
1178
+ }
1179
+ break;
1180
+
1181
+ case KEYWORD_double:
1182
+ readToken (token);
1183
+ if (isKeyword (token, KEYWORD_complex) ||
1184
+ isKeyword (token, KEYWORD_precision))
1185
+ readToken (token);
1186
+ else
1187
+ skipToToken (token, TOKEN_STATEMENT_END);
1188
+ break;
1189
+
1190
+ case KEYWORD_record:
1191
+ readToken (token);
1192
+ if (isType (token, TOKEN_OPERATOR) &&
1193
+ strcmp (vStringValue (token->string), "/") == 0)
1194
+ {
1195
+ readToken (token); /* skip to structure name */
1196
+ readToken (token); /* skip to '/' */
1197
+ readToken (token); /* skip to variable name */
1198
+ }
1199
+ break;
1200
+
1201
+ case KEYWORD_type:
1202
+ readToken (token);
1203
+ if (isType (token, TOKEN_PAREN_OPEN))
1204
+ skipOverParens (token); /* skip type-name */
1205
+ else
1206
+ parseDerivedTypeDef (token);
1207
+ break;
1208
+
1209
+ default:
1210
+ skipToToken (token, TOKEN_STATEMENT_END);
1211
+ break;
1212
+ }
1213
+ }
1214
+
1215
+ static boolean skipStatementIfKeyword (tokenInfo *const token, keywordId keyword)
1216
+ {
1217
+ boolean result = FALSE;
1218
+ if (isKeyword (token, keyword))
1219
+ {
1220
+ result = TRUE;
1221
+ skipToNextStatement (token);
1222
+ }
1223
+ return result;
1224
+ }
1225
+
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] ::]
1230
+ *
1231
+ * attr-spec
1232
+ * is PARAMETER
1233
+ * or access-spec (is PUBLIC or PRIVATE)
1234
+ * or ALLOCATABLE
1235
+ * or DIMENSION ( array-spec )
1236
+ * or EXTERNAL
1237
+ * or INTENT ( intent-spec )
1238
+ * or INTRINSIC
1239
+ * or OPTIONAL
1240
+ * or POINTER
1241
+ * or SAVE
1242
+ * or TARGET
1243
+ *
1244
+ * component-attr-spec
1245
+ * is POINTER
1246
+ * or DIMENSION ( component-array-spec )
1247
+ */
1248
+ static void parseQualifierSpecList (tokenInfo *const token)
1249
+ {
1250
+ do
1251
+ {
1252
+ readToken (token); /* should be an attr-spec */
1253
+ switch (token->keyword)
1254
+ {
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:
1263
+ case KEYWORD_save:
1264
+ case KEYWORD_target:
1265
+ readToken (token);
1266
+ break;
1267
+
1268
+ case KEYWORD_dimension:
1269
+ case KEYWORD_intent:
1270
+ readToken (token);
1271
+ skipOverParens (token);
1272
+ break;
1273
+
1274
+ default: skipToToken (token, TOKEN_STATEMENT_END); break;
1275
+ }
1276
+ } while (isType (token, TOKEN_COMMA));
1277
+ if (! isType (token, TOKEN_DOUBLE_COLON))
1278
+ skipToToken (token, TOKEN_STATEMENT_END);
1279
+ }
1280
+
1281
+ static tagType variableTagType (void)
1282
+ {
1283
+ tagType result = TAG_VARIABLE;
1284
+ if (ancestorCount () > 0)
1285
+ {
1286
+ const tokenInfo* const parent = ancestorTop ();
1287
+ switch (parent->tag)
1288
+ {
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;
1294
+ }
1295
+ }
1296
+ return result;
1297
+ }
1298
+
1299
+ static void parseEntityDecl (tokenInfo *const token)
1300
+ {
1301
+ Assert (isType (token, TOKEN_IDENTIFIER));
1302
+ makeFortranTag (token, variableTagType ());
1303
+ readToken (token);
1304
+ if (isType (token, TOKEN_PAREN_OPEN))
1305
+ skipOverParens (token);
1306
+ if (isType (token, TOKEN_OPERATOR) &&
1307
+ strcmp (vStringValue (token->string), "*") == 0)
1308
+ {
1309
+ readToken (token); /* read char-length */
1310
+ if (isType (token, TOKEN_PAREN_OPEN))
1311
+ skipOverParens (token);
1312
+ else
1313
+ readToken (token);
1314
+ }
1315
+ if (isType (token, TOKEN_OPERATOR))
1316
+ {
1317
+ if (strcmp (vStringValue (token->string), "/") == 0)
1318
+ { /* skip over initializations of structure field */
1319
+ readToken (token);
1320
+ skipPast (token, TOKEN_OPERATOR);
1321
+ }
1322
+ else if (strcmp (vStringValue (token->string), "=") == 0)
1323
+ {
1324
+ while (! isType (token, TOKEN_COMMA) &&
1325
+ ! isType (token, TOKEN_STATEMENT_END))
1326
+ {
1327
+ readToken (token);
1328
+ if (isType (token, TOKEN_PAREN_OPEN))
1329
+ skipOverParens (token);
1330
+ }
1331
+ }
1332
+ }
1333
+ /* token left at either comma or statement end */
1334
+ }
1335
+
1336
+ static void parseEntityDeclList (tokenInfo *const token)
1337
+ {
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)))
1344
+ {
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))
1350
+ readToken (token);
1351
+ else if (isType (token, TOKEN_STATEMENT_END))
1352
+ {
1353
+ skipToNextStatement (token);
1354
+ break;
1355
+ }
1356
+ }
1357
+ }
1358
+
1359
+ /* type-declaration-stmt is
1360
+ * type-spec [[, attr-spec] ... ::] entity-decl-list
1361
+ */
1362
+ static void parseTypeDeclarationStmt (tokenInfo *const token)
1363
+ {
1364
+ Assert (isTypeSpec (token));
1365
+ parseTypeSpec (token);
1366
+ if (!isType (token, TOKEN_STATEMENT_END)) /* if not end of derived type... */
1367
+ {
1368
+ if (isType (token, TOKEN_COMMA))
1369
+ parseQualifierSpecList (token);
1370
+ if (isType (token, TOKEN_DOUBLE_COLON))
1371
+ readToken (token);
1372
+ parseEntityDeclList (token);
1373
+ }
1374
+ if (isType (token, TOKEN_STATEMENT_END))
1375
+ skipToNextStatement (token);
1376
+ }
1377
+
1378
+ /* namelist-stmt is
1379
+ * NAMELIST /namelist-group-name/ namelist-group-object-list
1380
+ * [[,]/[namelist-group-name]/ namelist-block-object-list] ...
1381
+ *
1382
+ * namelist-group-object is
1383
+ * variable-name
1384
+ *
1385
+ * common-stmt is
1386
+ * COMMON [/[common-block-name]/] common-block-object-list
1387
+ * [[,]/[common-block-name]/ common-block-object-list] ...
1388
+ *
1389
+ * common-block-object is
1390
+ * variable-name [ ( explicit-shape-spec-list ) ]
1391
+ */
1392
+ static void parseCommonNamelistStmt (tokenInfo *const token, tagType type)
1393
+ {
1394
+ Assert (isKeyword (token, KEYWORD_common) ||
1395
+ isKeyword (token, KEYWORD_namelist));
1396
+ readToken (token);
1397
+ do
1398
+ {
1399
+ if (isType (token, TOKEN_OPERATOR) &&
1400
+ strcmp (vStringValue (token->string), "/") == 0)
1401
+ {
1402
+ readToken (token);
1403
+ if (isType (token, TOKEN_IDENTIFIER))
1404
+ {
1405
+ makeFortranTag (token, type);
1406
+ readToken (token);
1407
+ }
1408
+ skipPast (token, TOKEN_OPERATOR);
1409
+ }
1410
+ if (isType (token, TOKEN_IDENTIFIER))
1411
+ makeFortranTag (token, TAG_LOCAL);
1412
+ readToken (token);
1413
+ if (isType (token, TOKEN_PAREN_OPEN))
1414
+ skipOverParens (token); /* skip explicit-shape-spec-list */
1415
+ if (isType (token, TOKEN_COMMA))
1416
+ readToken (token);
1417
+ } while (! isType (token, TOKEN_STATEMENT_END));
1418
+ skipToNextStatement (token);
1419
+ }
1420
+
1421
+ static void parseFieldDefinition (tokenInfo *const token)
1422
+ {
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);
1429
+ else
1430
+ skipToNextStatement (token);
1431
+ }
1432
+
1433
+ static void parseMap (tokenInfo *const token)
1434
+ {
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);
1442
+ }
1443
+
1444
+ /* UNION
1445
+ * MAP
1446
+ * [field-definition] [field-definition] ...
1447
+ * END MAP
1448
+ * MAP
1449
+ * [field-definition] [field-definition] ...
1450
+ * END MAP
1451
+ * [MAP
1452
+ * [field-definition]
1453
+ * [field-definition] ...
1454
+ * END MAP] ...
1455
+ * END UNION
1456
+ * *
1457
+ *
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.
1461
+ *
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.
1465
+ *
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
1470
+ * that field.
1471
+ */
1472
+ static void parseUnionStmt (tokenInfo *const token)
1473
+ {
1474
+ Assert (isKeyword (token, KEYWORD_union));
1475
+ skipToNextStatement (token);
1476
+ while (isKeyword (token, KEYWORD_map))
1477
+ parseMap (token);
1478
+ /* should be at KEYWORD_end token */
1479
+ readSubToken (token);
1480
+ /* secondary token should be KEYWORD_end token */
1481
+ skipToNextStatement (token);
1482
+ }
1483
+
1484
+ /* STRUCTURE [/structure-name/] [field-names]
1485
+ * [field-definition]
1486
+ * [field-definition] ...
1487
+ * END STRUCTURE
1488
+ *
1489
+ * structure-name
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.
1493
+ *
1494
+ * field-names
1495
+ * (for substructure declarations only) one or more names having the
1496
+ * structure of the substructure being defined.
1497
+ *
1498
+ * field-definition
1499
+ * can be one or more of the following:
1500
+ *
1501
+ * Typed data declarations, which can optionally include one or more
1502
+ * data initialization values.
1503
+ *
1504
+ * Substructure declarations (defined by either RECORD statements or
1505
+ * subsequent STRUCTURE statements).
1506
+ *
1507
+ * UNION declarations, which are mapped fields defined by a block of
1508
+ * statements. The syntax of a UNION declaration is described below.
1509
+ *
1510
+ * PARAMETER statements, which do not affect the form of the
1511
+ * structure.
1512
+ */
1513
+ static void parseStructureStmt (tokenInfo *const token)
1514
+ {
1515
+ tokenInfo *name;
1516
+ Assert (isKeyword (token, KEYWORD_structure));
1517
+ readToken (token);
1518
+ if (isType (token, TOKEN_OPERATOR) &&
1519
+ strcmp (vStringValue (token->string), "/") == 0)
1520
+ { /* read structure name */
1521
+ readToken (token);
1522
+ if (isType (token, TOKEN_IDENTIFIER))
1523
+ makeFortranTag (token, TAG_DERIVED_TYPE);
1524
+ name = newTokenFrom (token);
1525
+ skipPast (token, TOKEN_OPERATOR);
1526
+ }
1527
+ else
1528
+ { /* fake out anonymous structure */
1529
+ name = newToken ();
1530
+ name->type = TOKEN_IDENTIFIER;
1531
+ name->tag = TAG_DERIVED_TYPE;
1532
+ vStringCopyS (name->string, "anonymous");
1533
+ }
1534
+ while (isType (token, TOKEN_IDENTIFIER))
1535
+ { /* read field names */
1536
+ makeFortranTag (token, TAG_COMPONENT);
1537
+ readToken (token);
1538
+ if (isType (token, TOKEN_COMMA))
1539
+ readToken (token);
1540
+ }
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);
1548
+ ancestorPop ();
1549
+ deleteToken (name);
1550
+ }
1551
+
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.)
1567
+ *
1568
+ * access-spec is PUBLIC or PRIVATE
1569
+ */
1570
+ static boolean parseSpecificationStmt (tokenInfo *const token)
1571
+ {
1572
+ boolean result = TRUE;
1573
+ switch (token->keyword)
1574
+ {
1575
+ case KEYWORD_common:
1576
+ parseCommonNamelistStmt (token, TAG_COMMON_BLOCK);
1577
+ break;
1578
+
1579
+ case KEYWORD_namelist:
1580
+ parseCommonNamelistStmt (token, TAG_NAMELIST);
1581
+ break;
1582
+
1583
+ case KEYWORD_structure:
1584
+ parseStructureStmt (token);
1585
+ break;
1586
+
1587
+ case KEYWORD_allocatable:
1588
+ case KEYWORD_data:
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:
1598
+ case KEYWORD_save:
1599
+ case KEYWORD_target:
1600
+ skipToNextStatement (token);
1601
+ break;
1602
+
1603
+ default:
1604
+ result = FALSE;
1605
+ break;
1606
+ }
1607
+ return result;
1608
+ }
1609
+
1610
+ /* component-def-stmt is
1611
+ * type-spec [[, component-attr-spec-list] ::] component-decl-list
1612
+ *
1613
+ * component-decl is
1614
+ * component-name [ ( component-array-spec ) ] [ * char-length ]
1615
+ */
1616
+ static void parseComponentDefStmt (tokenInfo *const token)
1617
+ {
1618
+ Assert (isTypeSpec (token));
1619
+ parseTypeSpec (token);
1620
+ if (isType (token, TOKEN_COMMA))
1621
+ parseQualifierSpecList (token);
1622
+ if (isType (token, TOKEN_DOUBLE_COLON))
1623
+ readToken (token);
1624
+ parseEntityDeclList (token);
1625
+ }
1626
+
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] ...
1632
+ * end-type-stmt
1633
+ */
1634
+ static void parseDerivedTypeDef (tokenInfo *const token)
1635
+ {
1636
+ if (isType (token, TOKEN_COMMA))
1637
+ parseQualifierSpecList (token);
1638
+ if (isType (token, TOKEN_DOUBLE_COLON))
1639
+ readToken (token);
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))
1646
+ {
1647
+ skipToNextStatement (token);
1648
+ }
1649
+ while (! isKeyword (token, KEYWORD_end))
1650
+ {
1651
+ if (isTypeSpec (token))
1652
+ parseComponentDefStmt (token);
1653
+ else
1654
+ skipToNextStatement (token);
1655
+ }
1656
+ readSubToken (token);
1657
+ /* secondary token should be KEYWORD_type token */
1658
+ skipToToken (token, TOKEN_STATEMENT_END);
1659
+ ancestorPop ();
1660
+ }
1661
+
1662
+ /* interface-block
1663
+ * interface-stmt (is INTERFACE [generic-spec])
1664
+ * [interface-body]
1665
+ * [module-procedure-stmt] ...
1666
+ * end-interface-stmt (is END INTERFACE)
1667
+ *
1668
+ * generic-spec
1669
+ * is generic-name
1670
+ * or OPERATOR ( defined-operator )
1671
+ * or ASSIGNMENT ( = )
1672
+ *
1673
+ * interface-body
1674
+ * is function-stmt
1675
+ * [specification-part]
1676
+ * end-function-stmt
1677
+ * or subroutine-stmt
1678
+ * [specification-part]
1679
+ * end-subroutine-stmt
1680
+ *
1681
+ * module-procedure-stmt is
1682
+ * MODULE PROCEDURE procedure-name-list
1683
+ */
1684
+ static void parseInterfaceBlock (tokenInfo *const token)
1685
+ {
1686
+ tokenInfo *name = NULL;
1687
+ Assert (isKeyword (token, KEYWORD_interface));
1688
+ readToken (token);
1689
+ if (isType (token, TOKEN_IDENTIFIER))
1690
+ {
1691
+ makeFortranTag (token, TAG_INTERFACE);
1692
+ name = newTokenFrom (token);
1693
+ }
1694
+ else if (isKeyword (token, KEYWORD_assignment) ||
1695
+ isKeyword (token, KEYWORD_operator))
1696
+ {
1697
+ readToken (token);
1698
+ if (isType (token, TOKEN_PAREN_OPEN))
1699
+ readToken (token);
1700
+ if (isType (token, TOKEN_OPERATOR))
1701
+ {
1702
+ makeFortranTag (token, TAG_INTERFACE);
1703
+ name = newTokenFrom (token);
1704
+ }
1705
+ }
1706
+ if (name == NULL)
1707
+ {
1708
+ name = newToken ();
1709
+ name->type = TOKEN_IDENTIFIER;
1710
+ name->tag = TAG_INTERFACE;
1711
+ }
1712
+ ancestorPush (name);
1713
+ while (! isKeyword (token, KEYWORD_end))
1714
+ {
1715
+ switch (token->keyword)
1716
+ {
1717
+ case KEYWORD_function: parseFunctionSubprogram (token); break;
1718
+ case KEYWORD_subroutine: parseSubroutineSubprogram (token); break;
1719
+
1720
+ default:
1721
+ if (isSubprogramPrefix (token))
1722
+ readToken (token);
1723
+ else if (isTypeSpec (token))
1724
+ parseTypeSpec (token);
1725
+ else
1726
+ skipToNextStatement (token);
1727
+ break;
1728
+ }
1729
+ }
1730
+ readSubToken (token);
1731
+ /* secondary token should be KEYWORD_interface token */
1732
+ skipToNextStatement (token);
1733
+ ancestorPop ();
1734
+ deleteToken (name);
1735
+ }
1736
+
1737
+ /* entry-stmt is
1738
+ * ENTRY entry-name [ ( dummy-arg-list ) ]
1739
+ */
1740
+ static void parseEntryStmt (tokenInfo *const token)
1741
+ {
1742
+ Assert (isKeyword (token, KEYWORD_entry));
1743
+ readToken (token);
1744
+ if (isType (token, TOKEN_IDENTIFIER))
1745
+ makeFortranTag (token, TAG_ENTRY_POINT);
1746
+ skipToNextStatement (token);
1747
+ }
1748
+
1749
+ /* stmt-function-stmt is
1750
+ * function-name ([dummy-arg-name-list]) = scalar-expr
1751
+ */
1752
+ static boolean parseStmtFunctionStmt (tokenInfo *const token)
1753
+ {
1754
+ boolean result = FALSE;
1755
+ Assert (isType (token, TOKEN_IDENTIFIER));
1756
+ #if 0 /* cannot reliably parse this yet */
1757
+ makeFortranTag (token, TAG_FUNCTION);
1758
+ #endif
1759
+ readToken (token);
1760
+ if (isType (token, TOKEN_PAREN_OPEN))
1761
+ {
1762
+ skipOverParens (token);
1763
+ result = (boolean) (isType (token, TOKEN_OPERATOR) &&
1764
+ strcmp (vStringValue (token->string), "=") == 0);
1765
+ }
1766
+ skipToNextStatement (token);
1767
+ return result;
1768
+ }
1769
+
1770
+ static boolean isIgnoredDeclaration (tokenInfo *const token)
1771
+ {
1772
+ boolean result;
1773
+ switch (token->keyword)
1774
+ {
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:
1788
+ case KEYWORD_value:
1789
+ case KEYWORD_virtual:
1790
+ case KEYWORD_volatile:
1791
+ result = TRUE;
1792
+ break;
1793
+
1794
+ default:
1795
+ result = FALSE;
1796
+ break;
1797
+ }
1798
+ return result;
1799
+ }
1800
+
1801
+ /* declaration-construct
1802
+ * [derived-type-def]
1803
+ * [interface-block]
1804
+ * [type-declaration-stmt]
1805
+ * [specification-stmt]
1806
+ * [parameter-stmt] (is PARAMETER ( named-constant-def-list )
1807
+ * [format-stmt] (is FORMAT format-specification)
1808
+ * [entry-stmt]
1809
+ * [stmt-function-stmt]
1810
+ */
1811
+ static boolean parseDeclarationConstruct (tokenInfo *const token)
1812
+ {
1813
+ boolean result = TRUE;
1814
+ switch (token->keyword)
1815
+ {
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(); */
1820
+
1821
+ case KEYWORD_automatic:
1822
+ readToken (token);
1823
+ if (isTypeSpec (token))
1824
+ parseTypeDeclarationStmt (token);
1825
+ else
1826
+ skipToNextStatement (token);
1827
+ result = TRUE;
1828
+ break;
1829
+
1830
+ default:
1831
+ if (isIgnoredDeclaration (token))
1832
+ skipToNextStatement (token);
1833
+ else if (isTypeSpec (token))
1834
+ {
1835
+ parseTypeDeclarationStmt (token);
1836
+ result = TRUE;
1837
+ }
1838
+ else if (isType (token, TOKEN_IDENTIFIER))
1839
+ result = parseStmtFunctionStmt (token);
1840
+ else
1841
+ result = parseSpecificationStmt (token);
1842
+ break;
1843
+ }
1844
+ return result;
1845
+ }
1846
+
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.)
1852
+ */
1853
+ static boolean parseImplicitPartStmt (tokenInfo *const token)
1854
+ {
1855
+ boolean result = TRUE;
1856
+ switch (token->keyword)
1857
+ {
1858
+ case KEYWORD_entry: parseEntryStmt (token); break;
1859
+
1860
+ case KEYWORD_implicit:
1861
+ case KEYWORD_include:
1862
+ case KEYWORD_parameter:
1863
+ case KEYWORD_format:
1864
+ skipToNextStatement (token);
1865
+ break;
1866
+
1867
+ default: result = FALSE; break;
1868
+ }
1869
+ return result;
1870
+ }
1871
+
1872
+ /* specification-part is
1873
+ * [use-stmt] ... (is USE module-name etc.)
1874
+ * [implicit-part] (is [implicit-part-stmt] ... [implicit-stmt])
1875
+ * [declaration-construct] ...
1876
+ */
1877
+ static boolean parseSpecificationPart (tokenInfo *const token)
1878
+ {
1879
+ boolean result = FALSE;
1880
+ while (skipStatementIfKeyword (token, KEYWORD_use))
1881
+ result = TRUE;
1882
+ while (parseImplicitPartStmt (token))
1883
+ result = TRUE;
1884
+ while (parseDeclarationConstruct (token))
1885
+ result = TRUE;
1886
+ return result;
1887
+ }
1888
+
1889
+ /* block-data is
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]])
1893
+ */
1894
+ static void parseBlockData (tokenInfo *const token)
1895
+ {
1896
+ Assert (isKeyword (token, KEYWORD_block));
1897
+ readToken (token);
1898
+ if (isKeyword (token, KEYWORD_data))
1899
+ {
1900
+ readToken (token);
1901
+ if (isType (token, TOKEN_IDENTIFIER))
1902
+ makeFortranTag (token, TAG_BLOCK_DATA);
1903
+ }
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);
1912
+ ancestorPop ();
1913
+ }
1914
+
1915
+ /* internal-subprogram-part is
1916
+ * contains-stmt (is CONTAINS)
1917
+ * internal-subprogram
1918
+ * [internal-subprogram] ...
1919
+ *
1920
+ * internal-subprogram
1921
+ * is function-subprogram
1922
+ * or subroutine-subprogram
1923
+ */
1924
+ static void parseInternalSubprogramPart (tokenInfo *const token)
1925
+ {
1926
+ boolean done = FALSE;
1927
+ if (isKeyword (token, KEYWORD_contains))
1928
+ skipToNextStatement (token);
1929
+ do
1930
+ {
1931
+ switch (token->keyword)
1932
+ {
1933
+ case KEYWORD_function: parseFunctionSubprogram (token); break;
1934
+ case KEYWORD_subroutine: parseSubroutineSubprogram (token); break;
1935
+ case KEYWORD_end: done = TRUE; break;
1936
+
1937
+ default:
1938
+ if (isSubprogramPrefix (token))
1939
+ readToken (token);
1940
+ else if (isTypeSpec (token))
1941
+ parseTypeSpec (token);
1942
+ else
1943
+ readToken (token);
1944
+ break;
1945
+ }
1946
+ } while (! done);
1947
+ }
1948
+
1949
+ /* module is
1950
+ * module-stmt (is MODULE module-name)
1951
+ * [specification-part]
1952
+ * [module-subprogram-part]
1953
+ * end-module-stmt (is END [MODULE [module-name]])
1954
+ *
1955
+ * module-subprogram-part
1956
+ * contains-stmt (is CONTAINS)
1957
+ * module-subprogram
1958
+ * [module-subprogram] ...
1959
+ *
1960
+ * module-subprogram
1961
+ * is function-subprogram
1962
+ * or subroutine-subprogram
1963
+ */
1964
+ static void parseModule (tokenInfo *const token)
1965
+ {
1966
+ Assert (isKeyword (token, KEYWORD_module));
1967
+ readToken (token);
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);
1980
+ ancestorPop ();
1981
+ }
1982
+
1983
+ /* execution-part
1984
+ * executable-construct
1985
+ *
1986
+ * executable-contstruct is
1987
+ * execution-part-construct [execution-part-construct]
1988
+ *
1989
+ * execution-part-construct
1990
+ * is executable-construct
1991
+ * or format-stmt
1992
+ * or data-stmt
1993
+ * or entry-stmt
1994
+ */
1995
+ static boolean parseExecutionPart (tokenInfo *const token)
1996
+ {
1997
+ boolean result = FALSE;
1998
+ boolean done = FALSE;
1999
+ while (! done)
2000
+ {
2001
+ switch (token->keyword)
2002
+ {
2003
+ default:
2004
+ if (isSubprogramPrefix (token))
2005
+ readToken (token);
2006
+ else
2007
+ skipToNextStatement (token);
2008
+ result = TRUE;
2009
+ break;
2010
+
2011
+ case KEYWORD_entry:
2012
+ parseEntryStmt (token);
2013
+ result = TRUE;
2014
+ break;
2015
+
2016
+ case KEYWORD_contains:
2017
+ case KEYWORD_function:
2018
+ case KEYWORD_subroutine:
2019
+ done = TRUE;
2020
+ break;
2021
+
2022
+ case KEYWORD_end:
2023
+ readSubToken (token);
2024
+ if (isSecondaryKeyword (token, KEYWORD_do) ||
2025
+ isSecondaryKeyword (token, KEYWORD_if) ||
2026
+ isSecondaryKeyword (token, KEYWORD_select) ||
2027
+ isSecondaryKeyword (token, KEYWORD_where))
2028
+ {
2029
+ skipToNextStatement (token);
2030
+ result = TRUE;
2031
+ }
2032
+ else
2033
+ done = TRUE;
2034
+ break;
2035
+ }
2036
+ }
2037
+ return result;
2038
+ }
2039
+
2040
+ static void parseSubprogram (tokenInfo *const token, const tagType tag)
2041
+ {
2042
+ Assert (isKeyword (token, KEYWORD_program) ||
2043
+ isKeyword (token, KEYWORD_function) ||
2044
+ isKeyword (token, KEYWORD_subroutine));
2045
+ readToken (token);
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
2058
+ */
2059
+ skipToNextStatement (token);
2060
+ ancestorPop ();
2061
+ }
2062
+
2063
+
2064
+ /* function-subprogram is
2065
+ * function-stmt (is [prefix] FUNCTION function-name etc.)
2066
+ * [specification-part]
2067
+ * [execution-part]
2068
+ * [internal-subprogram-part]
2069
+ * end-function-stmt (is END [FUNCTION [function-name]])
2070
+ *
2071
+ * prefix
2072
+ * is type-spec [RECURSIVE]
2073
+ * or [RECURSIVE] type-spec
2074
+ */
2075
+ static void parseFunctionSubprogram (tokenInfo *const token)
2076
+ {
2077
+ parseSubprogram (token, TAG_FUNCTION);
2078
+ }
2079
+
2080
+ /* subroutine-subprogram is
2081
+ * subroutine-stmt (is [RECURSIVE] SUBROUTINE subroutine-name etc.)
2082
+ * [specification-part]
2083
+ * [execution-part]
2084
+ * [internal-subprogram-part]
2085
+ * end-subroutine-stmt (is END [SUBROUTINE [function-name]])
2086
+ */
2087
+ static void parseSubroutineSubprogram (tokenInfo *const token)
2088
+ {
2089
+ parseSubprogram (token, TAG_SUBROUTINE);
2090
+ }
2091
+
2092
+ /* main-program is
2093
+ * [program-stmt] (is PROGRAM program-name)
2094
+ * [specification-part]
2095
+ * [execution-part]
2096
+ * [internal-subprogram-part ]
2097
+ * end-program-stmt
2098
+ */
2099
+ static void parseMainProgram (tokenInfo *const token)
2100
+ {
2101
+ parseSubprogram (token, TAG_PROGRAM);
2102
+ }
2103
+
2104
+ /* program-unit
2105
+ * is main-program
2106
+ * or external-subprogram (is function-subprogram or subroutine-subprogram)
2107
+ * or module
2108
+ * or block-data
2109
+ */
2110
+ static void parseProgramUnit (tokenInfo *const token)
2111
+ {
2112
+ readToken (token);
2113
+ do
2114
+ {
2115
+ if (isType (token, TOKEN_STATEMENT_END))
2116
+ readToken (token);
2117
+ else switch (token->keyword)
2118
+ {
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;
2125
+
2126
+ default:
2127
+ if (isSubprogramPrefix (token))
2128
+ readToken (token);
2129
+ else
2130
+ {
2131
+ boolean one = parseSpecificationPart (token);
2132
+ boolean two = parseExecutionPart (token);
2133
+ if (! (one || two))
2134
+ readToken (token);
2135
+ }
2136
+ break;
2137
+ }
2138
+ } while (TRUE);
2139
+ }
2140
+
2141
+ static boolean findFortranTags (const unsigned int passCount)
2142
+ {
2143
+ tokenInfo *token;
2144
+ exception_t exception;
2145
+ boolean retry;
2146
+
2147
+ Assert (passCount < 3);
2148
+ Parent = newToken ();
2149
+ token = newToken ();
2150
+ FreeSourceForm = (boolean) (passCount > 1);
2151
+ Column = 0;
2152
+ exception = (exception_t) setjmp (Exception);
2153
+ if (exception == ExceptionEOF)
2154
+ retry = FALSE;
2155
+ else if (exception == ExceptionFixedFormat && ! FreeSourceForm)
2156
+ {
2157
+ verbose ("%s: not fixed source form; retry as free source form\n",
2158
+ getInputFileName ());
2159
+ retry = TRUE;
2160
+ }
2161
+ else
2162
+ {
2163
+ parseProgramUnit (token);
2164
+ retry = FALSE;
2165
+ }
2166
+ ancestorClear ();
2167
+ deleteToken (token);
2168
+ deleteToken (Parent);
2169
+
2170
+ return retry;
2171
+ }
2172
+
2173
+ static void initialize (const langType language)
2174
+ {
2175
+ Lang_fortran = language;
2176
+ buildFortranKeywordHash ();
2177
+ }
2178
+
2179
+ extern parserDefinition* FortranParser (void)
2180
+ {
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",
2185
+ #endif
2186
+ NULL
2187
+ };
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;
2194
+ return def;
2195
+ }
2196
+
2197
+ /* vi:set tabstop=4 shiftwidth=4: */