1 /*
2  * This file is part of the FortranProject plugin for Code::Blocks IDE
3  * and licensed under the GNU General Public License, version 3
4  * http://www.gnu.org/licenses/gpl-3.0.html
5  */
6 
7 #include "parserthreadf.h"
8 
9 #include <sdk.h>
10 #ifndef CB_PRECOMP
11     #include <wx/tokenzr.h>
12 #endif
13 #include <set>
14 
15 #include "usetokenf.h"
16 
ParserThreadF(const wxString & projectFilename,const wxString & bufferOrFilename,TokensArrayF * tokens,FortranSourceForm fsForm,bool isBuffer,IncludeDB * includeDB)17 ParserThreadF::ParserThreadF(const wxString& projectFilename,
18                              const wxString& bufferOrFilename,
19                              TokensArrayF* tokens,
20                              FortranSourceForm fsForm,
21                              bool isBuffer,
22                              IncludeDB* includeDB)
23     :
24     m_pTokens(tokens),
25     m_pLastParent(0L),
26     m_pIncludeDB(includeDB),
27     m_Briefend(_T("@brief_end@"))
28 {
29     m_InterfaceOperator = 0;
30     m_InterfaceAssignment = 0;
31     m_InterfaceRead = 0;
32     m_InterfaceWrite = 0;
33 
34     m_pPPDefineTokens = new TokensArrayF();
35     m_inIfdef = 0;
36 
37     if (!isBuffer)
38     {
39         if (!bufferOrFilename.IsEmpty())
40         {
41             m_Filename = bufferOrFilename;
42             m_Tokens.Init(m_Filename, fsForm);
43             wxChar sep = wxFileName::GetPathSeparator();
44             m_pLastParent = DoAddFileToken(bufferOrFilename.AfterLast(sep), projectFilename);
45         }
46     }
47     else
48     {
49         m_Tokens.InitFromBuffer(bufferOrFilename, fsForm);
50     }
51     InitSecondEndPart();
52 }
53 
ParserThreadF(const wxString & projectFilename,const wxString & filename,TokensArrayF * tokens,FortranSourceForm fsForm,IncludeDB * includeDB,const wxString & buffer)54 ParserThreadF::ParserThreadF(const wxString& projectFilename,
55                              const wxString& filename,
56                              TokensArrayF* tokens,
57                              FortranSourceForm fsForm,
58                              IncludeDB* includeDB,
59                              const wxString& buffer)
60     :
61     m_pTokens(tokens),
62     m_pLastParent(0L),
63     m_pIncludeDB(includeDB),
64     m_Briefend(_T("@brief_end@"))
65 {
66     m_InterfaceOperator = 0;
67     m_InterfaceAssignment = 0;
68     m_InterfaceRead = 0;
69     m_InterfaceWrite = 0;
70 
71     m_pPPDefineTokens = new TokensArrayF();
72     m_inIfdef = 0;
73 
74     m_Filename = filename;
75     m_Tokens.InitFromBuffer(buffer, fsForm);
76     m_Tokens.SetFilename(filename);
77     wxChar sep = wxFileName::GetPathSeparator();
78     m_pLastParent = DoAddFileToken(filename.AfterLast(sep), projectFilename);
79 
80     InitSecondEndPart();
81 }
82 
~ParserThreadF()83 ParserThreadF::~ParserThreadF()
84 {
85     //dtor
86     delete m_pPPDefineTokens;
87 }
88 
InitSecondEndPart()89 void ParserThreadF::InitSecondEndPart()
90 {
91     m_KnownEndSecPart.insert(_T("subroutine"));
92     m_KnownEndSecPart.insert(_T("function"));
93     m_KnownEndSecPart.insert(_T("module"));
94     m_KnownEndSecPart.insert(_T("submodule"));
95     m_KnownEndSecPart.insert(_T("type"));
96     m_KnownEndSecPart.insert(_T("interface"));
97     m_KnownEndSecPart.insert(_T("program"));
98     m_KnownEndSecPart.insert(_T("block"));
99     m_KnownEndSecPart.insert(_T("blockdata"));
100     m_KnownEndSecPart.insert(_T("associate"));
101     m_KnownEndSecPart.insert(_T("procedure"));
102 
103     m_NumberOfBlockConstruct = 0;
104 }
105 
Parse()106 bool ParserThreadF::Parse()
107 {
108     if (!m_pTokens || !m_Tokens.IsOK())
109     {
110         return false;
111     }
112 
113     while (1)
114     {
115         wxString token = m_Tokens.GetToken();
116         if (token.IsEmpty())
117             break;
118 
119         wxString tok_low = token.Lower();
120         wxString next = m_Tokens.PeekToken();
121         wxString nex_low = next.Lower();
122 
123         if (tok_low.Matches(_T("use")))
124         {
125             HandleUse();
126         }
127         else if (tok_low.Matches(_T("module")) && !nex_low.Matches(_T("procedure"))
128                  && !nex_low.Matches(_T("function"))  && !nex_low.Matches(_T("subroutine")))
129         {
130             HandleModule();
131         }
132         else if (tok_low.Matches(_T("submodule")) && !nex_low.Matches(_T("procedure")))
133         {
134             HandleSubmodule();
135         }
136         else if (tok_low.Matches(_T("program")))
137         {
138             HandleFunction(tkProgram);
139         }
140         else if (tok_low.Matches(_T("function")))
141         {
142             HandleFunction(tkFunction);
143         }
144         else if (tok_low.Matches(_T("subroutine")))
145         {
146             HandleFunction(tkSubroutine);
147         }
148         else if (tok_low.Matches(_T("type")) && !nex_low(0,1).Matches(_T("(")) && !nex_low.Matches(_T("is")))
149         {
150             HandleType();
151         }
152         else if (tok_low.Matches(_T("block")))
153         {
154             if (nex_low.Matches(_T("data")))
155             {
156                 token = m_Tokens.GetToken();
157                 tok_low = token.Lower();
158                 next = m_Tokens.PeekToken();
159                 nex_low = next.Lower();
160                 HandleBlockData();
161             }
162             else
163             {
164                 HandleBlockConstruct();
165             }
166         }
167         else if (tok_low.Matches(_T("blockdata")))
168         {
169             HandleBlockData();
170         }
171         else if (tok_low.Matches(_T("include")))
172         {
173             HandleInclude();
174         }
175         else if (tok_low.GetChar(0) == '#')
176         {
177             HandlePPDirective(token);
178         }
179         else if (tok_low.Matches(_T("interface")))
180         {
181             HandleInterface();
182         }
183         else if (tok_low.Matches(_T("associate")))
184         {
185             HandleAssociateConstruct();
186         }
187         else if ((tok_low.Matches(_T("select")) && nex_low.Matches(_T("type"))) ||
188                  tok_low.Matches(_T("selecttype")))
189         {
190             HandleSelectTypeConstruct();
191         }
192         else if ((tok_low.Matches(_T("select")) && nex_low.Matches(_T("case"))) ||
193                  tok_low.Matches(_T("selectcase")))
194         {
195             HandleSelectCaseConstruct();
196         }
197         else if (tok_low.Matches(_T("end")))
198         {
199             // something is wrong with code or parser
200             m_Tokens.SkipToOneOfChars(";", true);
201         }
202         else if (tok_low.Matches(_T("procedure")) && nex_low(0,1).Matches(_T("(")))
203         {
204             ParseTypeBoundProcedures(token, true, false);
205         }
206         else
207         {
208             bool needDefault = true;
209             bool hasFunctionInLine;
210             TokensArrayF tokTmpArr;
211             CheckParseOneDeclaration(token, tok_low, next, nex_low, needDefault, tokTmpArr, hasFunctionInLine);
212         }
213     }
214 
215     if (!m_Filename.IsEmpty() && m_pIncludeDB)
216     {
217         //update IncludeDB
218         wxChar sep = wxFileName::GetPathSeparator();
219         m_pIncludeDB->SetInclude(m_Filename.AfterLast(sep), m_IncludeList);
220     }
221     return true;
222 }
223 
DoAddToken(TokenKindF kind,const wxString & name,const wxString & args,const wxString & typeDefinition)224 TokenF* ParserThreadF::DoAddToken(TokenKindF kind, const wxString& name, const wxString& args, const wxString& typeDefinition)
225 {
226     TokenF* newToken = new TokenF;
227     newToken->m_Name = name.Lower();
228 
229     newToken->m_TokenKind = kind;
230     newToken->m_pParent = m_pLastParent;
231     newToken->m_Filename = m_Tokens.GetFilename();
232     newToken->m_LineStart = m_Tokens.GetLineNumber();
233     newToken->m_DisplayName = name;
234     newToken->m_Args = args;
235     newToken->m_TypeDefinition = typeDefinition;
236     newToken->m_DefinitionLength = 1;
237 
238     if (m_pLastParent)
239     {
240         m_pLastParent->AddChild(newToken);
241     }
242     else
243     {
244         m_pTokens->Add(newToken);
245     }
246 
247     return newToken;
248 }
249 
DoAddToken(TokenKindF kind,const wxString & name,const wxString & args,const unsigned int defStartLine)250 TokenF* ParserThreadF::DoAddToken(TokenKindF kind, const wxString& name, const wxString& args, const unsigned int defStartLine)
251 {
252     TokenF* newToken = new TokenF;
253     newToken->m_Name = name.Lower();
254 
255     newToken->m_TokenKind = kind;
256     newToken->m_pParent = m_pLastParent;
257     newToken->m_Filename = m_Tokens.GetFilename();
258     newToken->m_DisplayName = name;
259     newToken->m_Args = args;
260     newToken->m_TypeDefinition = wxEmptyString;
261 
262     newToken->m_LineStart = defStartLine;
263     newToken->m_DefinitionLength = m_Tokens.GetLineNumber() - defStartLine + 1;
264 
265 
266     if (m_pLastParent)
267     {
268         m_pLastParent->AddChild(newToken);
269     }
270     else
271     {
272         m_pTokens->Add(newToken);
273     }
274 
275     return newToken;
276 }
277 
DoAddFileToken(const wxString & filename,const wxString & projectFilename)278 FileTokenF* ParserThreadF::DoAddFileToken(const wxString& filename, const wxString& projectFilename)
279 {
280     FileTokenF* newToken = new FileTokenF;
281     newToken->m_Name = filename.Lower();
282 
283     newToken->m_TokenKind = tkFile;
284     newToken->m_pParent = m_pLastParent;
285     newToken->m_Filename = m_Tokens.GetFilename();
286     newToken->m_LineStart = 0;
287     newToken->m_DisplayName = filename;
288     newToken->m_DefinitionLength = 1;
289 
290     m_pTokens->Add(newToken);
291 
292     newToken->m_ProjectFilename = projectFilename;
293 
294     return newToken;
295 }
296 
HandleUse()297 void ParserThreadF::HandleUse()
298 {
299     wxString modName;
300     wxArrayString lineTok = m_Tokens.GetTokensToEOL();
301     ModuleNature modNature = mnNonIntrinsic;
302     int ltCount = lineTok.GetCount();
303     int idx = lineTok.Index(_T("::"));
304     if (idx != wxNOT_FOUND)
305     {
306         if (idx > 0)
307         {
308             if (lineTok.Item(idx-1).Lower().IsSameAs(_T("intrinsic")))
309             {
310                 modNature = mnIntrinsic;
311             }
312         }
313         idx++;
314     }
315     else
316     {
317         idx = 0;
318     }
319     if (ltCount > idx)
320     {
321         modName = lineTok.Item(idx);
322     }
323     else
324     {
325         return; //something wrong
326     }
327     UseTokenF* pUseTok = DoAddUseToken(modName);
328     pUseTok->SetModuleNature(modNature);
329 
330     idx++;
331     if (ltCount <= idx)
332     {
333         return; // no more on the line
334     }
335     if (lineTok.Item(idx).Lower().IsSameAs(_T("only")))
336     {
337         pUseTok->SetOnly(true);
338         idx++;
339         while (true)
340         {
341             idx++;
342             if (ltCount <= idx)
343                 break;
344             wxString localName = lineTok.Item(idx);
345             wxString externalName;
346 
347             if (localName.Lower().IsSameAs(_T("operator")))
348             {
349                 idx += 4; // operator (.st.) => operator (.kt.)
350                 continue;
351             }
352             if (ltCount > idx+1 && lineTok.Item(idx+1).IsSameAs(_T("=>")))
353             {
354                 //it is rename
355                 if (ltCount > idx+2)
356                 {
357                     idx += 2;
358                     externalName = lineTok.Item(idx);
359                 }
360                 else
361                 {
362                     break; // '=>' on end of line
363                 }
364             }
365             if (externalName.IsEmpty())
366                 pUseTok->AddToNamesList(localName);
367             else
368                 pUseTok->AddToRenameList(localName, externalName);
369         }
370     }
371     else
372     {
373         pUseTok->SetOnly(false);
374         // rename-list
375         while (true)
376         {
377             if (lineTok.Item(idx).Lower().IsSameAs(_T("operator")))
378             {
379                 idx += 5; // operator (.st.) => operator (.kt.)
380             }
381             if (ltCount > idx+1 && lineTok.Item(idx+1).IsSameAs(_T("=>")))
382             {
383                 wxString localName = lineTok.Item(idx);
384                 wxString externalName;
385                 if (ltCount > idx+2)
386                 {
387                     idx += 2;
388                     externalName = lineTok.Item(idx);
389                 }
390                 else
391                 {
392                     break; // '=>' on end of line
393                 }
394                 pUseTok->AddToRenameList(localName, externalName);
395                 idx++;
396                 if (ltCount <= idx)
397                     break;
398             }
399             else
400             {
401                 break;
402             }
403         }
404     }
405 }
406 
407 
DoAddUseToken(const wxString & modName)408 UseTokenF* ParserThreadF::DoAddUseToken(const wxString& modName)
409 {
410     UseTokenF* newToken = new UseTokenF();
411     newToken->m_Name = modName.Lower();
412 
413     newToken->m_TokenKind = tkUse;
414     newToken->m_pParent = m_pLastParent;
415     newToken->m_Filename = m_Tokens.GetFilename();
416     newToken->m_DisplayName = modName;
417     newToken->m_TypeDefinition = wxEmptyString;
418 
419     newToken->m_LineStart = m_Tokens.GetLineNumber();
420     newToken->m_DefinitionLength = 1;
421 
422     if (m_pLastParent)
423     {
424         m_pLastParent->AddChild(newToken);
425     }
426     else
427     {
428         m_pTokens->Add(newToken);
429     }
430 
431     return newToken;
432 }
433 
434 
HandleModule()435 void ParserThreadF::HandleModule()
436 {
437     TokenKindF kind = tkModule;
438     TokenF* old_parent = m_pLastParent;
439 
440     int countAccessList = 0;
441     wxString token = m_Tokens.GetTokenSameLine();
442     TokenAccessKind taDefKind = taPublic;
443     ModuleTokenF* modToken;
444     if (token.IsEmpty())
445         modToken = DoAddModuleToken(_T("unnamed"));
446     else
447         modToken = DoAddModuleToken(token);
448     m_pLastParent = modToken;
449 
450     // Parse documentation
451     m_ParentDocs.Clear();
452     DocBlock docs;
453     GetDocBlock(docs, false, modToken->m_LineStart, true);
454     if (docs.HasBrief() || docs.HasDescription())
455         modToken->m_DocString << docs.GetBrief() + m_Briefend + docs.GetDescription();
456 
457     wxArrayString privateNameList;
458     wxArrayString publicNameList;
459     wxArrayString protectedNameList;
460 
461     TokensArrayF typeTokensAll;
462     TokensArrayF interfGenTokens;
463     TokensArrayF interfTokens;
464 
465     while (1)
466     {
467         token = m_Tokens.GetToken();
468         if (token.IsEmpty())
469             break;
470         wxString tok_low = token.Lower();
471 
472         wxString next = m_Tokens.PeekToken();
473         wxString nex_low = next.Lower();
474         if ( ((m_Tokens.GetLineNumber() == m_Tokens.GetPeekedLineNumber()) && IsEnd(tok_low, nex_low)) ||
475              ((m_Tokens.GetLineNumber() != m_Tokens.GetPeekedLineNumber()) && IsEnd(tok_low, _T(""))) )
476         {
477             m_Tokens.SkipToOneOfChars(";", true);
478             break;
479         }
480         else if (tok_low.Matches(_T("type")) && !nex_low(0,1).Matches(_T("(")))
481         {
482             bool needDefault=true;
483             TokenF* tokTmp = 0;
484             HandleType(needDefault, tokTmp);
485             if (tokTmp)
486                 typeTokensAll.Add(tokTmp);
487             if (!needDefault && tokTmp)
488             {
489                 if (tokTmp->m_TokenAccess == taPrivate)
490                     privateNameList.Add(tokTmp->m_Name);
491                 else
492                     publicNameList.Add(tokTmp->m_Name);
493             }
494         }
495         else if (tok_low.Matches(_T("subroutine")))
496         {
497             HandleFunction(tkSubroutine, taDefKind);
498         }
499         else if (tok_low.Matches(_T("function")))
500         {
501             HandleFunction(tkFunction, taDefKind);
502         }
503         else if (tok_low.Matches(_T("use")))
504         {
505             HandleUse();
506         }
507         else if (tok_low.Matches(_T("interface")))
508         {
509             TokenF* tokTmp = 0;
510             bool isGeneric = false;
511             HandleInterface(taDefKind, tokTmp, isGeneric);
512             if (isGeneric && tokTmp)
513                 interfGenTokens.Add(tokTmp);
514             if (tokTmp)
515                 interfTokens.Add(tokTmp);
516         }
517         else if (tok_low.Matches(_T("include")))
518         {
519             HandleInclude();
520         }
521         else if (tok_low.GetChar(0) == '#')
522         {
523             HandlePPDirective(token);
524         }
525         else if (tok_low.Matches(_T("private")))
526         {
527             bool changeDefault;
528             HandleAccessList(taPrivate, changeDefault, countAccessList, privateNameList);
529             if (changeDefault)
530             {
531                 modToken->SetDefaultPublic(false);
532                 taDefKind = taPrivate;
533             }
534         }
535         else if (tok_low.Matches(_T("public")))
536         {
537             bool changeDefault;
538             HandleAccessList(taPublic, changeDefault, countAccessList, publicNameList);
539             if (changeDefault)
540             {
541                 modToken->SetDefaultPublic(true);
542                 taDefKind = taPublic;
543             }
544         }
545         else if (tok_low.Matches(_T("protected")))
546         {
547             bool tmpB;
548             HandleAccessList(taProtected, tmpB, countAccessList, protectedNameList);
549         }
550         else if (kind == tkModule)
551         {
552             bool needDefault=true;
553             bool hasFunctionInLine;
554             TokensArrayF tokTmpArr;
555             CheckParseOneDeclaration(token, tok_low, next, nex_low, needDefault, tokTmpArr, hasFunctionInLine);
556             if (!needDefault)
557             {
558                 for (size_t i=0; i<tokTmpArr.Count(); i++)
559                 {
560                     if (tokTmpArr.Item(i)->m_TokenAccess == taPrivate)
561                         privateNameList.Add(tokTmpArr.Item(i)->m_Name);
562                     else
563                         publicNameList.Add(tokTmpArr.Item(i)->m_Name);
564                 }
565             }
566         }
567     }
568     modToken->AddLineEnd(m_Tokens.GetLineNumber());
569     m_pLastParent = old_parent;
570 
571     for (size_t i=0; i<interfTokens.GetCount(); i++)
572     {
573         interfTokens.Item(i)->m_TokenAccess = taDefKind;
574         if (interfTokens.Item(i)->m_TokenKind == tkInterfaceExplicit)
575         {
576             TokensArrayF* chs = &interfTokens.Item(i)->m_Children;
577             for (size_t j=0; j<chs->GetCount(); j++)
578             {
579                 chs->Item(j)->m_TokenAccess = taDefKind;
580             }
581         }
582     }
583 
584     for (size_t i=0; i<publicNameList.GetCount(); i++)
585     {
586         modToken->AddToPublicList(publicNameList.Item(i));
587     }
588     for (size_t i=0; i<privateNameList.GetCount(); i++)
589     {
590         modToken->AddToPrivateList(privateNameList.Item(i));
591     }
592 
593     TokensArrayF* toks = &modToken->m_Children;
594     if (toks)
595     {
596         for (size_t i=0; i<toks->GetCount(); i++)
597         {
598             SetTokenAccess(modToken, toks->Item(i), taDefKind);
599 
600             if (protectedNameList.Index(toks->Item(i)->m_Name) != wxNOT_FOUND)
601             {
602                 toks->Item(i)->m_TokenAccess = taProtected;
603             }
604             else if (toks->Item(i)->m_TokenKind == tkInterfaceExplicit)
605             {
606                 TokensArrayF* chs = &toks->Item(i)->m_Children;
607                 if (chs)
608                 {
609                     for (size_t j=0; j<chs->GetCount(); j++)
610                     {
611                         SetTokenAccess(modToken, chs->Item(j), taDefKind);
612                     }
613                 }
614             }
615         }
616     }
617 
618     // find kind of children of GenericInterfaces
619     for (size_t i=0; i<interfGenTokens.GetCount(); i++)
620     {
621         TokensArrayF* chs = &interfGenTokens.Item(i)->m_Children;
622         for (size_t j=0; j<chs->GetCount(); j++)
623         {
624             wxString intfname = chs->Item(j)->m_Name;
625             TokensArrayF* modChs = &modToken->m_Children;
626             TokenKindF tk;
627             bool found = false;
628             for (size_t k=0; k<modChs->GetCount(); k++)
629             {
630                 if ((modChs->Item(k)->m_TokenKind == tkSubroutine || modChs->Item(k)->m_TokenKind == tkFunction) &&
631                         modChs->Item(k)->m_Name.IsSameAs(intfname))
632                 {
633                     tk = modChs->Item(k)->m_TokenKind;
634                     found = true;
635                     break;
636                 }
637                 else if (modChs->Item(k)->m_TokenKind == tkInterfaceExplicit ||
638                          modChs->Item(k)->m_TokenKind == tkInterface)
639                 {
640                     TokensArrayF* intfExpChs = &modChs->Item(k)->m_Children;
641                     if (intfExpChs)
642                     {
643                         for (size_t m=0; m<intfExpChs->GetCount(); m++)
644                         {
645                             if ((intfExpChs->Item(m)->m_TokenKind == tkSubroutine || intfExpChs->Item(m)->m_TokenKind == tkFunction) &&
646                                     intfExpChs->Item(m)->m_Name.IsSameAs(intfname))
647                             {
648                                 tk = intfExpChs->Item(m)->m_TokenKind;
649                                 found = true;
650                                 break;
651                             }
652                         }
653                         if (found)
654                             break;
655                     }
656                 }
657             }
658 
659             if (found)
660             {
661                 // write kind for GenericInterface
662                 if (tk == tkFunction)
663                     interfGenTokens.Item(i)->m_TypeDefinition = _T("function");
664                 else
665                     interfGenTokens.Item(i)->m_TypeDefinition = _T("subroutine");
666                 break;
667             }
668         }
669     }
670 
671     for (size_t i=0; i<typeTokensAll.GetCount(); i++)
672     {
673         TokensArrayF* chs = &typeTokensAll.Item(i)->m_Children;
674         TokensArrayF genericProc;
675         for (size_t j=0; j<chs->GetCount(); j++)
676         {
677             if (chs->Item(j)->m_TokenKind == tkProcedure)
678             {
679                 wxString procName;
680                 if (chs->Item(j)->m_PartLast.IsEmpty())
681                     procName = chs->Item(j)->m_Name;
682                 else
683                     procName = chs->Item(j)->m_PartLast;
684 
685                 TokensArrayF* modChs = &modToken->m_Children;
686                 TokenKindF tk;
687                 bool found = false;
688                 for (size_t k=0; k<modChs->GetCount(); k++)
689                 {
690                     if ((modChs->Item(k)->m_TokenKind == tkSubroutine || modChs->Item(k)->m_TokenKind == tkFunction) &&
691                             modChs->Item(k)->m_Name.IsSameAs(procName))
692                     {
693                         tk = modChs->Item(k)->m_TokenKind;
694                         found = true;
695                         break;
696                     }
697                     else if (modChs->Item(k)->m_TokenKind == tkInterfaceExplicit)
698                     {
699                         TokensArrayF* intfExpChs = &modChs->Item(k)->m_Children;
700                         if (intfExpChs)
701                         {
702                             for (size_t m=0; m<intfExpChs->GetCount(); m++)
703                             {
704                                 if ((intfExpChs->Item(m)->m_TokenKind == tkSubroutine || intfExpChs->Item(m)->m_TokenKind == tkFunction) &&
705                                         intfExpChs->Item(m)->m_Name.IsSameAs(procName))
706                                 {
707                                     tk = intfExpChs->Item(m)->m_TokenKind;
708                                     found = true;
709                                     break;
710                                 }
711                             }
712                             if (found)
713                                 break;
714                         }
715                     }
716                 }
717 
718                 if (found)
719                 {
720                     if (tk == tkFunction)
721                         chs->Item(j)->m_TypeDefinition = _T("function");
722                     else
723                         chs->Item(j)->m_TypeDefinition = _T("subroutine");
724                 }
725             }
726             else if (chs->Item(j)->m_TokenKind == tkInterface)
727                 genericProc.Add(chs->Item(j));
728         }
729 
730         for (size_t k=0; k<genericProc.GetCount(); k++)
731         {
732             wxStringTokenizer tkz(genericProc.Item(k)->m_PartLast);
733             while (tkz.HasMoreTokens())
734             {
735                 wxString pron = tkz.GetNextToken().Lower();
736                 for (size_t j=0; j<chs->GetCount(); j++)
737                 {
738                     if (chs->Item(j)->m_TokenKind == tkProcedure && chs->Item(j)->m_Name.IsSameAs(pron))
739                     {
740                         genericProc.Item(k)->m_TypeDefinition = chs->Item(j)->m_TypeDefinition;
741                         break;
742                     }
743                 }
744                 break;
745             }
746         }
747     }
748 
749     if (modToken->m_DocString.IsEmpty())
750     {
751         unsigned int ln = modToken->m_LineStart + modToken->m_DefinitionLength - 1;
752         docs.Clear();
753         GetDocBlock(docs, true, ln, true); // look bellow the declaration for the non-doxyblocks documentation.
754         if (docs.HasBrief() || docs.HasDescription())
755             modToken->m_DocString << docs.GetBrief() + m_Briefend + docs.GetDescription();
756     }
757 }
758 
HandleSubmodule()759 void ParserThreadF::HandleSubmodule()
760 {
761     TokenF* old_parent = m_pLastParent;
762     unsigned int defStartLine = m_Tokens.GetLineNumber();
763     wxString ancestorModule;
764     wxString parentSubmodule;
765     wxString submName;
766 
767     wxString token = m_Tokens.GetTokenSameFortranLine();
768 
769     if (!token.IsEmpty() && token(0,1).Matches(_T("(")))
770     {
771         token = token.Mid(1).BeforeFirst(')');
772         int i = token.Find(':');
773         if (i != wxNOT_FOUND)
774         {
775             ancestorModule = token.Mid(0,i).Trim().Trim(false);
776             if (i+1 < int(token.Length()))
777                 parentSubmodule = token.Mid(i+1).Trim().Trim(false);
778         }
779         else
780             ancestorModule = token.Trim().Trim(false);
781 
782         token = m_Tokens.GetTokenSameFortranLine();
783         if (!token.IsEmpty())
784             submName = token;
785         else
786             submName = _T("unnamed");
787     }
788     else if(token.IsEmpty())
789         submName = _T("unnamed");
790     else
791         submName = token;
792 
793     SubmoduleTokenF* pSubmodToken = DoAddSubmoduleToken(submName, ancestorModule, parentSubmodule, defStartLine);
794     m_pLastParent = pSubmodToken;
795 
796     while (1)
797     {
798         token = m_Tokens.GetToken();
799         if (token.IsEmpty())
800             break;
801         wxString tok_low = token.Lower();
802 
803         wxString next = m_Tokens.PeekToken();
804         wxString nex_low = next.Lower();
805         if ( ((m_Tokens.GetLineNumber() == m_Tokens.GetPeekedLineNumber()) && IsEnd(tok_low, nex_low)) ||
806                 ((m_Tokens.GetLineNumber() != m_Tokens.GetPeekedLineNumber()) && IsEnd(tok_low, _T(""))) )
807         {
808             m_Tokens.SkipToOneOfChars(";", true);
809             break;
810         }
811         else if (tok_low.Matches(_T("type")) && !nex_low(0,1).Matches(_T("(")))
812         {
813             HandleType();
814         }
815         else if (tok_low.Matches(_T("subroutine")))
816         {
817             HandleFunction(tkSubroutine);
818         }
819         else if (tok_low.Matches(_T("function")))
820         {
821             HandleFunction(tkFunction);
822         }
823         else if (tok_low.Matches(_T("use")))
824         {
825             HandleUse();
826         }
827         else if (tok_low.Matches(_T("interface")))
828         {
829             HandleInterface();
830         }
831         else if (tok_low.Matches(_T("include")))
832         {
833             HandleInclude();
834         }
835         else if (tok_low.GetChar(0) == '#')
836         {
837             HandlePPDirective(token);
838         }
839         else if (tok_low.Matches(_T("module")) && nex_low.Matches(_T("procedure")))
840         {
841             m_Tokens.GetToken();
842             HandleSubmoduleProcedure();
843         }
844         else
845         {
846             bool needDefault=true;
847             bool hasFunctionInLine;
848             TokensArrayF tokTmpArr;
849             CheckParseOneDeclaration(token, tok_low, next, nex_low, needDefault, tokTmpArr, hasFunctionInLine);
850         }
851     }
852     pSubmodToken->AddLineEnd(m_Tokens.GetLineNumber());
853     m_pLastParent = old_parent;
854 }
855 
DoAddModuleToken(const wxString & modName)856 ModuleTokenF* ParserThreadF::DoAddModuleToken(const wxString& modName)
857 {
858     ModuleTokenF* newToken = new ModuleTokenF();
859     newToken->m_Name = modName.Lower();
860 
861     newToken->m_TokenKind = tkModule;
862     newToken->m_pParent = m_pLastParent;
863     newToken->m_Filename = m_Tokens.GetFilename();
864     newToken->m_DisplayName = modName;
865     newToken->m_TypeDefinition = wxEmptyString;
866 
867     newToken->m_LineStart = m_Tokens.GetLineNumber();
868     newToken->m_DefinitionLength = 1;
869 
870     if (m_pLastParent)
871     {
872         m_pLastParent->AddChild(newToken);
873     }
874     else
875     {
876         m_pTokens->Add(newToken);
877     }
878 
879     return newToken;
880 }
881 
DoAddSubmoduleToken(const wxString & submName,const wxString & ancestorModule,const wxString & parentSubmodule,unsigned int defStartLine)882 SubmoduleTokenF* ParserThreadF::DoAddSubmoduleToken(const wxString& submName, const wxString& ancestorModule,
883                                                     const wxString& parentSubmodule, unsigned int defStartLine)
884 {
885     SubmoduleTokenF* newToken = new SubmoduleTokenF();
886     newToken->m_Name = ancestorModule.Lower();
887     newToken->m_Name << _T(":") << submName.Lower();
888     newToken->m_TokenKind = tkSubmodule;
889     newToken->m_pParent = m_pLastParent;
890     newToken->m_Filename = m_Tokens.GetFilename();
891     newToken->m_DisplayName = submName;
892     newToken->m_DisplayName << _T(" (") << ancestorModule;
893     if (!parentSubmodule.IsEmpty())
894         newToken->m_DisplayName << _T(":") << parentSubmodule;
895     newToken->m_DisplayName << _T(")");
896     newToken->m_TypeDefinition = wxEmptyString;
897 
898     newToken->m_LineStart = defStartLine;
899     newToken->m_DefinitionLength = 1;
900 
901     newToken->m_AncestorModuleName = ancestorModule.Lower();
902     newToken->m_ParentSubmoduleName = parentSubmodule.Lower();
903 
904     if (m_pLastParent)
905         m_pLastParent->AddChild(newToken);
906     else
907         m_pTokens->Add(newToken);
908 //
909 //    TokenF* oldParent = m_pLastParent;
910 //    m_pLastParent = newToken;
911 //    wxString useName = ancestorModule.Lower();
912 //    useName << _T(":") << parentSubmodule.Lower();
913 //    UseTokenF* pUseTok = DoAddUseToken(useName);
914 //    pUseTok->SetModuleNature(mnNonIntrinsic);
915 //    m_pLastParent = oldParent;
916 
917     return newToken;
918 }
919 
HandleType()920 void ParserThreadF::HandleType()
921 {
922     bool needDefault;
923     TokenF* newToken = 0;
924     HandleType(needDefault, newToken);
925 }
926 
HandleType(bool & needDefault,TokenF * & newToken)927 void ParserThreadF::HandleType(bool& needDefault, TokenF* &newToken)
928 {
929     needDefault = true;
930     TokenAccessKind taKind = taPublic;
931     wxString typeName;
932     wxString exTypeName;
933     wxArrayString lineTok = m_Tokens.GetTokensToEOL();
934     wxArrayString lineTokLw;
935     wxString wholeLine;
936     bool isAbstract = false;
937     MakeArrayStringLower(lineTok, lineTokLw);
938     int idx = lineTok.Index(_T("::"));
939     if (idx != wxNOT_FOUND)
940     {
941         if (idx+1 < int(lineTok.GetCount()))
942         {
943             typeName = lineTok.Item(idx+1);
944             int idex = lineTokLw.Index(_T("extends"),false);
945             if (idex != wxNOT_FOUND)
946             {
947                 if (idex <= idx-2)
948                 {
949                     wxString ex = lineTok.Item(idex+1);
950                     int idx_a = ex.Find('(');
951                     int idx_b = ex.Find(')', true);
952                     if ( idx_a != wxNOT_FOUND && idx_b != wxNOT_FOUND && idx_a < (idx_b-1) )
953                     {
954                         exTypeName = ex.Mid(idx_a+1,idx_b-idx_a-1).Trim().Trim(false);
955                     }
956                 }
957             }
958 
959             idex = lineTokLw.Index(_T("private"));
960             if (idex != wxNOT_FOUND && idex < idx)
961             {
962                 taKind = taPrivate;
963                 needDefault = false;
964             }
965             else
966             {
967                 idex = lineTokLw.Index(_T("public"));
968                 if (idex != wxNOT_FOUND && idex < idx)
969                 {
970                     taKind = taPublic;
971                     needDefault = false;
972                 }
973             }
974 
975             idex = lineTokLw.Index(_T("abstract"));
976             if (idex != wxNOT_FOUND && idex < idx)
977             {
978                 isAbstract = true;
979             }
980         }
981         else
982         {
983             //something wrong
984             return;
985         }
986 
987         for (int i=0; i<idx; i++)
988         {
989             if (lineTokLw.Item(i+1).StartsWith(_T("(")) || i+1 == idx)
990                 wholeLine << lineTokLw.Item(i);
991             else
992                 wholeLine << lineTokLw.Item(i) << _T(",");
993 
994         }
995         wholeLine << _T("::");
996         for (size_t i=idx+1; i<lineTokLw.size(); i++)
997             wholeLine << lineTokLw.Item(i);
998     }
999     else
1000     {
1001         if (lineTok.GetCount() > 0)
1002         {
1003             typeName = lineTok.Item(0);
1004         }
1005         else
1006         {
1007             //something wrong
1008             return;
1009         }
1010         for (size_t i=0; i<lineTokLw.size(); i++)
1011             wholeLine << _T(" ") << lineTokLw.Item(i);
1012     }
1013     TokenF* old_parent = m_pLastParent;
1014     m_pLastParent = DoAddToken(tkType, typeName);
1015     m_pLastParent->m_ExtendsType = exTypeName;
1016     m_pLastParent->m_TokenAccess = taKind;
1017     m_pLastParent->m_IsAbstract = isAbstract;
1018     m_pLastParent->m_TypeDefinition = wholeLine;
1019 
1020     // Parse documentation
1021     DocBlock docs;
1022     GetDocBlock(docs, false, m_pLastParent->m_LineStart, true);
1023     if (docs.HasBrief() || docs.HasDescription())
1024         m_pLastParent->m_DocString << docs.GetBrief() + m_Briefend + docs.GetDescription();
1025 
1026     ParseDeclarations(true, true);
1027 
1028     if (m_LastTokenName.IsSameAs(_T("contains")))
1029         ParseTypeBoundProcedures(wxEmptyString, false);
1030 
1031     if (m_pLastParent->m_DocString.IsEmpty())
1032     {
1033         docs.Clear();
1034         GetDocBlock(docs, true, m_pLastParent->m_LineStart, true); // look bellow the declaration for the non-doxyblocks documentation.
1035         if (docs.HasBrief() || docs.HasDescription())
1036             m_pLastParent->m_DocString << docs.GetBrief() + m_Briefend + docs.GetDescription();
1037     }
1038 
1039     m_pLastParent->AddLineEnd(m_Tokens.GetLineNumber());
1040     newToken = m_pLastParent;
1041     m_pLastParent = old_parent;
1042 }
1043 
CheckParseOneDeclaration(wxString & token,wxString & tok_low,wxString & next,wxString & next_low,bool & needDefault,TokensArrayF & newTokenArr,bool & hasFunctionInLine)1044 void ParserThreadF::CheckParseOneDeclaration(wxString& token, wxString& tok_low, wxString& next, wxString& next_low,
1045                                              bool& needDefault, TokensArrayF& newTokenArr, bool& hasFunctionInLine)
1046 {
1047     hasFunctionInLine = false;
1048     if ( tok_low.IsSameAs(_T("integer")) || tok_low.IsSameAs(_T("real"))
1049             || tok_low.IsSameAs(_T("doubleprecision")) || tok_low.IsSameAs(_T("character"))
1050             || tok_low.IsSameAs(_T("complex")) || tok_low.IsSameAs(_T("logical"))
1051             || ( tok_low.IsSameAs(_T("double")) && next_low.IsSameAs(_T("precision")) )
1052             || ( tok_low.IsSameAs(_T("type")) && next_low.StartsWith(_T("(")) )
1053             || ( tok_low.IsSameAs(_T("class")) && next_low.StartsWith(_T("(")) )
1054             || tok_low.IsSameAs(_T("enumerator"))
1055        )
1056     {
1057         wxArrayString lineTok = m_Tokens.PeekTokensToEOL();
1058         if (lineTok.Index(_T("function"), false) == wxNOT_FOUND)
1059         {
1060             DocBlock docs;
1061             GetDocBlock(docs, false, m_Tokens.GetLineNumber(), false);
1062 
1063             bool found = ParseDeclarationsFirstPart(token, next);
1064             if (found)
1065             {
1066                 int ntold = newTokenArr.size();
1067                 ParseDeclarationsSecondPart(token, needDefault, newTokenArr);
1068 
1069                 int ntnew = newTokenArr.size();
1070                 if ((ntnew-ntold) > 0 && (docs.HasDescription() || docs.HasBrief()))
1071                 {
1072                     for (int i=ntold; i<ntnew; i++)
1073                     {
1074                         if (newTokenArr.Item(i)->m_DocString.IsEmpty())
1075                             newTokenArr.Item(i)->m_DocString << docs.GetBrief() + m_Briefend + docs.GetDescription();
1076                     }
1077                 }
1078             }
1079         }
1080         else
1081         {
1082             hasFunctionInLine = true;
1083         }
1084     }
1085 }
1086 
1087 
ParseDeclarations(bool breakAtEnd,bool breakAtContains)1088 void ParserThreadF::ParseDeclarations(bool breakAtEnd, bool breakAtContains)
1089 {
1090     TokenAccessKind taDefKind = taPublic;
1091     TokensArrayF tokArr;
1092     while (1)
1093     {
1094         wxString token = m_Tokens.GetToken();
1095         m_LastTokenName = token.Lower();
1096         wxString next = m_Tokens.PeekToken();
1097         if (m_LastTokenName.IsEmpty())
1098         {
1099             break;
1100         }
1101         else if (m_LastTokenName.IsSameAs(_T("include")))
1102         {
1103             HandleInclude();
1104         }
1105         else if (m_LastTokenName.GetChar(0) == '#')
1106         {
1107             HandlePPDirective(token);
1108         }
1109         else if (m_LastTokenName.IsSameAs(_T("interface")))
1110         {
1111             HandleInterface(taDefKind);
1112         }
1113         else if (breakAtEnd &&
1114                  ( ((m_Tokens.GetLineNumber() == m_Tokens.GetPeekedLineNumber()) && IsEnd(m_LastTokenName, next.Lower())) ||
1115                    ((m_Tokens.GetLineNumber() != m_Tokens.GetPeekedLineNumber()) && IsEnd(m_LastTokenName, _T(""))) ))
1116         {
1117             m_Tokens.SkipToOneOfChars(";", true);
1118             break;
1119         }
1120         else if (breakAtContains && m_LastTokenName.IsSameAs(_T("contains")))
1121         {
1122             m_Tokens.SkipToOneOfChars(";", true);
1123             break;
1124         }
1125         else if (m_LastTokenName.IsSameAs(_T("private")))
1126         {
1127             bool changeDefault;
1128             int cal=0;
1129             wxArrayString pnList;
1130             HandleAccessList(taPrivate, changeDefault, cal, pnList);
1131             if (changeDefault)
1132             {
1133                 taDefKind = taPrivate;
1134             }
1135         }
1136         else if (m_LastTokenName.IsSameAs(_T("public")))
1137         {
1138             bool changeDefault;
1139             int cal=0;
1140             wxArrayString pnList;
1141             HandleAccessList(taPublic, changeDefault, cal, pnList);
1142             if (changeDefault)
1143             {
1144                 taDefKind = taPublic;
1145             }
1146         }
1147         else if (m_LastTokenName.IsSameAs(_T("block")) && !next.Lower().IsSameAs(_T("data")))
1148         {
1149             HandleBlockConstruct();
1150         }
1151         else if (m_LastTokenName.IsSameAs(_T("procedure")))
1152         {
1153             ParseTypeBoundProcedures(m_LastTokenName, true, false);
1154         }
1155 
1156         wxArrayString lineTok = m_Tokens.PeekTokensToEOL();
1157         int funIdx = lineTok.Index(_T("function"), false);
1158         if (funIdx == wxNOT_FOUND || (funIdx > 2))
1159         {
1160             DocBlock docs;
1161             GetDocBlock(docs, false, m_Tokens.GetLineNumber(), false);
1162 
1163             bool found = ParseDeclarationsFirstPart(token, next);
1164             if (found)
1165             {
1166                 bool nDef=true;
1167                 TokensArrayF tokArrTmp;
1168                 ParseDeclarationsSecondPart(token, nDef, tokArrTmp);
1169                 if (nDef)
1170                 {
1171                     for (size_t i=0; i<tokArrTmp.Count(); i++)
1172                     {
1173                         tokArr.Add(tokArrTmp.Item(i));
1174                     }
1175                 }
1176                 int tac = tokArrTmp.Count();
1177                 if (tac > 0 && (docs.HasDescription() || docs.HasBrief()))
1178                 {
1179                     for (int i=0; i<tac; i++)
1180                     {
1181                         if (tokArrTmp.Item(i)->m_DocString.IsEmpty())
1182                             tokArrTmp.Item(i)->m_DocString << docs.GetBrief() + m_Briefend + docs.GetDescription();
1183                     }
1184                 }
1185             }
1186         }
1187     }
1188     for (size_t i=0; i<tokArr.Count(); i++)
1189     {
1190         tokArr.Item(i)->m_TokenAccess = taDefKind;
1191     }
1192     return;
1193 }
1194 
1195 
ParseDeclarationsFirstPart(wxString & token,wxString & next)1196 bool ParserThreadF::ParseDeclarationsFirstPart(wxString& token, wxString& next)
1197 {
1198     wxString tok_low = token.Lower();
1199     wxString next_low = next.Lower();
1200     bool found = false;
1201 
1202     if ( tok_low.IsSameAs(_T("integer")) || tok_low.IsSameAs(_T("real"))
1203             || tok_low.IsSameAs(_T("doubleprecision")) || tok_low.IsSameAs(_T("character"))
1204             || tok_low.IsSameAs(_T("complex")) || tok_low.IsSameAs(_T("logical"))
1205             || tok_low.IsSameAs(_T("enumerator")) )
1206     {
1207         if (next_low.StartsWith(_T("(")))
1208         {
1209             token.Append(next);
1210             m_Tokens.GetToken();
1211         }
1212         else if (next_low.StartsWith(_T("*")))
1213         {
1214             token.Append(m_Tokens.GetToken());
1215             token.Append(m_Tokens.GetTokenSameFortranLine());
1216         }
1217         found = true;
1218     }
1219     else if (tok_low.IsSameAs(_T("double")))
1220     {
1221         if (next_low.IsSameAs(_T("precision")))
1222         {
1223             found = true;
1224             token.Append(_T(" "));
1225             token.Append(next);
1226             m_Tokens.GetToken();
1227             next = m_Tokens.PeekToken();
1228             if (next.StartsWith(_T("(")))
1229             {
1230                 token.Append(next);
1231                 m_Tokens.GetToken();
1232             }
1233         }
1234     }
1235     else if (tok_low.IsSameAs(_T("type")) || tok_low.IsSameAs(_T("class")))
1236     {
1237         if (next_low.StartsWith(_T("(")))
1238         {
1239             if (next_low.EndsWith(_T(")")))
1240             {
1241                 wxString token_s = m_Tokens.GetToken();
1242                 token_s = token_s.Mid(1,token_s.Len()-2).Trim().Trim(false);
1243                 token.Append(_T("("));
1244                 token.Append(token_s);
1245                 token.Append(_T(")"));
1246                 found = true;
1247             }
1248             else
1249             {
1250                 //something wrong
1251                 m_Tokens.SkipToOneOfChars(";", true);
1252             }
1253         }
1254         else if (tok_low.IsSameAs(_T("type"))  && !next_low.IsSameAs(_T("is")))
1255         {
1256             // we found type definition
1257             HandleType();
1258         }
1259     }
1260     return found;
1261 }
1262 
1263 
ParseDeclarationsSecondPart(wxString & token,bool & needDefault,TokensArrayF & newTokenArr)1264 void ParserThreadF::ParseDeclarationsSecondPart(wxString& token, bool& needDefault, TokensArrayF& newTokenArr)
1265 {
1266     needDefault = true;
1267     TokenAccessKind taKind = taPublic;
1268     wxString defT = token;
1269     wxString dims;
1270     wxArrayString linesArr;
1271     m_Tokens.SetDetailedParsing(true);
1272     wxArrayString lineTok = m_Tokens.GetTokensToEOL(&linesArr);
1273     m_Tokens.SetDetailedParsing(false);
1274     int idx = lineTok.Index(_T("::"));
1275     if (idx != wxNOT_FOUND)
1276     {
1277         for (int i=0; i<idx; i++)
1278         {
1279             if (lineTok.Item(i).IsSameAs(_T(",")))
1280                 continue;
1281 
1282             if (!lineTok.Item(i).StartsWith(_T("(")))
1283             {
1284                 defT.Append(_T(", "));
1285             }
1286             defT.Append(lineTok.Item(i));
1287 
1288             wxString tokLw = lineTok.Item(i).Lower();
1289             if (tokLw.IsSameAs(_T("private")))
1290             {
1291                 taKind = taPrivate;
1292                 needDefault = false;
1293             }
1294             else if (tokLw.IsSameAs(_T("protected")))
1295             {
1296                 taKind = taProtected;
1297                 needDefault = false;
1298             }
1299             else if (tokLw.IsSameAs(_T("public")))
1300             {
1301                 taKind = taPublic;
1302                 needDefault = false;
1303             }
1304 
1305             if (tokLw.IsSameAs(_T("dimension")) && lineTok.Item(i+1).StartsWith(_T("(")))
1306             {
1307                 dims.Append(lineTok.Item(i+1));
1308             }
1309         }
1310     }
1311     else // "::" not found
1312     {
1313         if (lineTok.GetCount() > 0 && lineTok.Item(0).IsSameAs(_T(",")))
1314         {
1315             // it is unfinished declaration (e.g. "real, pointer, ")
1316             return;
1317         }
1318         idx = -1;
1319     }
1320 
1321     wxArrayString varNames;
1322     wxArrayString varArgs;
1323     wxArrayString varComs;
1324     wxArrayString varDims;
1325     for (size_t i=idx+1; i<lineTok.GetCount(); )
1326     {
1327         wxString var1= lineTok.Item(i);
1328         if (var1.IsSameAs(_T(",")))
1329         {
1330             i++;
1331             continue;
1332         }
1333         wxString arg1;
1334         wxString dim1;
1335         while (i+1 < lineTok.GetCount())
1336         {
1337             wxString s = lineTok.Item(i+1);
1338             if ((s.StartsWith(_T("(")) && s.EndsWith(_T(")"))) || (s.StartsWith(_T("[")) && s.EndsWith(_T("]"))))
1339             {
1340                 arg1 << s;
1341                 i++;
1342             }
1343             else
1344                 break;
1345         }
1346         dim1 << arg1;
1347         if (i+1 < lineTok.GetCount() && (lineTok.Item(i+1).IsSameAs(_T("=>")) || lineTok.Item(i+1).IsSameAs(_T("="))
1348                                          || lineTok.Item(i+1).IsSameAs(_T("*"))) )
1349         {
1350             i += 1;
1351             for (; i<lineTok.GetCount(); i++)
1352             {
1353                 if (lineTok.Item(i).IsSameAs(_T(",")))
1354                     break;
1355                 else
1356                     arg1 << lineTok.Item(i);
1357             }
1358             if(i >= lineTok.GetCount())
1359             {
1360                 i = lineTok.GetCount() - 1;
1361             }
1362         }
1363         wxString comStr = linesArr.Item(i).AfterFirst('!');
1364         if (comStr.StartsWith(_T("<")) || comStr.StartsWith(_T(">")))
1365             comStr = comStr.Mid(1);
1366         comStr = comStr.Trim(true).Trim(false);
1367 
1368         varNames.Add(var1);
1369         varArgs.Add(arg1);
1370         varComs.Add(comStr);
1371         if (dim1.IsEmpty())
1372             varDims.Add(dims);
1373         else
1374             varDims.Add(dim1);
1375         i++;
1376     }
1377     for (size_t i=0; i<varNames.GetCount(); i++)
1378     {
1379         TokenF* tok = DoAddToken(tkVariable, varNames[i], varArgs[i], defT);
1380         tok->m_DocString = varComs.Item(i);
1381         tok->m_TokenAccess = taKind;
1382         tok->AddLineEnd(tok->m_LineStart);
1383         if (varDims.Item(i).IsEmpty())
1384         {
1385             tok->AddPartFirst(token);
1386         }
1387         else
1388         {
1389             wxString tokStr = token + _T(", ") + varDims.Item(i);
1390             tok->AddPartFirst(tokStr);
1391         }
1392         newTokenArr.Add(tok);
1393     }
1394     return;
1395 }
1396 
1397 
HandleSubmoduleProcedure()1398 void ParserThreadF::HandleSubmoduleProcedure()
1399 {
1400     wxString token;
1401     token = m_Tokens.GetTokenSameFortranLine();
1402 
1403     TokenF* old_parent = m_pLastParent;
1404     m_pLastParent = DoAddToken(tkProcedure, token);
1405 
1406     GoThroughBody();
1407 
1408     m_pLastParent->AddLineEnd(m_Tokens.GetLineNumber());
1409     m_pLastParent = old_parent;
1410 }
1411 
1412 
HandleFunction(TokenKindF kind,TokenAccessKind taKind)1413 void ParserThreadF::HandleFunction(TokenKindF kind, TokenAccessKind taKind)
1414 {
1415     m_ParentDocs.Clear();
1416     unsigned int ln = m_Tokens.GetLineNumber();
1417     GetDocBlock(m_ParentDocs, false, ln, true);
1418 
1419     wxString token;
1420     token = m_Tokens.GetTokenSameFortranLine();
1421 
1422     if (token.IsEmpty() && kind == tkProgram)
1423         token = _T("unnamed");
1424 
1425     unsigned int defStartLine = m_Tokens.GetLineNumber();
1426     TokenF* old_parent = m_pLastParent;
1427     wxString args = m_Tokens.PeekTokenSameFortranLine();
1428 
1429     if (args.IsEmpty() || !args(0,1).Matches(_T("(")))
1430         args = _T("()");
1431     else
1432         args = m_Tokens.GetTokenSameFortranLine();
1433     m_pLastParent = DoAddToken(kind, token, args, defStartLine);
1434     m_pLastParent->m_TokenAccess = taKind;
1435     if (m_ParentDocs.HasBrief() || m_ParentDocs.HasDescription())
1436         m_pLastParent->m_DocString << m_ParentDocs.GetBrief() + m_Briefend + m_ParentDocs.GetDescription();
1437 
1438     if (kind == tkFunction)
1439     {
1440         wxString funkLine = m_Tokens.GetLineFortran();
1441         wxString funkLineLow = funkLine.Lower();
1442         int i_fun = funkLineLow.Find(_T("function"));
1443         if (i_fun != wxNOT_FOUND)
1444         {
1445             m_pLastParent->AddPartFirst(funkLine.Mid(0,i_fun).Trim().Trim(false));
1446             wxString secPart = funkLine.Mid(i_fun+8);
1447             i_fun = secPart.Find(')');
1448             if (i_fun != wxNOT_FOUND && (int)secPart.Len() > i_fun+1)
1449             {
1450                 wxString lastPart = secPart.Mid(i_fun+1).Trim().Trim(false);
1451                 m_pLastParent->AddPartLast(lastPart);
1452                 wxString lastPartLow = lastPart.Lower();
1453                 i_fun = lastPartLow.Find(_T("result"));
1454                 if (i_fun != wxNOT_FOUND)
1455                 {
1456                     wxString el = lastPartLow.Mid(i_fun+6);
1457                     int is = el.Find('(');
1458                     int ie = el.Find(')');
1459                     if (is != wxNOT_FOUND && ie != wxNOT_FOUND && ie > is)
1460                         m_pLastParent->AddResultVariable(el.Mid(is+1,ie-is-1).Trim().Trim(false));
1461                 }
1462             }
1463         }
1464     }
1465     GoThroughBody();
1466     m_pLastParent->AddLineEnd(m_Tokens.GetLineNumber());
1467     AddParamDocs(m_pLastParent, m_ParentDocs);
1468 
1469     if (m_pLastParent->m_DocString.IsEmpty())
1470     {
1471         ln = m_pLastParent->m_LineStart + m_pLastParent->m_DefinitionLength - 1;
1472         DocBlock doc;
1473         GetDocBlock(doc, true, ln, true); // look bellow the declaration for the non-doxyblocks documentation.
1474         if (doc.HasBrief() || doc.HasDescription())
1475             m_pLastParent->m_DocString << doc.GetBrief() + m_Briefend + doc.GetDescription();
1476     }
1477 
1478     m_pLastParent = old_parent;
1479 }
1480 
1481 
HandleBlockConstruct()1482 void ParserThreadF::HandleBlockConstruct()
1483 {
1484     unsigned int defStartLine = m_Tokens.GetLineNumber();
1485     TokenF* old_parent = m_pLastParent;
1486     m_NumberOfBlockConstruct += 1;
1487     wxString name = _T("%%tkBlockConstruct");
1488     name << wxString::Format(_T("%.3d"), m_NumberOfBlockConstruct);
1489     m_pLastParent = DoAddToken(tkBlockConstruct, name, wxEmptyString, defStartLine);
1490 
1491     GoThroughBody();
1492     m_pLastParent->AddLineEnd(m_Tokens.GetLineNumber());
1493     m_pLastParent = old_parent;
1494 }
1495 
1496 
HandleAssociateConstruct()1497 void ParserThreadF::HandleAssociateConstruct()
1498 {
1499     TokenF* old_parent = m_pLastParent;
1500     wxString args = m_Tokens.PeekTokenSameFortranLine();
1501 
1502     if (args.IsEmpty() || !args(0,1).Matches(_T("(")))
1503         args = _T("()");
1504     else
1505         args = m_Tokens.GetTokenSameFortranLine();
1506     m_pLastParent = DoAddToken(tkAssociateConstruct, wxEmptyString, args, wxEmptyString);
1507 
1508     GoThroughBody();
1509     m_pLastParent->AddLineEnd(m_Tokens.GetLineNumber());
1510     m_pLastParent = old_parent;
1511 }
1512 
1513 
HandleSelectTypeConstruct()1514 void ParserThreadF::HandleSelectTypeConstruct()
1515 {
1516     TokenF* old_parent = m_pLastParent;
1517     wxString args = m_Tokens.PeekTokenSameFortranLine();
1518     if (args.IsEmpty() || !args(0,1).Matches(_T("(")))
1519         args = _T("()");
1520     else
1521         args = m_Tokens.GetTokenSameFortranLine();
1522 
1523     while (1)
1524     {
1525         wxString token = m_Tokens.GetToken();
1526         if (token.IsEmpty())
1527             break;
1528 
1529         wxString tok_low = token.Lower();
1530         wxString next    = m_Tokens.PeekToken();
1531         wxString nex_low = next.Lower();
1532 
1533         if ( (tok_low.Matches(_T("end")) && nex_low.Matches(_T("select"))) || tok_low.Matches(_T("endselect")) )
1534         {
1535             m_Tokens.SkipToOneOfChars(";", true);
1536             break;
1537         }
1538         else if ( (tok_low.Matches(_T("type")) && nex_low.Matches(_T("is"))) ||
1539                   (tok_low.Matches(_T("class")) && nex_low.Matches(_T("is"))) )
1540         {
1541             wxString defstr = tok_low;
1542             if (m_Tokens.GetToken().IsEmpty())
1543                 break;
1544             next = m_Tokens.PeekToken();
1545             nex_low = next.Lower();
1546             if (nex_low.StartsWith(_T("(")))
1547                 defstr << nex_low;
1548 
1549             m_pLastParent = DoAddToken(tkSelectTypeChild, wxEmptyString, args, defstr);
1550             GoThroughBody();
1551             m_pLastParent->AddLineEnd(m_Tokens.GetLineNumber());
1552             m_pLastParent = old_parent;
1553         }
1554         else if (tok_low.Matches(_T("class")) && nex_low.Matches(_T("default")))
1555         {
1556             m_pLastParent = DoAddToken(tkSelectTypeDefault, wxEmptyString, args, wxEmptyString);
1557             GoThroughBody();
1558             m_pLastParent->AddLineEnd(m_Tokens.GetLineNumber());
1559             m_pLastParent = old_parent;
1560         }
1561         else if (tok_low.Matches(_T("include")))
1562         {
1563             HandleInclude();
1564         }
1565         else if (tok_low.GetChar(0) == '#')
1566         {
1567             HandlePPDirective(token);
1568         }
1569     }
1570     m_pLastParent = old_parent;
1571 }
1572 
1573 
HandleSelectCaseConstruct()1574 void ParserThreadF::HandleSelectCaseConstruct()
1575 {
1576     // we are not interesting in SelectCase, but we need to catch EndSelect
1577     GoThroughBody();
1578     m_Tokens.GetToken();
1579     m_Tokens.SkipToOneOfChars(";", true);
1580 }
1581 
1582 
HandleInterface(TokenAccessKind taKind)1583 void ParserThreadF::HandleInterface(TokenAccessKind taKind)
1584 {
1585     TokenF* tokTmp = 0;
1586     bool isGeneric;
1587     HandleInterface(taKind, tokTmp, isGeneric);
1588 }
1589 
HandleInterface(TokenAccessKind taKind,TokenF * & tokNew,bool & isGeneric)1590 void ParserThreadF::HandleInterface(TokenAccessKind taKind, TokenF* &tokNew, bool &isGeneric)
1591 {
1592     isGeneric = false;
1593     TokenF* old_parent = m_pLastParent;
1594     unsigned int defStartLine = m_Tokens.GetLineNumber();
1595     wxArrayString curLineArr = m_Tokens.GetTokensToEOL();
1596     wxString name;
1597     TokenKindF tokKin;
1598     if (curLineArr.GetCount() > 0)
1599     {
1600         wxString low = curLineArr.Item(0).Lower();
1601         if (low.IsSameAs(_T("operator")))
1602         {
1603             name.Append(_T("%%"));
1604             name.Append(curLineArr.Item(0));
1605             for (unsigned int i=1; i<curLineArr.GetCount(); i++)
1606             {
1607                 name.Append(_T(" "));
1608                 name.Append(curLineArr.Item(i));
1609             }
1610             m_InterfaceOperator += 1;
1611             if (m_InterfaceOperator > 1)
1612             {
1613                 name << _T(" #") << m_InterfaceOperator;
1614             }
1615         }
1616         else if (low.IsSameAs(_T("assignment")))
1617         {
1618             name.Append(_T("%%"));
1619             name.Append(curLineArr.Item(0));
1620             for (unsigned int i=1; i<curLineArr.GetCount(); i++)
1621             {
1622                 name.Append(_T(" "));
1623                 name.Append(curLineArr.Item(i));
1624             }
1625             m_InterfaceAssignment += 1;
1626             if (m_InterfaceAssignment > 1)
1627             {
1628                 name << _T(" #") << m_InterfaceAssignment;
1629             }
1630         }
1631         else if (low.IsSameAs(_T("read")))
1632         {
1633             name.Append(_T("%%"));
1634             name.Append(curLineArr.Item(0));
1635             for (unsigned int i=1; i<curLineArr.GetCount(); i++)
1636             {
1637                 name.Append(_T(" "));
1638                 name.Append(curLineArr.Item(i));
1639             }
1640             m_InterfaceRead += 1;
1641             if (m_InterfaceRead > 1)
1642             {
1643                 name << _T(" #") << m_InterfaceRead;
1644             }
1645         }
1646         else if (low.IsSameAs(_T("write")))
1647         {
1648             name.Append(_T("%%"));
1649             name.Append(curLineArr.Item(0));
1650             for (unsigned int i=1; i<curLineArr.GetCount(); i++)
1651             {
1652                 name.Append(_T(" "));
1653                 name.Append(curLineArr.Item(i));
1654             }
1655             m_InterfaceWrite += 1;
1656             if (m_InterfaceWrite > 1)
1657             {
1658                 name << _T(" #") << m_InterfaceWrite;
1659             }
1660         }
1661         else
1662         {
1663             // generic procedure name
1664             name.Append(curLineArr.Item(0));
1665             for (unsigned int i=1; i<curLineArr.GetCount(); i++)
1666             {
1667                 name.Append(_T(" "));
1668                 name.Append(curLineArr.Item(i));
1669             }
1670             isGeneric = true;
1671         }
1672         tokKin = tkInterface;
1673     }
1674     else
1675     {
1676         tokKin = tkInterfaceExplicit;
1677     }
1678 
1679     m_pLastParent = DoAddToken(tokKin, name, wxEmptyString, defStartLine);
1680     m_pLastParent->m_TokenAccess = taKind;
1681     tokNew = m_pLastParent;
1682 
1683     GoThroughBody();
1684 
1685     if (tokKin == tkInterfaceExplicit)
1686     {
1687         TokensArrayF* toks = &m_pLastParent->m_Children;
1688         if (toks)
1689         {
1690             for (size_t i=0; i<toks->GetCount(); i++)
1691             {
1692                 toks->Item(i)->m_TokenAccess = taKind;
1693             }
1694         }
1695     }
1696 
1697     m_pLastParent->AddLineEnd(m_Tokens.GetLineNumber());
1698 
1699     if (isGeneric)
1700     {
1701         // Parse documentation
1702         DocBlock docs;
1703         GetDocBlock(docs, false, m_pLastParent->m_LineStart, true);
1704         if (docs.HasBrief() || docs.HasDescription())
1705             m_pLastParent->m_DocString << docs.GetBrief() + m_Briefend + docs.GetDescription();
1706         else
1707         {
1708             docs.Clear();
1709             GetDocBlock(docs, true, m_pLastParent->m_LineStart, true); // look bellow the declaration for the non-doxyblocks documentation.
1710             if (docs.HasBrief() || docs.HasDescription())
1711                 m_pLastParent->m_DocString << docs.GetBrief() + m_Briefend + docs.GetDescription();
1712         }
1713     }
1714 
1715     m_pLastParent = old_parent;
1716 }
1717 
HandleBlockData()1718 void ParserThreadF::HandleBlockData()
1719 {
1720     TokenF* old_parent = m_pLastParent;
1721     wxString token = m_Tokens.GetTokenSameLine();
1722     if (token.IsEmpty())
1723         m_pLastParent = DoAddToken(tkBlockData, _T("BD_unnamed"));
1724     else
1725         m_pLastParent = DoAddToken(tkBlockData, token);
1726 
1727     while (1)
1728     {
1729         token = m_Tokens.GetToken();
1730         if (token.IsEmpty())
1731             break;
1732         wxString tok_low = token.Lower();
1733 
1734         wxString next = m_Tokens.PeekToken();
1735         wxString nex_low = next.Lower();
1736         if ( ((m_Tokens.GetLineNumber() == m_Tokens.GetPeekedLineNumber()) && IsEnd(tok_low, nex_low)) ||
1737                 ((m_Tokens.GetLineNumber() != m_Tokens.GetPeekedLineNumber()) && IsEnd(tok_low, _T(""))) )
1738         {
1739             m_Tokens.SkipToOneOfChars(";", true);
1740             break;
1741         }
1742         else if (tok_low.Matches(_T("include")))
1743         {
1744             HandleInclude();
1745         }
1746         else if (tok_low.GetChar(0) == '#')
1747         {
1748             HandlePPDirective(token);
1749         }
1750     }
1751     m_pLastParent->AddLineEnd(m_Tokens.GetLineNumber());
1752     m_pLastParent = old_parent;
1753 }
1754 
HandleInclude()1755 void ParserThreadF::HandleInclude()
1756 {
1757     wxString token = m_Tokens.GetTokenSameFortranLine();
1758 
1759     if (token.IsEmpty())
1760         return; // something wrong
1761     else if ((token.StartsWith(_T("\'")) || token.StartsWith(_T("\"")) || token.StartsWith(_T("<"))) &&
1762              (token.EndsWith(_T("\'")) || token.EndsWith(_T("\""))  || token.EndsWith(_T(">"))))
1763     {
1764         token = token.Mid(1,token.Len()-2).Trim().Trim(false);
1765         DoAddToken(tkInclude, token);
1766         m_IncludeList.Add(token);
1767     }
1768     else if (token.IsSameAs(_T("<")))
1769     {
1770         // Handle #include <filename.fpp>
1771         token = m_Tokens.GetTokenSameLine();
1772         if (m_Tokens.PeekTokenSameFortranLine().IsSameAs(_T(".")))
1773         {
1774             wxString point = m_Tokens.GetToken();
1775             token.Append(point + m_Tokens.GetTokenSameLine());
1776         }
1777         DoAddToken(tkInclude, token);
1778         m_IncludeList.Add(token);
1779         m_Tokens.SkipToEOL();
1780     }
1781 }
1782 
HandlePPDirective(wxString & token)1783 void ParserThreadF::HandlePPDirective(wxString& token)
1784 {
1785     if (token.Matches(_T("#define")))
1786         HandlePPDefine();
1787     else if (token.Matches(_T("#undefine")))
1788         HandlePPUndefine();
1789     else if (token.Matches(_T("#if")) || token.Matches(_T("#ifdef")) || token.Matches(_T("#ifndef")))
1790         HandlePPIfdef(token);
1791     else if (token.Matches(_T("#endif")) || token.Matches(_T("#else")) || token.Matches(_T("#elif")))
1792         HandlePPIfdef(token);
1793     else if (token.Matches(_T("#include")))
1794         HandleInclude();
1795     else
1796         m_Tokens.SkipToEOL();
1797 }
1798 
HandlePPDefine()1799 void ParserThreadF::HandlePPDefine()
1800 {
1801     // Handle #define ABC
1802     // More sophisticated cases isn't interpreted
1803     wxString token = m_Tokens.GetTokenSameLine();
1804 
1805     if (token.IsEmpty())
1806         return; // something wrong
1807 
1808     TokenF* newToken = new TokenF;
1809     newToken->m_TokenKind = tkMacroDefine;
1810     newToken->m_Filename = m_Tokens.GetFilename();
1811     newToken->m_DisplayName = token;
1812     newToken->m_LineStart = m_Tokens.GetLineNumber();
1813     newToken->m_LineEnd = 0;
1814 
1815     m_pPPDefineTokens->Add(newToken);
1816     m_Tokens.SkipToEOL();
1817 }
1818 
HandlePPUndefine()1819 void ParserThreadF::HandlePPUndefine()
1820 {
1821     // Handle #undefine ABC or #undef ABC
1822     wxString token = m_Tokens.GetTokenSameLine();
1823 
1824     if (token.IsEmpty())
1825         return; // something wrong
1826 
1827     for (size_t i=0; i<m_pPPDefineTokens->size(); ++i)
1828     {
1829         if (m_pPPDefineTokens->Item(i)->m_DisplayName == token)
1830         {
1831             m_pPPDefineTokens->Item(i)->m_LineEnd = m_Tokens.GetLineNumber();
1832             break;
1833         }
1834     }
1835     m_Tokens.SkipToEOL();
1836 }
1837 
HandlePPIfdef(wxString & ifToken)1838 void ParserThreadF::HandlePPIfdef(wxString& ifToken)
1839 {
1840     // Handle #ifdef construct in the simplest cases.
1841     if (ifToken.IsSameAs(_T("#ifdef")) || ifToken.IsSameAs(_T("#ifndef")))
1842     {
1843         m_inIfdef += 1;
1844         wxString token = m_Tokens.GetTokenSameLine();
1845         if (token.IsEmpty())
1846             return;
1847 
1848         bool hasDef = HasDefine(token, m_Tokens.GetLineNumber());
1849         if ((ifToken.IsSameAs(_T("#ifdef")) && hasDef) || (ifToken.IsSameAs(_T("#ifndef")) && !hasDef))
1850         {
1851             // Will be interpreted until correcponding #elif, #else or #endif
1852         }
1853         else
1854         {
1855             // Skip to the corresponding #elif #else or #endif
1856             m_Tokens.SkipToEOL();
1857             wxString lastTok;
1858             SkipPPIfdef(lastTok);
1859             if (lastTok.IsEmpty() || lastTok.IsSameAs(_T("#endif")))
1860                 m_inIfdef -= 1;
1861             else if (lastTok.IsSameAs(_T("#elif")))
1862                 HandlePPIfdef(lastTok);
1863         }
1864     }
1865     else if (ifToken.IsSameAs(_T("#if")) || ifToken.IsSameAs(_T("#elif")))
1866     {
1867         // More clever interpreter is required.
1868         // For now take as if defined in case of #if
1869         if (ifToken.IsSameAs(_T("#if")))
1870         {
1871             m_inIfdef += 1;
1872         }
1873         else
1874         {
1875             // Skip to the corresponding #endif
1876             wxString lastTok;
1877             while (true)
1878             {
1879                 m_Tokens.SkipToEOL();
1880                 SkipPPIfdef(lastTok);
1881                 if (lastTok.IsEmpty() || lastTok.IsSameAs(_T("#endif")))
1882                     break;
1883             }
1884             m_inIfdef -= 1;
1885         }
1886     }
1887     else if (ifToken.IsSameAs(_T("#else")))
1888     {
1889         // Skip to the corresponding #endif
1890         m_Tokens.SkipToEOL();
1891         wxString lastTok;
1892         SkipPPIfdef(lastTok);
1893         // here should be lastTok==#endif
1894         m_inIfdef -= 1;
1895     }
1896     else // #endif
1897         m_inIfdef -= 1;
1898 
1899     m_Tokens.SkipToEOL();
1900 }
1901 
HasDefine(const wxString & token,unsigned int lnum)1902 bool ParserThreadF::HasDefine(const wxString& token, unsigned int lnum)
1903 {
1904     size_t nDef = m_pPPDefineTokens->size();
1905     for (size_t i=0; i<nDef; ++i)
1906     {
1907         if (m_pPPDefineTokens->Item(i)->m_DisplayName.IsSameAs(token) &&
1908             (m_pPPDefineTokens->Item(i)->m_LineEnd == 0 ||
1909              m_pPPDefineTokens->Item(i)->m_LineEnd > lnum))
1910         {
1911             return true;
1912         }
1913     }
1914     return false;
1915 }
1916 
SkipPPIfdef(wxString & tokenAtEnd)1917 void ParserThreadF::SkipPPIfdef(wxString& tokenAtEnd)
1918 {
1919     // Skip to the next corresponding #elif, #else or #endif
1920     tokenAtEnd.clear();
1921     int start_inIfdef = m_inIfdef;
1922     while (true)
1923     {
1924         wxString token = m_Tokens.GetToken();
1925         if (token.IsEmpty())
1926             break;
1927 
1928         if (token.StartsWith(_T("#")))
1929         {
1930             if (token.IsSameAs(_T("#ifdef")) || token.IsSameAs(_T("#ifndef")))
1931             {
1932                 m_inIfdef += 1;
1933                 m_Tokens.SkipToEOL();
1934             }
1935             else if (m_inIfdef > start_inIfdef && token.IsSameAs(_T("#endif")))
1936             {
1937                 m_inIfdef -= 1;
1938                 m_Tokens.SkipToEOL();
1939             }
1940             else if (token.IsSameAs(_T("#define")))
1941                 continue; //HandlePPDefine();
1942             else if (token.IsSameAs(_T("#undefine")) || token.IsSameAs(_T("#undef")))
1943                 continue; //HandlePPUndefine();
1944             else if (m_inIfdef == start_inIfdef)
1945             {
1946                 tokenAtEnd = token;
1947                 break;
1948             }
1949         }
1950         else
1951             m_Tokens.SkipToEOL();
1952     }
1953     m_Tokens.SkipToEOL();
1954 }
1955 
HandleAccessList(TokenAccessKind taKind,bool & changeDefault,int & countAccess,wxArrayString & nameList)1956 void ParserThreadF::HandleAccessList(TokenAccessKind taKind, bool& changeDefault, int& countAccess, wxArrayString& nameList)
1957 {
1958     changeDefault = false;
1959     wxString curLine = m_Tokens.GetLineFortran().Lower().Trim(false);
1960     int ipp = wxNOT_FOUND;
1961     if (taKind == taPrivate)
1962         ipp = curLine.Find(_T("private"));
1963     else if (taKind == taPublic)
1964         ipp = curLine.Find(_T("public"));
1965     else if (taKind == taProtected)
1966         ipp = curLine.Find(_T("protected"));
1967 
1968     if (ipp == wxNOT_FOUND)
1969         return; // something is wrong
1970     else if (ipp != 0)
1971         return; // here private (public) is used as an attribute.
1972 
1973     unsigned int defStartLine = m_Tokens.GetLineNumber();
1974     wxArrayString curLineArr = m_Tokens.GetTokensToEOL();
1975     if (curLineArr.GetCount() == 0)
1976     {
1977         changeDefault = true;
1978         return;
1979     }
1980     countAccess++;
1981     wxString name;
1982     name = _T("AccessList");
1983     if (countAccess > 1)
1984         name << _T(" ") << countAccess;
1985 
1986     TokenF* token;
1987     token = DoAddToken(tkAccessList, name, wxEmptyString, defStartLine);
1988     token->AddLineEnd(m_Tokens.GetLineNumber());
1989     token->m_TokenAccess = taKind;
1990 
1991     nameList.Add(token->m_Name);
1992     size_t i=0;
1993     if (curLineArr.Item(0).IsSameAs(_T("::")))
1994         i=1;
1995     for (; i<curLineArr.GetCount(); i++)
1996     {
1997         nameList.Add(curLineArr.Item(i).Lower());
1998     }
1999 }
2000 
GoThroughBody()2001 void ParserThreadF::GoThroughBody()
2002 {
2003     wxString tok_low;
2004 
2005     while (1)
2006     {
2007         unsigned int ln_tokold = m_Tokens.GetLineNumber();
2008 
2009         wxString token = m_Tokens.GetToken();
2010         if (token.IsEmpty())
2011             break;
2012         else if (token.Matches(_T("::")))
2013         {
2014             m_Tokens.SkipToOneOfChars(";", true);
2015             continue;
2016         }
2017         tok_low = token.Lower();
2018 
2019         wxString next = m_Tokens.PeekToken();
2020         wxString nex_low = next.Lower();
2021 
2022         if ( ((m_Tokens.GetLineNumber() == m_Tokens.GetPeekedLineNumber()) && IsEnd(tok_low, nex_low)) ||
2023              ((m_Tokens.GetLineNumber() != m_Tokens.GetPeekedLineNumber()) && IsEnd(tok_low, _T(""))) )
2024         {
2025             m_Tokens.SkipToOneOfChars(";", true);
2026             break;
2027         }
2028         else if ( (tok_low.Matches(_T("end")) && nex_low.Matches(_T("select"))) || tok_low.Matches(_T("endselect")) ||
2029                   (tok_low.Matches(_T("type")) && nex_low.Matches(_T("is"))) ||
2030                   (tok_low.Matches(_T("class")) && nex_low.Matches(_T("is"))) ||
2031                   (tok_low.Matches(_T("class")) && nex_low.Matches(_T("default"))) )
2032         {
2033             m_Tokens.UngetToken();
2034             break;
2035         }
2036         else if (tok_low.Matches(_T("type")) && !nex_low(0,1).Matches(_T("(")) && !nex_low.Matches(_T("is"))
2037                  && ln_tokold != m_Tokens.GetLineNumber())
2038         {
2039             HandleType();
2040         }
2041         else if (tok_low.Matches(_T("subroutine")))
2042         {
2043             HandleFunction(tkSubroutine);
2044         }
2045         else if (tok_low.Matches(_T("function")))
2046         {
2047             HandleFunction(tkFunction);
2048         }
2049         else if (tok_low.Matches(_T("use")))
2050         {
2051             HandleUse();
2052         }
2053         else if (tok_low.Matches(_T("interface")))
2054         {
2055             HandleInterface();
2056         }
2057         else if (tok_low.Matches(_T("include")))
2058         {
2059             HandleInclude();
2060         }
2061         else if (tok_low.GetChar(0) == '#')
2062         {
2063             HandlePPDirective(token);
2064         }
2065         else if (tok_low.Matches(_T("procedure")) && m_pLastParent->m_TokenKind == tkInterface)
2066         {
2067             HandleProcedureList();
2068         }
2069         else if (tok_low.Matches(_T("module")) && (nex_low.Matches(_T("subroutine")) || nex_low.Matches(_T("function"))))
2070         {
2071             token = m_Tokens.GetToken();
2072             tok_low = token.Lower();
2073             if (tok_low.Matches(_T("subroutine")))
2074             {
2075                 HandleFunction(tkSubroutine);
2076             }
2077             else if (tok_low.Matches(_T("function")))
2078             {
2079                 HandleFunction(tkFunction);
2080             }
2081         }
2082         else if (tok_low.Matches(_T("block")))
2083         {
2084             if (nex_low.Matches(_T("data")))
2085             {
2086                 token = m_Tokens.GetToken();
2087                 tok_low = token.Lower();
2088                 next = m_Tokens.PeekToken();
2089                 nex_low = next.Lower();
2090                 HandleBlockData();
2091             }
2092             else if (m_Tokens.GetLineNumber() != m_Tokens.GetPeekedLineNumber() || next.Matches(_T(";")))
2093             {
2094                 HandleBlockConstruct();
2095             }
2096         }
2097         else if (tok_low.Matches(_T("blockdata")))
2098         {
2099             HandleBlockData();
2100         }
2101         else if (tok_low.Matches(_T("associate")))
2102         {
2103             HandleAssociateConstruct();
2104         }
2105         else if (tok_low.Matches(_T("select")) && nex_low.Matches(_T("type")))
2106         {
2107             m_Tokens.GetToken();
2108             HandleSelectTypeConstruct();
2109         }
2110         else if (tok_low.Matches(_T("selecttype")))
2111         {
2112             HandleSelectTypeConstruct();
2113         }
2114         else if ((tok_low.Matches(_T("select")) && nex_low.Matches(_T("case"))) ||
2115                  tok_low.Matches(_T("selectcase")))
2116         {
2117             HandleSelectCaseConstruct();
2118         }
2119         else if (tok_low.Matches(_T("procedure")) && nex_low(0,1).Matches(_T("(")))
2120         {
2121             ParseTypeBoundProcedures(token, true, false);
2122         }
2123         else if (tok_low.Matches(_T("!bindto")))
2124         {
2125             HandleBindTo();
2126         }
2127         else
2128         {
2129             bool needDefault = true;
2130             bool hasFunctionInLine = false;
2131             TokensArrayF tokTmpArr;
2132             if (ln_tokold != m_Tokens.GetLineNumber()) // declaration can start only from a new line
2133             {
2134                 CheckParseOneDeclaration(token, tok_low, next, nex_low, needDefault, tokTmpArr, hasFunctionInLine);
2135             }
2136 
2137             if (tokTmpArr.size() == 0 && m_pLastParent && !hasFunctionInLine)
2138             {
2139                 CheckParseCallProcedure(token, tok_low, next);
2140             }
2141         }
2142     }
2143 }
2144 
HandleProcedureList()2145 void ParserThreadF::HandleProcedureList()
2146 {
2147     unsigned int lineNum = m_Tokens.GetLineNumber();
2148     wxArrayString curLineArr = m_Tokens.GetTokensToEOL();
2149 
2150     for (unsigned int i=0; i<curLineArr.GetCount(); i++)
2151     {
2152         if (curLineArr.Item(i).IsSameAs(_T("::")))
2153             continue;
2154         DoAddToken(tkOther, curLineArr.Item(i), wxEmptyString, lineNum);
2155     }
2156 }
2157 
ParseTypeBoundProcedures(const wxString & firstWord,bool breakAtEOL,bool passIn)2158 void ParserThreadF::ParseTypeBoundProcedures(const wxString& firstWord, bool breakAtEOL, bool passIn)
2159 {
2160     TokenAccessKind defAccKind = taPublic;
2161     bool firstTime = true;
2162     int nOperator = 0;
2163     int nAssignment = 0;
2164     while (1)
2165     {
2166         bool pass = passIn;
2167         TokenAccessKind tokAccK = defAccKind;
2168         wxString firstTokenLw;
2169         if (firstTime && !firstWord.IsEmpty())
2170         {
2171             firstTokenLw = firstWord.Lower();
2172             firstTime = false;
2173         }
2174         else
2175             firstTokenLw = m_Tokens.GetToken().Lower();
2176 
2177         if (firstTokenLw.IsEmpty())
2178             break;
2179         wxString defString = firstTokenLw;
2180         unsigned int lineNum = m_Tokens.GetLineNumber();
2181         wxArrayString linesArr;
2182         wxArrayString curLineArr = m_Tokens.GetTokensToEOL(&linesArr);
2183         bool isGen = firstTokenLw.IsSameAs(_T("generic"));
2184         bool isProc = firstTokenLw.IsSameAs(_T("procedure"));
2185         if (curLineArr.Count() > 0 && (isProc || isGen) ) // &&
2186             // !curLineArr.Item(0).StartsWith(_T("(")) ) // not interface-name
2187         {
2188             wxString interfaceName;
2189             if (isProc)
2190             {
2191                 wxString strInter = curLineArr.Item(0);
2192                 int idx_a = strInter.Find(')',true);
2193                 int idx_b = strInter.Find('(');
2194                 if (idx_a != wxNOT_FOUND && idx_b != wxNOT_FOUND && idx_a > idx_b+1)
2195                 {
2196                     interfaceName = strInter.Mid(idx_b+1,idx_a-idx_b-1);
2197                     defString << strInter;
2198                 }
2199             }
2200             wxString passArg;
2201             int idx = curLineArr.Index(_T("::"));
2202             int startList;
2203             if (idx != wxNOT_FOUND)
2204             {
2205                 int startIdx = interfaceName.IsEmpty() ? 0 : 1;
2206                 for (int i=startIdx; i<idx; i++)
2207                 {
2208                     defString << _T(", ") << curLineArr.Item(i).Lower();
2209                 }
2210 
2211                 for (int i=0; i<idx; i++)
2212                 {
2213                     wxString tok = curLineArr.Item(i).Lower();
2214                     if (tok.IsSameAs(_T("nopass")))
2215                     {
2216                         pass = false;
2217                     }
2218                     else if (tok.IsSameAs(_T("pass")))
2219                     {
2220                         if (i < idx-1)
2221                         {
2222                             wxString strArg = curLineArr.Item(i+1);
2223                             int idx_a = strArg.Find(')',true);
2224                             int idx_b = strArg.Find('(');
2225                             if (idx_a != wxNOT_FOUND && idx_b != wxNOT_FOUND && idx_a > idx_b+1)
2226                             {
2227                                 passArg = strArg.Mid(idx_b+1,idx_a-idx_b-1);
2228                             }
2229                         }
2230                     }
2231                     else if (tok.IsSameAs(_T("private")))
2232                     {
2233                         tokAccK = taPrivate;
2234                     }
2235                     else if (tok.IsSameAs(_T("public")))
2236                     {
2237                         tokAccK = taPublic;
2238                     }
2239                 }
2240                 startList = idx + 1;
2241             }
2242             else
2243             {
2244                 startList = 0;
2245             }
2246             int countArr = curLineArr.GetCount();
2247             int ic=startList;
2248             if (!isGen)
2249             {
2250                 while (ic < countArr)
2251                 {
2252                     // Read docs
2253                     wxString comStr = linesArr.Item(ic).AfterFirst('!');
2254                     if (!comStr.IsEmpty())
2255                     {
2256                         if (comStr.StartsWith(_T("<")) || comStr.StartsWith(_T(">")))
2257                             comStr = comStr.Mid(1);
2258                         comStr = comStr.Trim(true).Trim(false);
2259                     }
2260 
2261                     wxString bindName = curLineArr.Item(ic);
2262                     wxString procName;
2263                     if (ic+2 < countArr)
2264                     {
2265                         if (curLineArr.Item(ic+1).IsSameAs(_T("=>")))
2266                         {
2267                             ic += 2;
2268                             procName = curLineArr.Item(ic);
2269                             if (ic+1 < countArr && curLineArr.Item(ic+1).StartsWith(_T("(")))
2270                                 ic++;
2271                         }
2272                     }
2273                     ic++;
2274                     TokenF* token = DoAddToken(tkProcedure, bindName.Lower(), wxEmptyString, lineNum);
2275                     token->m_DisplayName = bindName;
2276                     token->m_Pass = pass;
2277                     token->m_Args = passArg;
2278                     if (interfaceName.IsEmpty())
2279                     {
2280                         token->m_PartLast = procName.Lower();
2281                         token->m_IsAbstract = false;
2282                     }
2283                     else
2284                     {
2285                         token->m_PartLast = interfaceName.Lower();
2286                         token->m_IsAbstract = true;
2287                     }
2288                     token->AddLineEnd(m_Tokens.GetLineNumber());
2289                     token->m_TokenAccess = tokAccK;
2290                     token->m_TypeDefinition = defString;
2291                     token->m_DocString = comStr;
2292                 }
2293             }
2294             else //isGen
2295             {
2296                 while (ic < countArr-2)
2297                 {
2298                     wxString curNam;
2299                     wxString curNamLw = curLineArr.Item(ic).Lower();
2300                     if (curNamLw.IsSameAs(_T("operator")) || curNamLw.IsSameAs(_T("assignment")))
2301                     {
2302                         curNam.Append(_T("%%"));
2303                         curNam.Append(curLineArr.Item(ic));
2304                         if (curLineArr.Item(ic+1).StartsWith(_("(")))
2305                         {
2306                             ic++;
2307                             curNam.Append(curLineArr.Item(ic));
2308                         }
2309                         if (curNamLw.IsSameAs(_T("operator")))
2310                         {
2311                             nOperator += 1;
2312                             curNam << _T(" #") << nOperator;
2313                         }
2314                         else
2315                         {
2316                             nAssignment += 1;
2317                             curNam << _T(" #") << nAssignment;
2318                         }
2319                         TokenF* token = DoAddToken(tkInterface, curNam, wxEmptyString, lineNum);
2320                         token->AddLineEnd(m_Tokens.GetLineNumber());
2321                     }
2322                     else if (curLineArr.Item(ic+1).IsSameAs(_T("=>")))
2323                     {
2324                         wxString bindName = curLineArr.Item(ic);
2325                         TokenF* token = DoAddToken(tkInterface, bindName.Lower(), wxEmptyString, lineNum);
2326                         token->m_DisplayName = bindName;
2327                         ic += 2;
2328                         wxString specNames;
2329                         for (; ic < countArr; ic++)
2330                         {
2331                             specNames << curLineArr.Item(ic) << _T(" ");
2332                         }
2333                         token->m_PartLast = specNames.Trim();
2334                         token->AddLineEnd(m_Tokens.GetLineNumber());
2335                         token->m_TokenAccess = tokAccK;
2336                     }
2337                     ic++;
2338                 }
2339             }
2340         }
2341         else if ( (curLineArr.Count() == 0 && IsEnd(firstTokenLw, wxEmptyString)) ||
2342                   (curLineArr.Count() >= 1 && IsEnd(firstTokenLw,curLineArr.Item(0).Lower())) )
2343         {
2344             m_Tokens.SkipToOneOfChars(";", true);
2345             break;
2346         }
2347         else if ( firstTokenLw.IsSameAs(_T("private")) && curLineArr.Count() == 0 )
2348         {
2349             defAccKind = taPrivate;
2350         }
2351         else if ( firstTokenLw.IsSameAs(_T("final")) && curLineArr.Count() > 0 )
2352         {
2353             int idx = curLineArr.Index(_T("::"));
2354             int startIdx = (idx == wxNOT_FOUND) ? 0 : idx+1;
2355             for (size_t i=startIdx; i<curLineArr.Count(); i++)
2356             {
2357                 wxString name = curLineArr.Item(i);
2358                 TokenF* token = DoAddToken(tkProcedureFinal, name.Lower(), wxEmptyString, lineNum);
2359                 token->m_DisplayName = name;
2360                 token->AddLineEnd(m_Tokens.GetLineNumber());
2361             }
2362         }
2363 
2364         if (breakAtEOL)
2365             break;
2366     }
2367 }
2368 
IsEnd(wxString tok_low,wxString nex_low)2369 bool ParserThreadF::IsEnd(wxString tok_low, wxString nex_low)
2370 {
2371     bool isend = false;
2372     if ( tok_low.StartsWith(_T("end")) &&
2373             ( (tok_low.Matches(_T("end")) && (nex_low.IsEmpty() || m_KnownEndSecPart.count(nex_low))) ||
2374               tok_low.Matches(_T("endsubroutine")) ||
2375               tok_low.Matches(_T("endfunction")) ||
2376               tok_low.Matches(_T("endmodule")) ||
2377               tok_low.Matches(_T("endsubmodule")) ||
2378               tok_low.Matches(_T("endtype")) ||
2379               tok_low.Matches(_T("endinterface")) ||
2380               tok_low.Matches(_T("endprogram")) ||
2381               tok_low.Matches(_T("endblock")) ||
2382               tok_low.Matches(_T("endblockdata")) ||
2383               tok_low.Matches(_T("endassociate")) ||
2384               tok_low.Matches(_T("endprocedure")) )
2385        )
2386     {
2387         isend = true;
2388     }
2389     return isend;
2390 }
2391 
MakeArrayStringLower(wxArrayString & arr,wxArrayString & arrLw)2392 void ParserThreadF::MakeArrayStringLower(wxArrayString &arr, wxArrayString &arrLw)
2393 {
2394     for(size_t i=0; i<arr.Count(); i++)
2395     {
2396         arrLw.Add(arr.Item(i).Lower());
2397     }
2398 }
2399 
SetTokenAccess(ModuleTokenF * modToken,TokenF * token,TokenAccessKind defAKind)2400 void ParserThreadF::SetTokenAccess(ModuleTokenF* modToken, TokenF* token, TokenAccessKind defAKind)
2401 {
2402     if (modToken->HasNameInPrivateList(token->m_Name))
2403     {
2404         token->m_TokenAccess = taPrivate;
2405     }
2406     else if (modToken->HasNameInPublicList(token->m_Name))
2407     {
2408         if (token->m_TokenAccess != taProtected)
2409             token->m_TokenAccess = taPublic;
2410     }
2411     else
2412     {
2413         token->m_TokenAccess = defAKind;
2414     }
2415 }
2416 
2417 
SplitAssociateConstruct(const wxString & argLine,std::map<wxString,wxString> & assocMap)2418 void ParserThreadF::SplitAssociateConstruct(const wxString& argLine, std::map<wxString,wxString>& assocMap)
2419 {
2420     wxString args = argLine;
2421     int pos = args.Find(')',true);
2422     if (pos != wxNOT_FOUND)
2423         args.Remove(pos);
2424     args = args.AfterFirst('(');
2425 
2426     int cnt = 0;
2427     int sta = 0;
2428     for(size_t i=0; i<args.Len(); i++)
2429     {
2430         if (args.GetChar(i) == '(')
2431             cnt++;
2432         else if (args.GetChar(i) == ')')
2433             cnt--;
2434 
2435         if ( (args.GetChar(i) == ',' && cnt == 0) ||
2436                 (i == args.Len()-1) )
2437         {
2438             wxString block;
2439             if (args.GetChar(i) == ',')
2440                 block = args.Mid(sta, i-sta);
2441             else
2442                 block = args.Mid(sta, i-sta+1);
2443             sta = i + 1;
2444             int sind = block.Find(_T("=>"));
2445             if (sind != wxNOT_FOUND)
2446             {
2447                 wxString assocName = block.Mid(0,sind).Trim(true).Trim(false);
2448                 wxString sourceExpr = block.Mid(sind+2).Trim(true).Trim(false);
2449                 assocMap.insert(std::pair<wxString,wxString>(assocName, sourceExpr));
2450             }
2451             else
2452             {
2453                 wxString assocName = block.Trim(true).Trim(false);
2454                 assocMap.insert(std::pair<wxString,wxString>(assocName, assocName));
2455             }
2456         }
2457     }
2458 }
2459 
GetDocBlock(DocBlock & docs,bool lookDown,unsigned int ln,bool takeSimpleDoc)2460 void ParserThreadF::GetDocBlock(DocBlock &docs, bool lookDown, unsigned int ln, bool takeSimpleDoc)
2461 {
2462     bool isSimpleDoc = false;
2463     bool hasDoc = false;
2464     wxArrayString docLines;
2465     unsigned int loopStart;
2466     if (lookDown)
2467         loopStart = ln+1;
2468     else
2469         loopStart = ln-1;
2470     unsigned int ii = loopStart;
2471     unsigned int nLines = m_Tokens.GetLineCount();
2472 
2473     while (ii >= 1 && ii <= nLines)
2474     {
2475         wxString line = m_Tokens.GetLine(ii).Trim(false);
2476 
2477         if (ii == loopStart && !line.StartsWith(_T("!")))
2478             isSimpleDoc = false;
2479         else if (ii == loopStart && line.StartsWith(_T("!")))
2480         {
2481             if (!lookDown && (line.StartsWith(_T("!!")) || line.StartsWith(_T("!<")) || line.StartsWith(_T("!>"))))
2482                 isSimpleDoc = false;
2483             else
2484             {
2485                 isSimpleDoc = true;
2486                 if (!takeSimpleDoc)
2487                     break;
2488             }
2489         }
2490 
2491         if (line.StartsWith(_T("!")))
2492         {
2493             if (line.StartsWith(_T("!!")) || line.StartsWith(_T("!<")) || line.StartsWith(_T("!>")))
2494             {
2495                 docLines.Add(line.Mid(2).Trim(true).Trim(false));
2496             }
2497             else if (isSimpleDoc)
2498             {
2499                 docLines.Add(line.Mid(1).Trim(true).Trim(false));
2500             }
2501             else
2502                 break;
2503 
2504             hasDoc = true;
2505         }
2506         else if (hasDoc && line.IsEmpty())
2507             break;
2508         else if (!line.IsEmpty())
2509             break;
2510 
2511         if (lookDown)
2512             ii++;
2513         else
2514             ii--;
2515     }
2516 
2517     if (isSimpleDoc && docLines.GetCount()>0)
2518     {
2519         // Not Doxygen comments
2520         // Take first 3 nonempty lines and use it as a doc-string
2521         wxString docLine;
2522         int isimp = 0;
2523         if (lookDown)
2524             loopStart = 0;
2525         else
2526             loopStart = docLines.GetCount()-1;
2527         int j = loopStart;
2528 
2529         while ((lookDown && j < (int) docLines.GetCount()) || (!lookDown && j >= 0))
2530         {
2531             size_t sidx = docLines[j].find_first_not_of(_T("! \t"));
2532             if (sidx != wxString::npos)
2533             {
2534                 size_t sidx2 = docLines[j].find_first_not_of(docLines[j].at(sidx)); // an attempt to avoid e.g. !********
2535                 if (sidx2 != wxString::npos)
2536                 {
2537                     //if (isimp == 3) // take 3 lines at most
2538                     if (docLine.size() > 400) // limit number of symbols
2539                     {
2540                         docLine << _T("...");
2541                         break;
2542                     }
2543                     if (sidx2 > sidx+2)
2544                         docLine << _T(" ") + docLines[j].Mid(sidx2);
2545                     else
2546                         docLine << _T(" ") + docLines[j].Mid(sidx);
2547 
2548                     isimp += 1;
2549                 }
2550                 else if (!docLine.IsEmpty())
2551                     break;
2552             }
2553             else if (!docLine.IsEmpty())
2554                 break;
2555 
2556             if (lookDown)
2557                 j++;
2558             else
2559                 j--;
2560         }
2561         if (!docLine.IsEmpty())
2562             docs.AddDescription(docLine.Trim(false));
2563 
2564     }
2565     else if (docLines.GetCount()>0)
2566     {
2567         // Doxygen docs
2568         wxString description;
2569         wxString brief;
2570         wxArrayString paramNames;
2571         wxArrayString paramDescr;
2572         bool inbrief = false;
2573         bool indescription = false;
2574         for (int i=docLines.GetCount()-1; i>=0; i--)
2575         {
2576             bool iscommand = false;
2577 
2578             if (docLines[i].IsEmpty())
2579             {
2580                 inbrief = false;
2581                 indescription = false;
2582                 continue;
2583             }
2584             else if (docLines[i].StartsWith(_T("\\")) || docLines[i].StartsWith(_T("@")))
2585             {
2586                 inbrief = false;
2587                 indescription = false;
2588                 iscommand = true;
2589             }
2590 
2591             bool isbrief = false;
2592             bool isparam = false;
2593             if (iscommand)
2594             {
2595                 size_t sidx = docLines[i].find(_T("brief"),1);
2596                 if (sidx == 1)
2597                     isbrief = true;
2598 
2599                 if (!isbrief)
2600                 {
2601                     sidx = docLines[i].find(_T("param"),1);
2602                     if (sidx == 1)
2603                         isparam = true;
2604                 }
2605             }
2606 
2607             if (isbrief)
2608             {
2609                 brief = docLines[i].Mid(6).Trim(false);
2610                 inbrief = true;
2611                 indescription = false;
2612             }
2613             else if (inbrief)
2614             {
2615                 wxString repNoStr = TrimRepetitives(docLines[i]);
2616                 if (!repNoStr.IsEmpty())
2617                     brief << _T(" ") << repNoStr;
2618             }
2619             else if (isparam)
2620             {
2621                 wxString pline = docLines[i].Mid(6).Trim(false);
2622                 size_t sidx = pline.find_first_of(_T(" \t"));
2623                 if (sidx != wxString::npos)
2624                 {
2625                     paramDescr.Add(pline.Mid(sidx+1).Trim(false));
2626                     paramNames.Add(pline.Mid(0,sidx));
2627                 }
2628                 indescription = false;
2629             }
2630             else if (!iscommand && description.IsEmpty() && paramNames.Count() == 0)
2631             {
2632                 indescription = true;
2633             }
2634 
2635             if (indescription)
2636             {
2637                 wxString repNoStr = TrimRepetitives(docLines[i]);
2638                 if (!repNoStr.IsEmpty())
2639                     description << repNoStr + _T(" ");
2640             }
2641 
2642         }
2643 
2644         if (!description.IsEmpty())
2645             docs.AddDescription(description.Trim());
2646         if (!brief.IsEmpty())
2647             docs.AddBrief(brief);
2648         for (size_t i=0; i<paramDescr.size(); i++)
2649         {
2650             docs.AddParam(paramNames[i], paramDescr[i]);
2651         }
2652     }
2653 }
2654 
TrimRepetitives(wxString & inStr)2655 wxString ParserThreadF::TrimRepetitives(wxString& inStr)
2656 {
2657     // an attempt to avoid e.g. !********
2658     wxString outStr;
2659     size_t sidx = inStr.find_first_not_of(_T("! \t"));
2660     if (sidx != wxString::npos)
2661     {
2662         size_t sidx2 = inStr.find_first_not_of(inStr.at(sidx),sidx);
2663         if (sidx2 != wxString::npos)
2664         {
2665             if (sidx2 > sidx+2)
2666                 outStr = inStr.Mid(sidx2);
2667             else
2668                 outStr = inStr.Mid(sidx);
2669         }
2670     }
2671     return outStr;
2672 }
2673 
GetDocLine(unsigned int ln)2674 wxString ParserThreadF::GetDocLine(unsigned int ln)
2675 {
2676     wxString line = m_Tokens.GetLine(ln);
2677     line = line.AfterFirst('!');
2678     if (line.StartsWith(_T("<")) || line.StartsWith(_T(">")))
2679         line = line.substr(1);
2680     return line.Trim(true).Trim(false);
2681 }
2682 
AddParamDocs(TokenF * pParToken,DocBlock & docs)2683 void ParserThreadF::AddParamDocs(TokenF* pParToken, DocBlock &docs)
2684 {
2685     int npar = docs.GetParamCount();
2686     if (npar == 0)
2687         return;
2688     int nadd = 0;
2689     TokensArrayF* tokArr = &pParToken->m_Children;
2690     for (size_t j=0; j<tokArr->GetCount(); j++)
2691     {
2692         if (tokArr->Item(j)->m_TokenKind == tkVariable && tokArr->Item(j)->m_DocString.IsEmpty())
2693         {
2694             wxString descr = docs.GetValue(tokArr->Item(j)->m_Name);
2695             if (!descr.IsEmpty())
2696             {
2697                 tokArr->Item(j)->m_DocString = descr;
2698                 nadd++;
2699                 if (nadd == npar)
2700                     break;
2701             }
2702         }
2703     }
2704 }
2705 
HandleBindTo()2706 void ParserThreadF::HandleBindTo()
2707 {
2708     wxString line = m_Tokens.GetCurrentLine().Trim(true).Trim(false);
2709     line = line.Mid(7).Trim(false).Lower();
2710     DoAddToken(tkBindTo, wxEmptyString, line.BeforeFirst('!').Trim());
2711     m_Tokens.SkipToEOL();
2712 }
2713 
CheckParseCallProcedure(wxString & token,wxString & tok_low,wxString & next)2714 void ParserThreadF::CheckParseCallProcedure(wxString& token, wxString& tok_low, wxString& next)
2715 {
2716     if ( tok_low.IsSameAs(_T("call")) )
2717     {
2718         wxArrayString args_arr;
2719         token = m_Tokens.GetTokenSameFortranLine();
2720         while (true)
2721         {
2722             wxString nextTok = m_Tokens.PeekTokenSameFortranLine();
2723             if (nextTok.IsSameAs(_T("%")))
2724             {
2725                 token << m_Tokens.GetTokenSameFortranLine();
2726                 token << m_Tokens.GetTokenSameFortranLine();
2727             }
2728             else if (nextTok.StartsWith(_T("(")) && nextTok.EndsWith(_T(")")))
2729             {
2730                 args_arr.Add(m_Tokens.GetTokenSameFortranLine());
2731             }
2732             else
2733                 break;
2734         }
2735         if (token != wxEmptyString)
2736         {
2737             DoAddToken(tkCallSubroutine, token);
2738             for (size_t i=0; i<args_arr.size(); ++i)
2739             {
2740                 token = args_arr.Item(i);
2741                 if (token.StartsWith(_T("(")) && token.EndsWith(_T(")")))
2742                 {
2743                     // we have argument list. Find function-array calls.
2744                     wxString args = token.Mid(1, token.length()-2);
2745                     TakeFunctionsCallsFromString(args);
2746                 }
2747             }
2748         }
2749     }
2750     else
2751     {
2752         if (next.StartsWith(_T("(")))
2753         {
2754             wxString curLine = m_Tokens.GetLineFortran();
2755             TakeFunctionsCallsFromString(curLine);
2756             m_Tokens.SkipToOneOfChars(";", true);
2757         }
2758     }
2759 }
2760 
TakeFunctionsCallsFromString(const wxString & strIn)2761 void ParserThreadF::TakeFunctionsCallsFromString(const wxString& strIn)
2762 {
2763     wxString str = strIn;
2764     for (int i=0; i<20; i++)
2765     {
2766         int idx = str.Find(_T("("));
2767         if (idx == wxNOT_FOUND)
2768         {
2769             break;
2770         }
2771         else if (idx > 0)
2772         {
2773             int idxStart;
2774             wxString funName;
2775             int idxEnd = idx-1;
2776             while (true)
2777             {
2778                 wxString wordTmp;
2779                 GetWordBefore(str, idxEnd, wordTmp, idxStart);
2780                 if (wordTmp.IsEmpty())
2781                 {
2782                     break;
2783                 }
2784                 else if (wordTmp.StartsWith(_T("(")) && wordTmp.EndsWith(_T(")")))
2785                 {
2786                     idxEnd = idxStart - 1;
2787                 }
2788                 else
2789                 {
2790                     int idxCur = idxStart-1;
2791                     for (; idxCur>=0; idxCur--)
2792                     {
2793                         if (!isspace(str.GetChar(idxCur)))
2794                             break;
2795                     }
2796 
2797                     if (idxCur >= 0 && str.GetChar(idxCur) == '%')
2798                     {
2799                         funName = _T("%") + wordTmp + funName;
2800                         idxEnd = idxCur-1;
2801                     }
2802                     else
2803                     {
2804                         funName = wordTmp + funName;
2805                         break;
2806                     }
2807                 }
2808             }
2809 
2810             if (!funName.IsEmpty() && !isdigit(funName.GetChar(0)))
2811             {
2812                 DoAddToken(tkCallFunction, funName);
2813             }
2814             else
2815                 break; // something is wrong
2816         }
2817         str = str.Mid(idx+1);
2818     }
2819 }
2820 
2821 
GetWordBefore(const wxString & str,int idxEnd,wxString & funName,int & idxStart)2822 void ParserThreadF::GetWordBefore(const wxString& str, int idxEnd, wxString& funName, int& idxStart)
2823 {
2824     funName = wxEmptyString;
2825     for (; idxEnd>=0; idxEnd--)
2826     {
2827         if (!isspace(str.GetChar(idxEnd)))
2828             break;
2829     }
2830 
2831     if (idxEnd < 0)
2832         return;
2833 
2834     int lev = 0;
2835     for (idxStart=idxEnd; idxStart>=0; idxStart--)
2836     {
2837         if (str.GetChar(idxStart) == ')')
2838         {
2839             lev+=1;
2840         }
2841         else if (str.GetChar(idxStart) == '(')
2842         {
2843             if (lev == 0)
2844                 break;
2845             else if (lev == 1)
2846             {
2847                 idxStart-=1;
2848                 break;
2849             }
2850             else
2851                 lev-=1;
2852         }
2853         else if (!isalnum(str.GetChar(idxStart)) && str.GetChar(idxStart) != '_' && str.GetChar(idxStart) != '$')
2854             break;
2855     }
2856     idxStart += 1;
2857     funName = str.Mid(idxStart, idxEnd-idxStart+1);
2858 }
2859