|
1 /* -*- mode: fundamental; indent-tabs-mode: 1; -*- */ |
|
2 /***************************************************************************** |
|
3 * Parser for Fortran90 F subset |
|
4 * |
|
5 * Copyright (C) by Anke Visser |
|
6 * based on the work of Dimitri van Heesch. |
|
7 * |
|
8 * Permission to use, copy, modify, and distribute this software and its |
|
9 * documentation under the terms of the GNU General Public License is hereby |
|
10 * granted. No representations are made about the suitability of this software |
|
11 * for any purpose. It is provided "as is" without express or implied warranty. |
|
12 * See the GNU General Public License for more details. |
|
13 * |
|
14 * Documents produced by Doxygen are derivative works derived from the |
|
15 * input used in their production; they are not affected by this license. |
|
16 * |
|
17 */ |
|
18 |
|
19 /* Developer notes. |
|
20 * |
|
21 * - Consider using startScope(), endScope() functions with module, program, |
|
22 * subroutine or any other scope in fortran program. |
|
23 * |
|
24 * - Symbol modifiers (attributes) are collected using SymbolModifiers |= operator during |
|
25 * substructure parsing. When substructure ends all modifiers are applied to actual |
|
26 * entries in applyModifiers() functions. |
|
27 * |
|
28 * - How case insensitiveness should be handled in code? |
|
29 * On one side we have arg->name and entry->name, on another side modifierMap[name]. |
|
30 * In entries and arguments case is the same as in code, in modifier map case is lowered and |
|
31 * then it is compared to lowered entry/argument names. |
|
32 * |
|
33 * - Do not like constructs like aa{BS} or {BS}bb. Should try to handle blank space |
|
34 * with separate rule?: It seems it is often necessary, because we may parse something like |
|
35 * "functionA" or "MyInterface". So constructs like `(^|[ \t])interface({BS_}{ID})?/[ \t\n]' |
|
36 * are desired. |
|
37 */ |
|
38 |
|
39 %{ |
|
40 |
|
41 #include <stdio.h> |
|
42 #include <stdlib.h> |
|
43 #include <assert.h> |
|
44 #include <ctype.h> |
|
45 |
|
46 #include "qtbc.h" |
|
47 #include <qarray.h> |
|
48 #include <qstack.h> |
|
49 #include <qregexp.h> |
|
50 #include <unistd.h> |
|
51 #include <qfile.h> |
|
52 #include <qmap.h> |
|
53 |
|
54 #include "fortranscanner.h" |
|
55 #include "entry.h" |
|
56 #include "message.h" |
|
57 #include "config.h" |
|
58 #include "doxygen.h" |
|
59 #include "util.h" |
|
60 #include "defargs.h" |
|
61 #include "language.h" |
|
62 #include "commentscan.h" |
|
63 #include "fortrancode.h" |
|
64 #include "pre.h" |
|
65 |
|
66 #define YY_NEVER_INTERACTIVE 1 |
|
67 |
|
68 enum ScanVar { V_IGNORE, V_VARIABLE, V_PARAMETER}; |
|
69 |
|
70 // {{{ ----- Helper structs ----- |
|
71 //! Holds modifiers (ie attributes) for one symbol (variable, function, etc) |
|
72 struct SymbolModifiers { |
|
73 enum Protection {NONE_P, PUBLIC, PRIVATE}; |
|
74 enum Direction {NONE_D, IN, OUT, INOUT}; |
|
75 |
|
76 //!< This is only used with function return value. |
|
77 QCString type, returnName; |
|
78 Protection protection; |
|
79 Direction direction; |
|
80 bool optional; |
|
81 QCString dimension; |
|
82 bool allocatable; |
|
83 bool external; |
|
84 bool intrinsic; |
|
85 bool parameter; |
|
86 bool pointer; |
|
87 bool target; |
|
88 bool save; |
|
89 |
|
90 SymbolModifiers() : type(), returnName(), protection(NONE_P), direction(NONE_D), |
|
91 optional(FALSE), dimension(), allocatable(FALSE), |
|
92 external(FALSE), intrinsic(FALSE), parameter(FALSE), |
|
93 pointer(FALSE), target(FALSE), save(FALSE) {} |
|
94 |
|
95 SymbolModifiers& operator|=(const SymbolModifiers &mdfs); |
|
96 SymbolModifiers& operator|=(QCString mdfrString); |
|
97 }; |
|
98 |
|
99 //ostream& operator<<(ostream& out, const SymbolModifiers& mdfs); |
|
100 |
|
101 static const char *directionStrs[] = |
|
102 { |
|
103 "", "intent(in)", "intent(out)", "intent(inout)" |
|
104 }; |
|
105 |
|
106 // }}} |
|
107 |
|
108 /* ----------------------------------------------------------------- |
|
109 * |
|
110 * statics |
|
111 */ |
|
112 static ParserInterface *g_thisParser; |
|
113 static const char * inputString; |
|
114 static int inputPosition; |
|
115 static bool isFixedForm; |
|
116 static QCString inputStringPrepass; ///< Input string for prepass of line cont. '&' |
|
117 static unsigned int inputPositionPrepass; |
|
118 static int lineCountPrepass = 0; |
|
119 |
|
120 struct CommentInPrepass { |
|
121 int column; |
|
122 QCString str; |
|
123 CommentInPrepass(int column, QCString str) : column(column), str(str) {} |
|
124 }; |
|
125 static QList<CommentInPrepass> comments; |
|
126 |
|
127 #define MAX_INCLUDE_DEPTH 10 |
|
128 YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH]; |
|
129 int include_stack_ptr = 0; |
|
130 |
|
131 static QFile inputFile; |
|
132 static QCString yyFileName; |
|
133 static int yyLineNr = 1 ; |
|
134 static Entry* current_root = 0 ; |
|
135 static Entry* global_root = 0 ; |
|
136 static Entry* file_root = 0 ; |
|
137 static Entry* current = 0 ; |
|
138 static Entry* last_entry = 0 ; |
|
139 static ScanVar v_type = V_IGNORE; // type of parsed variable |
|
140 static QList<Entry> moduleProcedures; // list of all interfaces which contain unresolved |
|
141 // module procedures |
|
142 static QCString docBlock; |
|
143 static QCString docBlockName; |
|
144 static bool docBlockInBody; |
|
145 static bool docBlockJavaStyle; |
|
146 |
|
147 static MethodTypes mtype; |
|
148 static bool gstat; |
|
149 static Specifier virt; |
|
150 |
|
151 static QCString debugStr; |
|
152 static QCString result; // function result |
|
153 static Argument *parameter; // element of parameter list |
|
154 static QCString argType; // fortran type of an argument of a parameter list |
|
155 static QCString argName; // last identifier name in variable list |
|
156 static QCString initializer; // initial value of a variable |
|
157 static int initializerScope; // number if nested array scopes in initializer |
|
158 static QCString useModuleName; // name of module in the use statement |
|
159 static Protection defaultProtection; |
|
160 |
|
161 static char stringStartSymbol; // single or double quote |
|
162 |
|
163 //! Accumulated modifiers of current statement, eg variable declaration. |
|
164 static SymbolModifiers currentModifiers; |
|
165 //! Holds program scope->symbol name->symbol modifiers. |
|
166 static QMap<Entry*,QMap<QCString,SymbolModifiers> > modifiers; |
|
167 |
|
168 //----------------------------------------------------------------------------- |
|
169 |
|
170 static int yyread(char *buf,int max_size); |
|
171 static void startCommentBlock(bool); |
|
172 static void handleCommentBlock(const QCString &doc,bool brief); |
|
173 static void addCurrentEntry(); |
|
174 static void addModule(const char *name, bool isModule=FALSE); |
|
175 static void addSubprogram(const char *text); |
|
176 static void addInterface(QCString name); |
|
177 static Argument *addFortranParameter(const QCString &type,const QCString &name, const QCString docs); |
|
178 static void scanner_abort(); |
|
179 |
|
180 static void startScope(Entry *scope); |
|
181 static bool endScope(Entry *scope, bool isGlobalRoot=FALSE); |
|
182 static QCString getFullName(Entry *e); |
|
183 static bool isTypeName(QCString name); |
|
184 static void resolveModuleProcedures(QList<Entry> &moduleProcedures, Entry *current_root); |
|
185 static int getAmpersandAtTheStart(const char *buf, int length); |
|
186 static int getAmpOrExclAtTheEnd(const char *buf, int length); |
|
187 static void truncatePrepass(int index); |
|
188 static void pushBuffer(QCString &buffer); |
|
189 static void popBuffer(); |
|
190 static void extractPrefix(QCString& text); |
|
191 |
|
192 //----------------------------------------------------------------------------- |
|
193 #undef YY_INPUT |
|
194 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); |
|
195 //----------------------------------------------------------------------------- |
|
196 |
|
197 %} |
|
198 |
|
199 //----------------------------------------------------------------------------- |
|
200 //----------------------------------------------------------------------------- |
|
201 IDSYM [a-z_A-Z0-9] |
|
202 NOTIDSYM [^a-z_A-Z0-9] |
|
203 SEPARATE [:, \t] |
|
204 ID [a-z_A-Z%]+{IDSYM}* |
|
205 PP_ID {ID} |
|
206 LABELID [a-z_A-Z]+[a-z_A-Z0-9\-]* |
|
207 SUBPROG (subroutine|function|block) |
|
208 B [ \t] |
|
209 BS [ \t]* |
|
210 BS_ [ \t]+ |
|
211 COMMA {BS},{BS} |
|
212 ARGS {BS}("("[^)]*")") |
|
213 NOARGS {BS}"\n" |
|
214 |
|
215 NUM_TYPE (complex|integer|logical|real) |
|
216 KIND {ARGS} |
|
217 CHAR (CHARACTER{ARGS}?|CHARACTER{BS}"*"({BS}[0-9]+|{ARGS})) |
|
218 TYPE_SPEC (({NUM_TYPE}({BS}"*"{BS}[0-9]+)?)|({NUM_TYPE}{KIND})|DOUBLE{BS_}PRECISION|{CHAR}|TYPE{ARGS}) |
|
219 |
|
220 INTENT_SPEC intent{BS}"("{BS}(in|out|in{BS}out){BS}")" |
|
221 ATTR_SPEC (ALLOCATABLE|DIMENSION{ARGS}|EXTERNAL|{INTENT_SPEC}|INTRINSIC|OPTIONAL|PARAMETER|POINTER|PRIVATE|PUBLIC|SAVE|TARGET) |
|
222 ACCESS_SPEC (PRIVATE|PUBLIC) |
|
223 /* Assume that attribute statements are almost the same as attributes. */ |
|
224 ATTR_STMT {ATTR_SPEC}|DIMENSION|{ACCESS_SPEC} |
|
225 |
|
226 CONTAINS CONTAINS |
|
227 PREFIX (RECURSIVE{BS_}|PURE{BS_}|ELEMENTAL{BS_}){0,2}(RECURSIVE|PURE|ELEMENTAL)? |
|
228 |
|
229 %option noyywrap |
|
230 %option stack |
|
231 %option caseless |
|
232 /*%option debug */ |
|
233 |
|
234 //--------------------------------------------------------------------------------- |
|
235 |
|
236 /** fortran parsing states */ |
|
237 %x Subprog |
|
238 %x SubprogPrefix |
|
239 %x Parameterlist |
|
240 %x SubprogBody |
|
241 %x SubprogBodyContains |
|
242 %x Start |
|
243 %x Comment |
|
244 %x Module |
|
245 %x Program |
|
246 %x ModuleBody |
|
247 %x ModuleBodyContains |
|
248 %x AttributeList |
|
249 %x Variable |
|
250 %x Initialization |
|
251 %x ArrayInitializer |
|
252 %x Typedef |
|
253 %x TypedefBody |
|
254 %x InterfaceBody |
|
255 %x StrIgnore |
|
256 %x String |
|
257 %x Use |
|
258 %x UseOnly |
|
259 %x ModuleProcedure |
|
260 |
|
261 %x Prepass |
|
262 |
|
263 /** comment parsing states */ |
|
264 %x DocBlock |
|
265 %x DocBackLine |
|
266 %x EndDoc |
|
267 |
|
268 %% |
|
269 |
|
270 /*-----------------------------------------------------------------------------------*/ |
|
271 |
|
272 <*>^.*\n { // prepass: look for line continuations |
|
273 |
|
274 //fprintf(stderr, "---%s", yytext); |
|
275 |
|
276 int indexStart = getAmpersandAtTheStart(yytext, yyleng); |
|
277 int indexEnd = getAmpOrExclAtTheEnd(yytext, yyleng); |
|
278 if (indexEnd>=0 && yytext[indexEnd]!='&') //we are only interested in amp |
|
279 indexEnd=-1; |
|
280 |
|
281 if(indexEnd<0){ // ----- no ampersand as line continuation |
|
282 if(YY_START == Prepass) { // last line in "continuation" |
|
283 |
|
284 // Only take input after initial ampersand |
|
285 inputStringPrepass+=(const char*)(yytext+(indexStart+1)); |
|
286 |
|
287 pushBuffer(inputStringPrepass); |
|
288 yy_pop_state(); |
|
289 } else { // simple line |
|
290 REJECT; |
|
291 } |
|
292 |
|
293 } else { // ----- line with continuation |
|
294 if(YY_START != Prepass) { |
|
295 comments.setAutoDelete(TRUE); |
|
296 comments.clear(); |
|
297 yy_push_state(Prepass); |
|
298 } |
|
299 |
|
300 int length = inputStringPrepass.length(); |
|
301 |
|
302 // Only take input after initial ampersand |
|
303 inputStringPrepass+=(const char*)(yytext+(indexStart+1)); |
|
304 lineCountPrepass ++; |
|
305 |
|
306 // cut off & and remove following comment if present |
|
307 truncatePrepass(length+indexEnd-(indexStart+1)); |
|
308 } |
|
309 |
|
310 } |
|
311 |
|
312 |
|
313 /*------ ignore strings */ |
|
314 <*>"\\\\" { /* ignore \\ */} |
|
315 <*>"\\\""|\\\' { /* ignore \" and \' */} |
|
316 |
|
317 <String>\"|\' { // string ends with next quote without previous backspace |
|
318 if (yytext[0]!=stringStartSymbol) REJECT; // single vs double quote |
|
319 // fprintf(stderr,"string end: %s\n",debugStr.data()); |
|
320 yy_pop_state(); |
|
321 } |
|
322 |
|
323 <String>. { debugStr+=yytext; } // ignore String contents (especially '!') |
|
324 |
|
325 <*>\"|\' { /* string starts */ |
|
326 if (YY_START == StrIgnore) REJECT; // ignore in simple comments |
|
327 // fprintf(stderr,"string start: %c %d\n",yytext[0],yyLineNr); |
|
328 yy_push_state(YY_START); |
|
329 stringStartSymbol=yytext[0]; // single or double quote |
|
330 BEGIN(String); debugStr="!^!"; |
|
331 } |
|
332 |
|
333 /*------ ignore simple comment (not documentation comments) */ |
|
334 |
|
335 <*>"!"/[^<>\n] { if (YY_START == String) REJECT; // "!" is ignored in strings |
|
336 // skip comment line (without docu comments "!>" "!<" ) |
|
337 /* ignore further "!" and ignore comments in Strings */ |
|
338 if ((YY_START != StrIgnore) && (YY_START != String)) |
|
339 { |
|
340 yy_push_state(YY_START); |
|
341 BEGIN(StrIgnore); |
|
342 debugStr="*!"; |
|
343 //fprintf(stderr,"start comment %d\n",yyLineNr); |
|
344 } |
|
345 } |
|
346 <StrIgnore>.?/\n { yy_pop_state(); // comment ends with endline character |
|
347 //fprintf(stderr,"end comment %d %s\n",yyLineNr,debugStr.data()); |
|
348 } // comment line ends |
|
349 <StrIgnore>. { debugStr+=yytext; } |
|
350 |
|
351 |
|
352 /*------ use handling ------------------------------------------------------------*/ |
|
353 |
|
354 <Start,ModuleBody,TypedefBody,SubprogBody>"use"{BS_} { |
|
355 if(YY_START == Start) |
|
356 { |
|
357 addModule(NULL); |
|
358 yy_push_state(ModuleBody); //anon program |
|
359 } |
|
360 yy_push_state(Use); |
|
361 } |
|
362 <Use>{ID} { |
|
363 //fprintf(stderr,"using dir %s\n",yytext); |
|
364 current->name=yytext; |
|
365 current->fileName = yyFileName; |
|
366 current->section=Entry::USINGDIR_SEC; |
|
367 current_root->addSubEntry(current); |
|
368 current = new Entry; |
|
369 yy_pop_state(); |
|
370 } |
|
371 <Use>{ID}/, { |
|
372 useModuleName=yytext; |
|
373 } |
|
374 <Use>,{BS}"ONLY" { BEGIN(UseOnly); |
|
375 } |
|
376 <UseOnly>{BS},{BS} {} |
|
377 <UseOnly>{ID} { |
|
378 current->name= useModuleName+"::"+yytext; |
|
379 current->fileName = yyFileName; |
|
380 current->section=Entry::USINGDECL_SEC; |
|
381 current_root->addSubEntry(current); |
|
382 current = new Entry ; |
|
383 } |
|
384 <Use,UseOnly>"\n" { |
|
385 unput(*yytext); |
|
386 yy_pop_state(); |
|
387 } |
|
388 |
|
389 /*------ ignore special fortran statements */ |
|
390 <Start,ModuleBody,SubprogBody>^[ \t]*interface({BS_}{ID}({BS}\({BS}[^ \t()]+{BS}\))?)?/{BS}(!|\n) { // handle interface block |
|
391 if(YY_START == Start) |
|
392 { |
|
393 addModule(NULL); |
|
394 yy_push_state(ModuleBody); //anon program |
|
395 } |
|
396 |
|
397 QCString name = yytext; |
|
398 int index = name.find("interface", 0, FALSE); |
|
399 index = name.find(QRegExp("[^ \\t]"), index+9); |
|
400 //printf(stderr,"%s,%d\n",name.data(),index); |
|
401 if (index!=-1) |
|
402 name = name.right(name.length()-index); |
|
403 else // interface without name, must be inside subprog |
|
404 name = "interface"; |
|
405 addInterface(name); |
|
406 yy_push_state(InterfaceBody); |
|
407 startScope(last_entry); |
|
408 } |
|
409 <InterfaceBody>^{BS}"end"({BS}"interface"({BS_}{ID})?)?{BS}/(\n|!) { |
|
410 if (!endScope(current_root)) |
|
411 yyterminate(); |
|
412 yy_pop_state(); |
|
413 } |
|
414 <InterfaceBody>module{BS}procedure { yy_push_state(YY_START); |
|
415 BEGIN(ModuleProcedure); |
|
416 } |
|
417 <ModuleProcedure>{ID} { |
|
418 current->section = Entry::FUNCTION_SEC ; |
|
419 current->name = yytext; |
|
420 moduleProcedures.append(current); |
|
421 addCurrentEntry(); |
|
422 } |
|
423 <ModuleProcedure>"\n" { unput(*yytext); |
|
424 yy_pop_state(); |
|
425 } |
|
426 <InterfaceBody>. {} |
|
427 |
|
428 /*-- Contains handling --*/ |
|
429 <Start>^{BS}{CONTAINS}/({BS}|\n|!) { |
|
430 if(YY_START == Start) |
|
431 { |
|
432 addModule(NULL); |
|
433 yy_push_state(ModuleBodyContains); //anon program |
|
434 } |
|
435 } |
|
436 <ModuleBody>^{BS}{CONTAINS}/({BS}|\n|!) { BEGIN(ModuleBodyContains); } |
|
437 <SubprogBody>^{BS}{CONTAINS}/({BS}|\n|!) { BEGIN(SubprogBodyContains); } |
|
438 |
|
439 /*------ module handling ------------------------------------------------------------*/ |
|
440 <Start>module|program{BS_} { // |
|
441 if(yytext[0]=='m' || yytext[0]=='M') |
|
442 yy_push_state(Module); |
|
443 else |
|
444 yy_push_state(Program); |
|
445 defaultProtection = Public; |
|
446 } |
|
447 <Start,ModuleBody,ModuleBodyContains>^{BS}"end"({BS}(module|program)({BS_}{ID})?)?{BS}/(\n|!) { // end module |
|
448 resolveModuleProcedures(moduleProcedures, current_root); |
|
449 if (!endScope(current_root)) |
|
450 yyterminate(); |
|
451 defaultProtection = Public; |
|
452 yy_pop_state(); |
|
453 } |
|
454 <Module>{ID} { |
|
455 addModule(yytext, TRUE); |
|
456 BEGIN(ModuleBody); |
|
457 } |
|
458 |
|
459 <Program>{ID} { |
|
460 addModule(yytext, FALSE); |
|
461 BEGIN(ModuleBody); |
|
462 } |
|
463 |
|
464 /*------- access specification --------------------------------------------------------------------------*/ |
|
465 |
|
466 <ModuleBody>private/{BS}(\n|"!") { defaultProtection = Private; } |
|
467 <ModuleBody>public/{BS}(\n|"!") { defaultProtection = Public; } |
|
468 |
|
469 /*------- type definition -------------------------------------------------------------------------------*/ |
|
470 |
|
471 <Start,ModuleBody>"type"({BS_}|({COMMA}{ACCESS_SPEC})) { /* type definition found : TYPE , access-spec::type-name |*/ |
|
472 if(YY_START == Start) |
|
473 { |
|
474 addModule(NULL); |
|
475 yy_push_state(ModuleBody); //anon program |
|
476 } |
|
477 |
|
478 yy_push_state(Typedef); |
|
479 current->protection = defaultProtection; |
|
480 } |
|
481 <Typedef>{ACCESS_SPEC} { |
|
482 QCString type= yytext; |
|
483 } |
|
484 <Typedef>{ID} { /* type name found */ |
|
485 //cout << "=========> got typedef " << yytext << ": " << yyLineNr << endl; |
|
486 current->section = Entry::CLASS_SEC; // was Entry::STRUCT_SEC; |
|
487 current->spec = Entry::Struct; |
|
488 current->name = yytext; |
|
489 |
|
490 /* if type is part of a module, mod name is necessary for output */ |
|
491 if ((current_root) && |
|
492 (current_root->section == Entry::CLASS_SEC || |
|
493 current_root->section == Entry::NAMESPACE_SEC)) |
|
494 //current_root->section == Entry::INTERFACE_SEC)) |
|
495 { |
|
496 current->name= current_root->name+"::"+current->name; |
|
497 } |
|
498 current->fileName = yyFileName; |
|
499 current->bodyLine = yyLineNr; |
|
500 addCurrentEntry(); |
|
501 startScope(last_entry); |
|
502 BEGIN(TypedefBody); |
|
503 } |
|
504 <TypedefBody>^{BS}"end"{BS}"type"({BS_}{ID})?{BS}/(\n|!) { /* end type definition */ |
|
505 //printf("=========> got typedef end \n"); |
|
506 if (!endScope(current_root)) |
|
507 yyterminate(); |
|
508 yy_pop_state(); |
|
509 } |
|
510 |
|
511 /*------- module/global/typedef variable ---------------------------------------------------*/ |
|
512 |
|
513 <SubprogBody,SubprogBodyContains>^{BS}"end"({BS}{SUBPROG}({BS_}{ID})?)?{BS}/(\n|!) { |
|
514 //fprintf(stderr,"1e=========> got end subprog: %s\n", yytext); |
|
515 |
|
516 /* args is used for parameters in list of functions, argList for |
|
517 parameters in detailed function descripttion */ |
|
518 //current->args = argListToString(current->argList); |
|
519 //current->endBodyLine = yyLineNr; // ??? what ist endBodyLine for |
|
520 if (!endScope(current_root)) |
|
521 yyterminate(); |
|
522 yy_pop_state() ; |
|
523 } |
|
524 <Start,ModuleBody,TypedefBody,SubprogBody>{ |
|
525 ^{BS}{TYPE_SPEC}/{SEPARATE} { |
|
526 /* variable declaration starts */ |
|
527 if(YY_START == Start) |
|
528 { |
|
529 addModule(NULL); |
|
530 yy_push_state(ModuleBody); //anon program |
|
531 } |
|
532 //fprintf(stderr,"4=========> got variable type: %s\n",yytext); |
|
533 QCString help=yytext; |
|
534 help= help.simplifyWhiteSpace(); |
|
535 argType= help; |
|
536 yy_push_state(AttributeList); |
|
537 } |
|
538 ^{BS}{PP_ID}{KIND}? { /* check for preprocessor symbol expand to type */ |
|
539 QCString str = yytext; |
|
540 str = str.stripWhiteSpace(); |
|
541 DefineDict* defines = getFileDefineDict(); |
|
542 QCString name; |
|
543 int index = str.find("("); |
|
544 if (index != -1) |
|
545 name = str.left(index).stripWhiteSpace(); |
|
546 else |
|
547 name = str; |
|
548 |
|
549 Define *define = (*defines)[name]; |
|
550 if (define != 0 && isTypeName(define->definition)) |
|
551 { |
|
552 argType = str; |
|
553 yy_push_state(AttributeList); |
|
554 } |
|
555 else |
|
556 { |
|
557 REJECT; |
|
558 } |
|
559 } |
|
560 {ATTR_STMT}/{BS_}{ID} | |
|
561 {ATTR_STMT}/{BS}"::" { |
|
562 /* attribute statement starts */ |
|
563 //fprintf(stderr,"5=========> Attribute statement: %s\n", yytext); |
|
564 QCString tmp = yytext; |
|
565 currentModifiers |= tmp.stripWhiteSpace(); |
|
566 argType=""; |
|
567 yy_push_state(YY_START); |
|
568 BEGIN( AttributeList ) ; |
|
569 } |
|
570 {ID} { |
|
571 } |
|
572 } |
|
573 <AttributeList>{ |
|
574 {COMMA} {} |
|
575 {BS} {} |
|
576 {ATTR_SPEC} { /* update current modifiers */ |
|
577 QCString tmp = yytext; |
|
578 currentModifiers |= (tmp); |
|
579 } |
|
580 "::" { /* end attribute list */ |
|
581 BEGIN( Variable ); |
|
582 } |
|
583 . { /* unknown attribute, consider variable name */ |
|
584 //cout<<"start variables, unput "<<*yytext<<endl; |
|
585 unput(*yytext); |
|
586 BEGIN( Variable ); |
|
587 } |
|
588 } |
|
589 |
|
590 <Variable>{BS} {} |
|
591 <Variable>{ID} { /* parse variable declaration */ |
|
592 //cout << "5=========> got variable: " << argType << "::" << yytext << endl; |
|
593 /* work around for bug in QCString.replace (QCString works) */ |
|
594 QCString name=yytext; |
|
595 /* remember attributes for the symbol */ |
|
596 modifiers[current_root][name.lower()] |= currentModifiers; |
|
597 argName= name; |
|
598 |
|
599 v_type= V_IGNORE; |
|
600 if (!argType.isEmpty() && current_root->section!=Entry::FUNCTION_SEC) |
|
601 { // new variable entry |
|
602 v_type = V_VARIABLE; |
|
603 current->section = Entry::VARIABLE_SEC; |
|
604 current->name = argName; |
|
605 current->type = argType; |
|
606 current->fileName = yyFileName; |
|
607 current->bodyLine = yyLineNr; // used for source reference |
|
608 addCurrentEntry(); |
|
609 } |
|
610 else if (!argType.isEmpty()) |
|
611 { // deklaration of parameter list: add type for corr. parameter |
|
612 parameter= addFortranParameter(argType,argName,docBlock); |
|
613 if (parameter) v_type= V_PARAMETER; |
|
614 // save, it may be function return type |
|
615 modifiers[current_root][name.lower()].type = argType; |
|
616 // any accumulated doc for argument should be emptied, |
|
617 // because it is handled other way and this doc can be |
|
618 // unexpectedly passed to the next member. |
|
619 current->doc.resize(0); |
|
620 current->brief.resize(0); |
|
621 } |
|
622 } |
|
623 <Variable>{ARGS} { /* dimension of the previous entry. */ |
|
624 QCString name(argName); |
|
625 QCString attr("dimension"); |
|
626 attr += yytext; |
|
627 modifiers[current_root][name] |= attr; |
|
628 } |
|
629 <Variable>{COMMA} {} |
|
630 <Variable>{BS}"=" { yy_push_state(YY_START); |
|
631 initializer=""; |
|
632 initializerScope = 0; |
|
633 BEGIN(Initialization); |
|
634 } |
|
635 <Variable>"\n" { currentModifiers = SymbolModifiers(); |
|
636 yy_pop_state(); // end variable deklaration list |
|
637 yyLineNr++; yyLineNr+=lineCountPrepass; lineCountPrepass=0; |
|
638 docBlock.resize(0); |
|
639 } |
|
640 |
|
641 <Initialization,ArrayInitializer>"(/" { initializer+=yytext; |
|
642 initializerScope++; |
|
643 BEGIN(ArrayInitializer); // initializer may contain comma |
|
644 } |
|
645 <ArrayInitializer>"/)" { initializer+=yytext; |
|
646 initializerScope--; |
|
647 if(initializerScope<=0) |
|
648 { |
|
649 initializerScope = 0; // just in case |
|
650 BEGIN(Initialization); |
|
651 } |
|
652 } |
|
653 <ArrayInitializer>. { initializer+=yytext; } |
|
654 <Initialization>{COMMA} { yy_pop_state(); // end initialization |
|
655 if (v_type == V_VARIABLE) last_entry->initializer= initializer; |
|
656 } |
|
657 <Initialization>"\n"|"!" { //| |
|
658 yy_pop_state(); // end initialization |
|
659 if (v_type == V_VARIABLE) last_entry->initializer= initializer; |
|
660 unput(*yytext); |
|
661 } |
|
662 <Initialization>. { initializer+=yytext; } |
|
663 |
|
664 /*------ fortran subroutine/function handling ------------------------------------------------------------*/ |
|
665 /* Start is initial condition */ |
|
666 |
|
667 <Start,ModuleBody,SubprogBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains>^{BS}({PREFIX}{BS_})?{TYPE_SPEC}{BS}/{SUBPROG}{BS_} { |
|
668 // TYPE_SPEC is for old function style function result |
|
669 result= yytext; |
|
670 result= result.stripWhiteSpace(); |
|
671 extractPrefix(result); |
|
672 //fprintf(stderr, "===%s\n", (const char*)result); |
|
673 current->type = result; |
|
674 yy_push_state(SubprogPrefix); |
|
675 } |
|
676 |
|
677 <SubprogPrefix>{BS}{SUBPROG}{BS_} { |
|
678 // Fortran subroutine or function found |
|
679 addSubprogram(yytext); |
|
680 BEGIN(Subprog); |
|
681 } |
|
682 |
|
683 <Start,ModuleBody,SubprogBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains>^{BS}({PREFIX}{BS_})?{SUBPROG}{BS_} { |
|
684 // Fortran subroutine or function found |
|
685 result= yytext; |
|
686 result= result.stripWhiteSpace(); |
|
687 extractPrefix(result); |
|
688 addSubprogram(result); |
|
689 yy_push_state(Subprog); |
|
690 } |
|
691 |
|
692 <Subprog>{BS} { /* ignore white space */ } |
|
693 <Subprog>{ID} { current->name = yytext; |
|
694 //cout << "1a==========> got " << current->type << " " << yytext << " " << yyLineNr << endl; |
|
695 modifiers[current_root][current->name.lower()].returnName = current->name; |
|
696 BEGIN(Parameterlist); |
|
697 } |
|
698 <Parameterlist>{ARGS} { |
|
699 //current->type not yet available |
|
700 QCString arglist= yytext; |
|
701 //cout << "3=========> got parameterlist " << yytext << endl; |
|
702 //yyLineNr+= arglist.contains('\n'); |
|
703 //static QRegExp re("&[^\n]*\n"); |
|
704 //arglist = arglist.replace(re,""); |
|
705 //cout << "3=========> got parameterlist " << arglist << endl; |
|
706 current->args = arglist; |
|
707 current->args = removeRedundantWhiteSpace(current->args); |
|
708 stringToArgumentList(current->args, current->argList); |
|
709 addCurrentEntry(); |
|
710 startScope(last_entry); |
|
711 BEGIN(SubprogBody); |
|
712 } |
|
713 <Parameterlist>{NOARGS} { |
|
714 yyLineNr++; yyLineNr+=lineCountPrepass; lineCountPrepass=0; |
|
715 //printf("3=========> without parameterlist \n"); |
|
716 stringToArgumentList("", current->argList); |
|
717 addCurrentEntry(); |
|
718 startScope(last_entry); |
|
719 BEGIN(SubprogBody); |
|
720 } |
|
721 <SubprogBody>result{BS}\({BS}{ID} { |
|
722 result= yytext; |
|
723 result= result.right(result.length()-result.find("(")-1); |
|
724 result= result.stripWhiteSpace(); |
|
725 modifiers[current_root->parent()][current_root->name.lower()].returnName = result; |
|
726 //cout << "=====> got result " << result << endl; |
|
727 } |
|
728 |
|
729 /*---- documentation comments --------------------------------------------------------------------*/ |
|
730 |
|
731 <Variable>"!<" { /* backward docu comment (only one line) */ |
|
732 if (v_type != V_IGNORE) { |
|
733 yy_push_state(YY_START); |
|
734 current->docLine = yyLineNr; |
|
735 docBlockJavaStyle = FALSE; |
|
736 docBlock.resize(0); |
|
737 docBlockJavaStyle = Config_getBool("JAVADOC_AUTOBRIEF"); |
|
738 startCommentBlock(TRUE); |
|
739 BEGIN(DocBackLine); |
|
740 } |
|
741 } |
|
742 <DocBackLine>.* { // contents of current comment line |
|
743 docBlock=yytext; |
|
744 if (v_type == V_VARIABLE) |
|
745 { |
|
746 Entry *tmp_entry = current; |
|
747 current = last_entry; // temporarily switch to the previous entry |
|
748 handleCommentBlock(docBlock,TRUE); |
|
749 current=tmp_entry; |
|
750 } |
|
751 else if (v_type == V_PARAMETER) |
|
752 { |
|
753 parameter->docs=docBlock; |
|
754 } |
|
755 yy_pop_state(); |
|
756 } |
|
757 |
|
758 <Start,SubprogBody,ModuleBody,TypedefBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains>"!>" { |
|
759 yy_push_state(YY_START); |
|
760 current->docLine = yyLineNr; |
|
761 docBlockJavaStyle = FALSE; |
|
762 docBlock.resize(0); |
|
763 docBlockJavaStyle = Config_getBool("JAVADOC_AUTOBRIEF"); |
|
764 startCommentBlock(TRUE); |
|
765 BEGIN(DocBlock); |
|
766 //cout << "start DocBlock " << endl; |
|
767 } |
|
768 |
|
769 <DocBlock>.* { // contents of current comment line |
|
770 docBlock+=yytext; |
|
771 } |
|
772 <DocBlock>"\n"{BS}"!"(">"|"!"+) { // comment block (next line is also comment line) |
|
773 docBlock+="\n"; // \n is necessary for lists |
|
774 yyLineNr++; yyLineNr+=lineCountPrepass; lineCountPrepass=0; |
|
775 } |
|
776 <DocBlock>"\n" { // comment block ends at the end of this line |
|
777 //cout <<"3=========> comment block : "<< docBlock << endl; |
|
778 unput(*yytext); |
|
779 handleCommentBlock(docBlock,TRUE); |
|
780 yy_pop_state(); |
|
781 } |
|
782 |
|
783 /*------------------------------------------------------------------------------------------------*/ |
|
784 |
|
785 <*>"\n" { |
|
786 yyLineNr++; yyLineNr+=lineCountPrepass; lineCountPrepass=0; |
|
787 //if (debugStr.stripWhiteSpace().length() > 0) cout << "ignored text: " << debugStr << " state: " <<YY_START << endl; |
|
788 debugStr=""; |
|
789 } |
|
790 |
|
791 |
|
792 /*---- error: EOF in wrong state --------------------------------------------------------------------*/ |
|
793 |
|
794 <*><<EOF>> { |
|
795 if ( include_stack_ptr <= 0 ) { |
|
796 if (YY_START!=INITIAL && YY_START!=Start) { |
|
797 //fprintf(stderr,"==== Error: EOF reached in wrong state (end missing)"); |
|
798 scanner_abort(); |
|
799 } |
|
800 yyterminate(); |
|
801 } else { |
|
802 popBuffer(); |
|
803 } |
|
804 } |
|
805 <*>. { |
|
806 //debugStr+=yytext; |
|
807 //printf("I:%c\n", *yytext); |
|
808 } // ignore remaining text |
|
809 |
|
810 /**********************************************************************************/ |
|
811 /**********************************************************************************/ |
|
812 /**********************************************************************************/ |
|
813 %% |
|
814 //---------------------------------------------------------------------------- |
|
815 |
|
816 static void extractPrefix(QCString &text) { |
|
817 int prefixIndex = 0; |
|
818 int curIndex = 0; |
|
819 bool cont = TRUE; |
|
820 const char* pre[] = {"RECURSIVE","PURE","ELEMENTAL"}; |
|
821 while(cont) |
|
822 { |
|
823 cont = FALSE; |
|
824 for(unsigned int i=0; i<3; i++) |
|
825 { |
|
826 if((prefixIndex=text.find(pre[i], curIndex, FALSE))==0) |
|
827 { |
|
828 text.remove(0,strlen(pre[i])); |
|
829 text.stripWhiteSpace(); |
|
830 cont = TRUE; |
|
831 } |
|
832 } |
|
833 } |
|
834 } |
|
835 |
|
836 static int getAmpersandAtTheStart(const char *buf, int length) |
|
837 { |
|
838 for(int i=0; i<length; i++) { |
|
839 switch(buf[i]) { |
|
840 case ' ': |
|
841 case '\t': |
|
842 break; |
|
843 case '&': |
|
844 return i; |
|
845 default: |
|
846 return -1; |
|
847 } |
|
848 } |
|
849 return -1; |
|
850 } |
|
851 |
|
852 /* Returns ampersand index, comment start index or -1 if neither exist.*/ |
|
853 static int getAmpOrExclAtTheEnd(const char *buf, int length) |
|
854 { |
|
855 // Avoid ampersands in string and comments |
|
856 int parseState = Start; |
|
857 char quoteSymbol = 0; |
|
858 int ampIndex = -1; |
|
859 int commentIndex = -1; |
|
860 |
|
861 for(int i=0; i<length && parseState!=Comment; i++) |
|
862 { |
|
863 // When in string, skip backslashes |
|
864 // Legacy code, not sure whether this is correct? |
|
865 if(parseState==String) |
|
866 { |
|
867 if(buf[i]=='\\') i++; |
|
868 } |
|
869 |
|
870 switch(buf[i]) |
|
871 { |
|
872 case '\'': |
|
873 case '"': |
|
874 // Close string, if quote symbol matches. |
|
875 // Quote symbol is set iff parseState==String |
|
876 if(buf[i]==quoteSymbol) |
|
877 { |
|
878 parseState = Start; |
|
879 quoteSymbol = 0; |
|
880 } |
|
881 // Start new string, if not already in string or comment |
|
882 else if(parseState==Start) |
|
883 { |
|
884 parseState = String; |
|
885 quoteSymbol = buf[i]; |
|
886 } |
|
887 ampIndex = -1; // invalidate prev ampersand |
|
888 break; |
|
889 case '!': |
|
890 // When in string or comment, ignore exclamation mark |
|
891 if(parseState==Start) |
|
892 { |
|
893 parseState = Comment; |
|
894 commentIndex = i; |
|
895 } |
|
896 break; |
|
897 case ' ': // ignore whitespace |
|
898 case '\t': |
|
899 case '\n': // this may be at the end of line |
|
900 break; |
|
901 case '&': |
|
902 ampIndex = i; |
|
903 break; |
|
904 default: |
|
905 ampIndex = -1; // invalidate prev ampersand |
|
906 } |
|
907 } |
|
908 |
|
909 if (ampIndex>=0) |
|
910 return ampIndex; |
|
911 else |
|
912 return commentIndex; |
|
913 } |
|
914 |
|
915 /* Although comments at the end of continuation line are grabbed by this function, |
|
916 * we still do not know how to use them later in parsing. |
|
917 */ |
|
918 void truncatePrepass(int index) |
|
919 { |
|
920 int length = inputStringPrepass.length(); |
|
921 for (int i=index+1; i<length; i++) { |
|
922 if (inputStringPrepass[i]=='!') { // save comment |
|
923 //printf("-----SAVE----- %d:%s", i, (const char*)inputStringPrepass.right(length-i)); |
|
924 struct CommentInPrepass *c=new CommentInPrepass(index, inputStringPrepass.right(length-i)); |
|
925 comments.append(c); |
|
926 } |
|
927 } |
|
928 inputStringPrepass.truncate(index); |
|
929 } |
|
930 |
|
931 // simplified way to know if this is fixed form |
|
932 // duplicate in fortrancode.l |
|
933 static bool recognizeFixedForm(const char* contents) |
|
934 { |
|
935 int column=0; |
|
936 bool skipLine=FALSE; |
|
937 |
|
938 for(int i=0;;i++) { |
|
939 column++; |
|
940 |
|
941 switch(contents[i]) { |
|
942 case '\n': |
|
943 column=0; |
|
944 skipLine=FALSE; |
|
945 break; |
|
946 case ' ': |
|
947 break; |
|
948 case '\000': |
|
949 return FALSE; |
|
950 case 'C': |
|
951 case 'c': |
|
952 case '*': |
|
953 if(column==1) return TRUE; |
|
954 if(skipLine) break; |
|
955 return FALSE; |
|
956 case '!': |
|
957 if(column>1 && column<7) return FALSE; |
|
958 skipLine=TRUE; |
|
959 break; |
|
960 default: |
|
961 if(skipLine) break; |
|
962 if(column==7) return TRUE; |
|
963 return FALSE; |
|
964 } |
|
965 } |
|
966 return FALSE; |
|
967 } |
|
968 |
|
969 /* This function assumes that contents has at least size=length+1 */ |
|
970 static void insertCharacter(char *contents, int length, int pos, char c) |
|
971 { |
|
972 // shift tail by one character |
|
973 for(int i=length; i>pos; i--) |
|
974 contents[i]=contents[i-1]; |
|
975 // set the character |
|
976 contents[pos] = c; |
|
977 } |
|
978 |
|
979 /* change comments and bring line continuation character to previous line */ |
|
980 static const char* prepassFixedForm(const char* contents) |
|
981 { |
|
982 int column=0; |
|
983 int prevLineLength=0; |
|
984 int prevLineAmpOrExclIndex=-1; |
|
985 bool emptyLabel=TRUE; |
|
986 int newContentsSize = strlen(contents)+2; // \000 and one spare character (to avoid reallocation) |
|
987 char* newContents = (char*)malloc(newContentsSize); |
|
988 |
|
989 for(int i=0, j=0;;i++,j++) { |
|
990 if(j>=newContentsSize-1) { // check for one spare character, which may be eventually used below (by &) |
|
991 newContents = (char*)realloc(newContents, newContentsSize+1000); |
|
992 newContentsSize = newContentsSize+1000; |
|
993 } |
|
994 |
|
995 column++; |
|
996 char c = contents[i]; |
|
997 switch(c) { |
|
998 case '\n': |
|
999 prevLineLength=column; |
|
1000 prevLineAmpOrExclIndex=getAmpOrExclAtTheEnd(&contents[i-prevLineLength+1], prevLineLength); |
|
1001 column=0; |
|
1002 emptyLabel=TRUE; |
|
1003 newContents[j]=c; |
|
1004 break; |
|
1005 case ' ': |
|
1006 newContents[j]=c; |
|
1007 break; |
|
1008 case '\000': |
|
1009 newContents[j]='\000'; |
|
1010 return newContents; |
|
1011 case 'C': |
|
1012 case 'c': |
|
1013 case '*': |
|
1014 emptyLabel=FALSE; |
|
1015 if(column==1) |
|
1016 newContents[j]='!'; |
|
1017 else |
|
1018 newContents[j]=c; |
|
1019 break; |
|
1020 default: |
|
1021 if(column==6 && emptyLabel) { // continuation |
|
1022 newContents[j]=' '; |
|
1023 |
|
1024 if(prevLineAmpOrExclIndex==-1) { // add & just before end of previous line |
|
1025 insertCharacter(newContents, j+1, (j+1)-6-1, '&'); |
|
1026 j++; |
|
1027 } else { // add & just before end of previous line comment |
|
1028 insertCharacter(newContents, j+1, (j+1)-6-prevLineLength+prevLineAmpOrExclIndex, '&'); |
|
1029 j++; |
|
1030 } |
|
1031 } else { |
|
1032 newContents[j]=c; |
|
1033 emptyLabel=FALSE; |
|
1034 } |
|
1035 break; |
|
1036 } |
|
1037 } |
|
1038 return newContents; |
|
1039 } |
|
1040 |
|
1041 static void pushBuffer(QCString& buffer) |
|
1042 { |
|
1043 if ( include_stack_ptr >= MAX_INCLUDE_DEPTH ) |
|
1044 { |
|
1045 fprintf( stderr, "Stack buffers nested too deeply" ); |
|
1046 exit( 1 ); |
|
1047 } |
|
1048 include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER; |
|
1049 yy_switch_to_buffer(yy_scan_string(buffer)); |
|
1050 |
|
1051 //fprintf(stderr, "--PUSH--%s", (const char *)buffer); |
|
1052 buffer = NULL; |
|
1053 } |
|
1054 |
|
1055 static void popBuffer() { |
|
1056 //fprintf(stderr, "--POP--"); |
|
1057 include_stack_ptr --; |
|
1058 yy_delete_buffer( YY_CURRENT_BUFFER ); |
|
1059 yy_switch_to_buffer( include_stack[include_stack_ptr] ); |
|
1060 } |
|
1061 |
|
1062 /** used to copy entry to an interface module procedure */ |
|
1063 static void copyEntry(Entry *dest, Entry *src) |
|
1064 { |
|
1065 dest->type = src->type; |
|
1066 dest->fileName = src->fileName; |
|
1067 dest->bodyLine = src->bodyLine; |
|
1068 dest->args = src->args; |
|
1069 dest->argList = new ArgumentList(*src->argList); |
|
1070 } |
|
1071 |
|
1072 /** fill empty interface module procedures with info from |
|
1073 corresponding module subprogs |
|
1074 @TODO: handle procedures in used modules |
|
1075 */ |
|
1076 void resolveModuleProcedures(QList<Entry> &moduleProcedures, Entry *current_root) |
|
1077 { |
|
1078 if (moduleProcedures.isEmpty()) return; |
|
1079 |
|
1080 EntryListIterator eli1(moduleProcedures); |
|
1081 // for all module procedures |
|
1082 for (Entry *ce1; (ce1=eli1.current()); ++eli1) |
|
1083 { |
|
1084 // check all entries in this module |
|
1085 EntryListIterator eli2(*current_root->children()); |
|
1086 for (Entry *ce2; (ce2=eli2.current()); ++eli2) |
|
1087 { |
|
1088 if (ce1->name == ce2->name) |
|
1089 { |
|
1090 copyEntry(ce1, ce2); |
|
1091 } |
|
1092 } // for procedures in current module |
|
1093 } // for all interface module procedures |
|
1094 moduleProcedures.clear(); |
|
1095 } |
|
1096 |
|
1097 static bool isTypeName(QCString name) |
|
1098 { |
|
1099 name = name.lower(); |
|
1100 return name=="integer" || name == "real" || |
|
1101 name=="complex" || name == "logical"; |
|
1102 } |
|
1103 |
|
1104 /*! Extracts string which resides within parentheses of provided string. */ |
|
1105 static QCString extractFromParens(const QCString name) |
|
1106 { |
|
1107 QCString extracted = name; |
|
1108 int start = extracted.find("("); |
|
1109 if (start != -1) |
|
1110 { |
|
1111 extracted.remove(0, start+1); |
|
1112 } |
|
1113 int end = extracted.findRev(")"); |
|
1114 if (end != -1) |
|
1115 { |
|
1116 int length = extracted.length(); |
|
1117 extracted.remove(end, length); |
|
1118 } |
|
1119 extracted = extracted.stripWhiteSpace(); |
|
1120 |
|
1121 return extracted; |
|
1122 } |
|
1123 |
|
1124 /*! Adds passed modifiers to these modifiers.*/ |
|
1125 SymbolModifiers& SymbolModifiers::operator|=(const SymbolModifiers &mdfs) |
|
1126 { |
|
1127 if (mdfs.protection!=NONE_P) protection = mdfs.protection; |
|
1128 if (mdfs.direction!=NONE_D) direction = mdfs.direction; |
|
1129 optional |= mdfs.optional; |
|
1130 if (!mdfs.dimension.isNull()) dimension = mdfs.dimension; |
|
1131 allocatable |= mdfs.allocatable; |
|
1132 external |= mdfs.external; |
|
1133 intrinsic |= mdfs.intrinsic; |
|
1134 parameter |= mdfs.parameter; |
|
1135 pointer |= mdfs.pointer; |
|
1136 target |= mdfs.target; |
|
1137 save |= mdfs.save; |
|
1138 return *this; |
|
1139 } |
|
1140 |
|
1141 /*! Extracts and adds passed modifier to these modifiers.*/ |
|
1142 SymbolModifiers& SymbolModifiers::operator|=(QCString mdfString) |
|
1143 { |
|
1144 mdfString = mdfString.lower(); |
|
1145 SymbolModifiers newMdf; |
|
1146 |
|
1147 if (mdfString.find("dimension")==0) |
|
1148 { |
|
1149 newMdf.dimension=mdfString; |
|
1150 } |
|
1151 else if (mdfString.contains("intent")) |
|
1152 { |
|
1153 QCString tmp = extractFromParens(mdfString); |
|
1154 bool isin = tmp.contains("in"); |
|
1155 bool isout = tmp.contains("out"); |
|
1156 if (isin && isout) newMdf.direction = SymbolModifiers::INOUT; |
|
1157 else if (isin) newMdf.direction = SymbolModifiers::IN; |
|
1158 else if (isout) newMdf.direction = SymbolModifiers::OUT; |
|
1159 } |
|
1160 else if (mdfString=="public") |
|
1161 { |
|
1162 newMdf.protection = SymbolModifiers::PUBLIC; |
|
1163 } |
|
1164 else if (mdfString=="private") |
|
1165 { |
|
1166 newMdf.protection = SymbolModifiers::PRIVATE; |
|
1167 } |
|
1168 else if (mdfString=="optional") |
|
1169 { |
|
1170 newMdf.optional = TRUE; |
|
1171 } |
|
1172 else if (mdfString=="allocatable") |
|
1173 { |
|
1174 newMdf.allocatable = TRUE; |
|
1175 } |
|
1176 else if (mdfString=="external") |
|
1177 { |
|
1178 newMdf.external = TRUE; |
|
1179 } |
|
1180 else if (mdfString=="intrinsic") |
|
1181 { |
|
1182 newMdf.intrinsic = TRUE; |
|
1183 } |
|
1184 else if (mdfString=="parameter") |
|
1185 { |
|
1186 newMdf.parameter = TRUE; |
|
1187 } |
|
1188 else if (mdfString=="pointer") |
|
1189 { |
|
1190 newMdf.pointer = TRUE; |
|
1191 } |
|
1192 else if (mdfString=="target") |
|
1193 { |
|
1194 newMdf.target = TRUE; |
|
1195 } |
|
1196 else if (mdfString=="save") |
|
1197 { |
|
1198 newMdf.save = TRUE; |
|
1199 } |
|
1200 |
|
1201 (*this) |= newMdf; |
|
1202 return *this; |
|
1203 } |
|
1204 |
|
1205 /*! For debugging purposes. */ |
|
1206 //ostream& operator<<(ostream& out, const SymbolModifiers& mdfs) |
|
1207 //{ |
|
1208 // out<<mdfs.protection<<", "<<mdfs.direction<<", "<<mdfs.optional<< |
|
1209 // ", "<<(mdfs.dimension.isNull() ? "" : mdfs.dimension.latin1())<< |
|
1210 // ", "<<mdfs.allocatable<<", "<<mdfs.external<<", "<<mdfs.intrinsic; |
|
1211 // |
|
1212 // return out; |
|
1213 //} |
|
1214 |
|
1215 /*! Find argument with given name in \a subprog entry. */ |
|
1216 static Argument *findArgument(Entry* subprog, QCString name, bool byTypeName = FALSE) |
|
1217 { |
|
1218 QCString cname(name.lower()); |
|
1219 for (unsigned int i=0; i<subprog->argList->count(); i++) |
|
1220 { |
|
1221 Argument *arg = subprog->argList->at(i); |
|
1222 if ((!byTypeName && arg->name.lower() == cname) || |
|
1223 (byTypeName && arg->type.lower() == cname) |
|
1224 ) |
|
1225 { |
|
1226 return arg; |
|
1227 } |
|
1228 } |
|
1229 return 0; |
|
1230 } |
|
1231 |
|
1232 /*! Find function with given name in \a entry. */ |
|
1233 #if 0 |
|
1234 static Entry *findFunction(Entry* entry, QCString name) |
|
1235 { |
|
1236 QCString cname(name.lower()); |
|
1237 |
|
1238 EntryListIterator eli(*entry->children()); |
|
1239 Entry *ce; |
|
1240 for (;(ce=eli.current());++eli) |
|
1241 { |
|
1242 if (ce->section != Entry::FUNCTION_SEC) |
|
1243 continue; |
|
1244 |
|
1245 if (ce->name.lower() == cname) |
|
1246 return ce; |
|
1247 } |
|
1248 |
|
1249 return 0; |
|
1250 } |
|
1251 #endif |
|
1252 |
|
1253 /*! Apply modifiers stored in \a mdfs to the \a typeName string. */ |
|
1254 static QCString applyModifiers(QCString typeName, SymbolModifiers& mdfs) |
|
1255 { |
|
1256 if (!mdfs.dimension.isNull()) |
|
1257 { |
|
1258 typeName += ","; |
|
1259 typeName += mdfs.dimension; |
|
1260 } |
|
1261 if (mdfs.direction!=SymbolModifiers::NONE_D) |
|
1262 { |
|
1263 typeName += ","; |
|
1264 typeName += directionStrs[mdfs.direction]; |
|
1265 } |
|
1266 if (mdfs.optional) |
|
1267 { |
|
1268 typeName += ","; |
|
1269 typeName += "optional"; |
|
1270 } |
|
1271 if (mdfs.allocatable) |
|
1272 { |
|
1273 typeName += ","; |
|
1274 typeName += "allocatable"; |
|
1275 } |
|
1276 if (mdfs.external) |
|
1277 { |
|
1278 typeName += ","; |
|
1279 typeName += "external"; |
|
1280 } |
|
1281 if (mdfs.intrinsic) |
|
1282 { |
|
1283 typeName += ","; |
|
1284 typeName += "intrinsic"; |
|
1285 } |
|
1286 if (mdfs.parameter) |
|
1287 { |
|
1288 typeName += ","; |
|
1289 typeName += "parameter"; |
|
1290 } |
|
1291 if (mdfs.pointer) |
|
1292 { |
|
1293 typeName += ","; |
|
1294 typeName += "pointer"; |
|
1295 } |
|
1296 if (mdfs.target) |
|
1297 { |
|
1298 typeName += ","; |
|
1299 typeName += "target"; |
|
1300 } |
|
1301 if (mdfs.save) |
|
1302 { |
|
1303 typeName += ","; |
|
1304 typeName += "save"; |
|
1305 } |
|
1306 |
|
1307 return typeName; |
|
1308 } |
|
1309 |
|
1310 /*! Apply modifiers stored in \a mdfs to the \a arg argument. */ |
|
1311 static void applyModifiers(Argument *arg, SymbolModifiers& mdfs) |
|
1312 { |
|
1313 QCString tmp = arg->type; |
|
1314 arg->type = applyModifiers(tmp, mdfs); |
|
1315 } |
|
1316 |
|
1317 /*! Apply modifiers stored in \a mdfs to the \a ent entry. */ |
|
1318 static void applyModifiers(Entry *ent, SymbolModifiers& mdfs) |
|
1319 { |
|
1320 QCString tmp = ent->type; |
|
1321 ent->type = applyModifiers(tmp, mdfs); |
|
1322 |
|
1323 if (mdfs.protection == SymbolModifiers::PUBLIC) |
|
1324 ent->protection = Public; |
|
1325 else if (mdfs.protection == SymbolModifiers::PRIVATE) |
|
1326 ent->protection = Private; |
|
1327 } |
|
1328 |
|
1329 /*! Starts the new scope in fortran program. Consider using this function when |
|
1330 * starting module, interface, function or other program block. |
|
1331 * \see endScope() |
|
1332 */ |
|
1333 static void startScope(Entry *scope) |
|
1334 { |
|
1335 //cout<<"start scope: "<<scope->name<<endl; |
|
1336 current_root= scope; /* start substructure */ |
|
1337 |
|
1338 QMap<QCString,SymbolModifiers> mdfMap; |
|
1339 modifiers.insert(scope, mdfMap); |
|
1340 } |
|
1341 |
|
1342 /*! Ends scope in fortran program: may update subprogram arguments or module variable attributes. |
|
1343 * \see startScope() |
|
1344 */ |
|
1345 static bool endScope(Entry *scope, bool isGlobalRoot) |
|
1346 { |
|
1347 //cout<<"end scope: "<<scope->name<<endl; |
|
1348 if (current_root->parent() || isGlobalRoot) |
|
1349 { |
|
1350 current_root= current_root->parent(); /* end substructure */ |
|
1351 } |
|
1352 else |
|
1353 { |
|
1354 fprintf(stderr,"parse error in end <scopename>"); |
|
1355 scanner_abort(); |
|
1356 return FALSE; |
|
1357 } |
|
1358 |
|
1359 // update variables or subprogram arguments with modifiers |
|
1360 QMap<QCString,SymbolModifiers>& mdfsMap = modifiers[scope]; |
|
1361 |
|
1362 if (scope->section == Entry::FUNCTION_SEC) |
|
1363 { |
|
1364 // iterate all symbol modifiers of the scope |
|
1365 for (QMap<QCString,SymbolModifiers>::Iterator it=mdfsMap.begin(); it!=mdfsMap.end(); it++) |
|
1366 { |
|
1367 //cout<<it.key()<<": "<<it.data()<<endl; |
|
1368 Argument *arg = findArgument(scope, it.key()); |
|
1369 |
|
1370 if (arg) |
|
1371 applyModifiers(arg, it.data()); |
|
1372 } |
|
1373 |
|
1374 // find return type for function |
|
1375 //cout<<"RETURN NAME "<<modifiers[current_root][scope->name.lower()].returnName<<endl; |
|
1376 QCString returnName = modifiers[current_root][scope->name.lower()].returnName.lower(); |
|
1377 if (modifiers[scope].contains(returnName)) |
|
1378 { |
|
1379 scope->type = modifiers[scope][returnName].type; // returning type works |
|
1380 applyModifiers(scope, modifiers[scope][returnName]); // returning array works |
|
1381 } |
|
1382 |
|
1383 } |
|
1384 if (scope->section == Entry::CLASS_SEC) |
|
1385 { // was INTERFACE_SEC |
|
1386 if (scope->parent()->section == Entry::FUNCTION_SEC) |
|
1387 { // interface within function |
|
1388 // iterate functions of interface and |
|
1389 // try to find types for dummy(ie. argument) procedures. |
|
1390 //cout<<"Search in "<<scope->name<<endl; |
|
1391 EntryListIterator eli(*scope->children()); |
|
1392 Entry *ce; |
|
1393 for (;(ce=eli.current());++eli) |
|
1394 { |
|
1395 if (ce->section != Entry::FUNCTION_SEC) |
|
1396 continue; |
|
1397 |
|
1398 Argument *arg = findArgument(scope->parent(), ce->name, TRUE); |
|
1399 if (arg != 0) |
|
1400 { |
|
1401 // set type of dummy procedure argument to interface |
|
1402 arg->name = arg->type; |
|
1403 arg->type = scope->name; |
|
1404 } |
|
1405 } |
|
1406 } |
|
1407 } |
|
1408 if (scope->section!=Entry::FUNCTION_SEC) |
|
1409 { // not function section |
|
1410 // iterate variables: get and apply modifiers |
|
1411 EntryListIterator eli(*scope->children()); |
|
1412 Entry *ce; |
|
1413 for (;(ce=eli.current());++eli) |
|
1414 { |
|
1415 if (ce->section != Entry::VARIABLE_SEC && ce->section != Entry::FUNCTION_SEC) |
|
1416 continue; |
|
1417 |
|
1418 //cout<<ce->name<<", "<<mdfsMap.contains(ce->name.lower())<<mdfsMap.count()<<endl; |
|
1419 if (mdfsMap.contains(ce->name.lower())) |
|
1420 applyModifiers(ce, mdfsMap[ce->name.lower()]); |
|
1421 } |
|
1422 } |
|
1423 |
|
1424 // clear all modifiers of the scope |
|
1425 modifiers.remove(scope); |
|
1426 |
|
1427 return TRUE; |
|
1428 } |
|
1429 |
|
1430 //! Return full name of the entry. Sometimes we must combine several names recursively. |
|
1431 static QCString getFullName(Entry *e) |
|
1432 { |
|
1433 QCString name = e->name; |
|
1434 if (e->section == Entry::CLASS_SEC // || e->section == Entry::INTERFACE_SEC |
|
1435 || !e->parent() || e->parent()->name.isEmpty()) |
|
1436 return name; |
|
1437 |
|
1438 return getFullName(e->parent())+"::"+name; |
|
1439 } |
|
1440 |
|
1441 static int yyread(char *buf,int max_size) |
|
1442 { |
|
1443 int c=0; |
|
1444 |
|
1445 while ( c < max_size && inputString[inputPosition] ) |
|
1446 { |
|
1447 *buf = inputString[inputPosition++] ; |
|
1448 c++; buf++; |
|
1449 } |
|
1450 return c; |
|
1451 } |
|
1452 |
|
1453 static void initParser() |
|
1454 { |
|
1455 last_entry = 0; |
|
1456 } |
|
1457 |
|
1458 static void initEntry() |
|
1459 { |
|
1460 current->protection = defaultProtection ; |
|
1461 current->mtype = mtype; |
|
1462 current->virt = virt; |
|
1463 current->stat = gstat; |
|
1464 initGroupInfo(current); |
|
1465 } |
|
1466 |
|
1467 /** |
|
1468 adds current entry to current_root and creates new current |
|
1469 */ |
|
1470 static void addCurrentEntry() |
|
1471 { |
|
1472 //printf("===Adding entry %s to %s\n", current->name.data(), current_root->name.data()); |
|
1473 current_root->addSubEntry(current); |
|
1474 last_entry = current; |
|
1475 current = new Entry ; |
|
1476 initEntry(); |
|
1477 } |
|
1478 |
|
1479 static int max(int a, int b) {return a>b?a:b;} |
|
1480 |
|
1481 static void addModule(const char *name, bool isModule) |
|
1482 { |
|
1483 //fprintf(stderr, "0=========> got module %s\n", name); |
|
1484 |
|
1485 if (isModule) |
|
1486 current->section = Entry::NAMESPACE_SEC; |
|
1487 else |
|
1488 current->section = Entry::FUNCTION_SEC; |
|
1489 |
|
1490 if (name!=NULL) |
|
1491 { |
|
1492 current->name = name; |
|
1493 } |
|
1494 else |
|
1495 { |
|
1496 QCString fname = yyFileName; |
|
1497 int index = max(fname.findRev('/'), fname.findRev('\\')); |
|
1498 fname = fname.right(fname.length()-index-1); |
|
1499 fname = fname.prepend("__").append("__"); |
|
1500 current->name = fname; |
|
1501 } |
|
1502 current->type = "program"; |
|
1503 current->fileName = yyFileName; |
|
1504 current->bodyLine = yyLineNr; // used for source reference |
|
1505 current->protection = Public ; |
|
1506 addCurrentEntry(); |
|
1507 startScope(last_entry); |
|
1508 } |
|
1509 |
|
1510 |
|
1511 static void addSubprogram(const char *text) |
|
1512 { |
|
1513 //fprintf(stderr,"1=========> got subprog, type: %s\n",text); |
|
1514 current->section = Entry::FUNCTION_SEC ; |
|
1515 QCString subtype = text; subtype=subtype.lower().stripWhiteSpace(); |
|
1516 if (!current->type) current->type = subtype; |
|
1517 current->fileName = yyFileName; |
|
1518 current->bodyLine = yyLineNr; // used for source reference |
|
1519 current->startLine = -1; // ??? what is startLine for? |
|
1520 current->args.resize(0); |
|
1521 current->argList->clear(); |
|
1522 docBlock.resize(0); |
|
1523 } |
|
1524 |
|
1525 /*! Adds interface to the root entry. |
|
1526 * \note Code was brought to this procedure from the parser, |
|
1527 * because there was/is idea to use it in several parts of the parser. |
|
1528 */ |
|
1529 static void addInterface(QCString name) |
|
1530 { |
|
1531 current->section = Entry::CLASS_SEC; // was Entry::INTERFACE_SEC; |
|
1532 current->spec = Entry::Interface; |
|
1533 current->name = name; |
|
1534 |
|
1535 /* if type is part of a module, mod name is necessary for output */ |
|
1536 if ((current_root) && |
|
1537 (current_root->section == Entry::CLASS_SEC || |
|
1538 current_root->section == Entry::NAMESPACE_SEC)) |
|
1539 { |
|
1540 current->name= current_root->name+"::"+current->name; |
|
1541 } |
|
1542 if ((current_root) && |
|
1543 (current_root->section == Entry::FUNCTION_SEC)) |
|
1544 { |
|
1545 current->name = getFullName(current_root) + "__" + QCString(current->name); |
|
1546 } |
|
1547 |
|
1548 current->fileName = yyFileName; |
|
1549 current->bodyLine = yyLineNr; |
|
1550 addCurrentEntry(); |
|
1551 } |
|
1552 |
|
1553 |
|
1554 //----------------------------------------------------------------------------- |
|
1555 |
|
1556 /*! Update the argument \a name with additional \a type info. |
|
1557 */ |
|
1558 static Argument *addFortranParameter(const QCString &type,const QCString &name, const QCString docs) |
|
1559 { |
|
1560 //cout<<"addFortranParameter(): "<<name<<" DOCS:"<<(docs.isNull()?QCString("null"):docs)<<endl; |
|
1561 Argument *ret = 0; |
|
1562 if (current_root->argList==0) return 0; |
|
1563 ArgumentListIterator ali(*current_root->argList); |
|
1564 Argument *a; |
|
1565 for (ali.toFirst();(a=ali.current());++ali) |
|
1566 { |
|
1567 if (a->type.lower()==name.lower()) |
|
1568 { |
|
1569 ret=a; |
|
1570 //cout << "addParameter found: " << type << " , " << name << endl; |
|
1571 a->type=type.stripWhiteSpace(); |
|
1572 a->name=name.stripWhiteSpace(); |
|
1573 if (!docs.isNull()) |
|
1574 a->docs = docs; |
|
1575 break; |
|
1576 } |
|
1577 } // for |
|
1578 return ret; |
|
1579 } |
|
1580 |
|
1581 //---------------------------------------------------------------------------- |
|
1582 static void startCommentBlock(bool brief) |
|
1583 { |
|
1584 if (brief) |
|
1585 { |
|
1586 current->briefFile = yyFileName; |
|
1587 current->briefLine = yyLineNr; |
|
1588 } |
|
1589 else |
|
1590 { |
|
1591 current->docFile = yyFileName; |
|
1592 current->docLine = yyLineNr; |
|
1593 } |
|
1594 } |
|
1595 |
|
1596 //---------------------------------------------------------------------------- |
|
1597 static void handleCommentBlock(const QCString &doc,bool brief) |
|
1598 { |
|
1599 docBlockInBody = FALSE; |
|
1600 bool needsEntry = FALSE; |
|
1601 static bool hideInBodyDocs = Config_getBool("HIDE_IN_BODY_DOCS"); |
|
1602 int position=0; |
|
1603 if (docBlockInBody && hideInBodyDocs) return; |
|
1604 //fprintf(stderr,"call parseCommentBlock [%s]\n",doc.data()); |
|
1605 int lineNr = brief ? current->briefLine : current->docLine; |
|
1606 while (parseCommentBlock( |
|
1607 g_thisParser, |
|
1608 docBlockInBody ? last_entry : current, |
|
1609 doc, // text |
|
1610 yyFileName, // file |
|
1611 lineNr, |
|
1612 docBlockInBody ? FALSE : brief, |
|
1613 docBlockInBody ? FALSE : docBlockJavaStyle, |
|
1614 docBlockInBody, |
|
1615 defaultProtection, |
|
1616 position, |
|
1617 needsEntry |
|
1618 )) |
|
1619 { |
|
1620 //fprintf(stderr,"parseCommentBlock position=%d [%s] needsEntry=%d\n",position,doc.data()+position,needsEntry); |
|
1621 if (needsEntry) addCurrentEntry(); |
|
1622 } |
|
1623 //fprintf(stderr,"parseCommentBlock position=%d [%s] needsEntry=%d\n",position,doc.data()+position,needsEntry); |
|
1624 |
|
1625 if (needsEntry) addCurrentEntry(); |
|
1626 } |
|
1627 |
|
1628 //---------------------------------------------------------------------------- |
|
1629 static int level=0; |
|
1630 static void debugCompounds(Entry *rt) // print Entry structure (for debugging) |
|
1631 { |
|
1632 level++; |
|
1633 printf("%d) debugCompounds(%s) line %d\n",level, rt->name.data(), rt->bodyLine); |
|
1634 EntryListIterator eli(*rt->children()); |
|
1635 Entry *ce; |
|
1636 for (;(ce=eli.current());++eli) |
|
1637 { |
|
1638 debugCompounds(ce); |
|
1639 } |
|
1640 level--; |
|
1641 } |
|
1642 |
|
1643 |
|
1644 static void parseMain(const char *fileName,const char *fileBuf,Entry *rt) |
|
1645 { |
|
1646 initParser(); |
|
1647 |
|
1648 defaultProtection = Public; |
|
1649 inputString = fileBuf; |
|
1650 inputPosition = 0; |
|
1651 inputStringPrepass = NULL; |
|
1652 inputPositionPrepass = 0; |
|
1653 |
|
1654 //anonCount = 0; // don't reset per file |
|
1655 mtype = Method; |
|
1656 gstat = FALSE; |
|
1657 virt = Normal; |
|
1658 current_root = rt; |
|
1659 global_root = rt; |
|
1660 inputFile.setName(fileName); |
|
1661 if (inputFile.open(IO_ReadOnly)) |
|
1662 { |
|
1663 isFixedForm = recognizeFixedForm(fileBuf); |
|
1664 |
|
1665 if (isFixedForm) { |
|
1666 printf("Prepassing fixed form of %s\n", yyFileName.data()); |
|
1667 //printf("---strlen=%d\n", strlen(fileBuf)); |
|
1668 //clock_t start=clock(); |
|
1669 |
|
1670 inputString = prepassFixedForm(fileBuf); |
|
1671 |
|
1672 //clock_t end=clock(); |
|
1673 //printf("CPU time used=%f\n", ((double) (end-start))/CLOCKS_PER_SEC); |
|
1674 } |
|
1675 |
|
1676 yyLineNr= 1 ; |
|
1677 yyFileName = fileName; |
|
1678 msg("Parsing file %s...\n",yyFileName.data()); |
|
1679 |
|
1680 startScope(rt); // implies current_root = rt |
|
1681 initParser(); |
|
1682 groupEnterFile(yyFileName,yyLineNr); |
|
1683 |
|
1684 current = new Entry; |
|
1685 current->name = yyFileName; |
|
1686 current->section = Entry::SOURCE_SEC; |
|
1687 current_root->addSubEntry(current); |
|
1688 file_root = current; |
|
1689 current = new Entry; |
|
1690 |
|
1691 fscanYYrestart( fscanYYin ); |
|
1692 { |
|
1693 BEGIN( Start ); |
|
1694 } |
|
1695 |
|
1696 fscanYYlex(); |
|
1697 groupLeaveFile(yyFileName,yyLineNr); |
|
1698 |
|
1699 endScope(current_root, TRUE); // TRUE - global root |
|
1700 |
|
1701 //debugCompounds(rt); //debug |
|
1702 |
|
1703 rt->program.resize(0); |
|
1704 delete current; current=0; |
|
1705 moduleProcedures.clear(); |
|
1706 if (isFixedForm) { |
|
1707 free((char*)inputString); |
|
1708 inputString=NULL; |
|
1709 } |
|
1710 |
|
1711 inputFile.close(); |
|
1712 } |
|
1713 } |
|
1714 |
|
1715 //---------------------------------------------------------------------------- |
|
1716 |
|
1717 void FortranLanguageScanner::parseInput(const char *fileName,const char *fileBuf,Entry *root) |
|
1718 { |
|
1719 g_thisParser = this; |
|
1720 ::parseMain(fileName,fileBuf,root); |
|
1721 } |
|
1722 |
|
1723 void FortranLanguageScanner::parseCode(CodeOutputInterface & codeOutIntf, |
|
1724 const char * scopeName, |
|
1725 const QCString & input, |
|
1726 bool isExampleBlock, |
|
1727 const char * exampleName, |
|
1728 FileDef * fileDef, |
|
1729 int startLine, |
|
1730 int endLine, |
|
1731 bool inlineFragment, |
|
1732 MemberDef *memberDef |
|
1733 ) |
|
1734 { |
|
1735 ::parseFortranCode(codeOutIntf,scopeName,input,isExampleBlock,exampleName, |
|
1736 fileDef,startLine,endLine,inlineFragment,memberDef); |
|
1737 } |
|
1738 |
|
1739 bool FortranLanguageScanner::needsPreprocessing(const QCString &extension) |
|
1740 { |
|
1741 (void)extension; |
|
1742 return TRUE; |
|
1743 } |
|
1744 void FortranLanguageScanner::resetCodeParserState() |
|
1745 { |
|
1746 ::resetFortranCodeParserState(); |
|
1747 } |
|
1748 |
|
1749 void FortranLanguageScanner::parsePrototype(const char *text) |
|
1750 { |
|
1751 (void)text; |
|
1752 } |
|
1753 |
|
1754 static void scanner_abort() |
|
1755 { |
|
1756 fprintf(stderr,"********************************************************************\n"); |
|
1757 fprintf(stderr,"Error in file %s line: %d, state: %d\n",yyFileName.data(),yyLineNr,YY_START); |
|
1758 fprintf(stderr,"********************************************************************\n"); |
|
1759 |
|
1760 EntryListIterator eli(*global_root->children()); |
|
1761 Entry *ce; |
|
1762 bool start=FALSE; |
|
1763 |
|
1764 for (;(ce=eli.current());++eli) |
|
1765 { |
|
1766 if (ce == file_root) start=TRUE; |
|
1767 if (start) ce->reset(); |
|
1768 } |
|
1769 |
|
1770 // dummy call to avoid compiler warning |
|
1771 (void)yy_top_state(); |
|
1772 |
|
1773 return; |
|
1774 //exit(-1); |
|
1775 } |
|
1776 |
|
1777 //---------------------------------------------------------------------------- |
|
1778 |
|
1779 #if !defined(YY_FLEX_SUBMINOR_VERSION) |
|
1780 //---------------------------------------------------------------------------- |
|
1781 extern "C" { // some bogus code to keep the compiler happy |
|
1782 void fscannerYYdummy() { yy_flex_realloc(0,0); } |
|
1783 } |
|
1784 #endif |
|
1785 |