Recent

Author Topic: [TRegExpr] How to get all uses library's from pascal file ?  (Read 3966 times)

TonnyB

  • Newbie
  • Posts: 6
[TRegExpr] How to get all uses library's from pascal file ?
« on: September 11, 2017, 06:49:47 pm »
Hello there. I try to get all uses library from pascal file ?

My regular expression:

Code: Pascal  [Select][+][-]
  1. uses[\W+]{0,}([0-9A-Za-z_]{0,})[,\s]{0,};

h**ps://regex101.com/r/rfQtQg/1


But if there is several library then my regular expression not works.

h**ps://regex101.com/r/rfQtQg/4



Leledumbo

  • Hero Member
  • *****
  • Posts: 8746
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: [TRegExpr] How to get all uses library's from pascal file ?
« Reply #1 on: September 11, 2017, 09:22:17 pm »
Use the syntax diagram as your base.
Your regex:
Code: [Select]
uses[\W+]{0,}([0-9A-Za-z_]{0,})[,\s]{0,};
  • uses (✓)
  • set of non-identifier chars and a plus literal, 0 or more (×)
  • set of identifier chars, 0 or more, grouped (for capture, I suppose?) (×)
  • set of comma and whitespace chars, 0 or more (×)
has too many errors. Written in a more common notation (WSN / EBNF, implied whitespace), the grammar would be:
Code: [Select]
uses-clause = "uses" uses-ident { "," uses-ident } ";" .
uses-ident = identifier [ "in" pascal-string-literal ] .
You can simplify uses-ident to identifier if the former is too difficult to recognize and you're sure none will appear in the project you scan uses clause for.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: [TRegExpr] How to get all uses library's from pascal file ?
« Reply #2 on: September 11, 2017, 09:34:17 pm »
There might be preprocessor directives in there too (and there will be, in most professional codebases, if only to cope with FPC/Delphi versioning and OS dependence)

Regex are too weak to parse programming languages.

Thaddy

  • Hero Member
  • *****
  • Posts: 14204
  • Probably until I exterminate Putin.
Re: [TRegExpr] How to get all uses library's from pascal file ?
« Reply #3 on: September 11, 2017, 09:57:58 pm »
Indeed. Parsing used units (including those mentioned in includes) is like parsing a language.
Since regular expressions are not Turing complete this is not even possible.

There are tools, however, that will resolve each and every unit used, based on a Pascal parser.
Specialize a type, not a var.

ASerge

  • Hero Member
  • *****
  • Posts: 2222
Re: [TRegExpr] How to get all uses library's from pascal file ?
« Reply #4 on: September 11, 2017, 10:05:44 pm »
Do not forget about //uses..., {uses...} and (*uses...*) and the possibility of placing on several lines with the comments between them.

Wosi

  • New Member
  • *
  • Posts: 21
Re: [TRegExpr] How to get all uses library's from pascal file ?
« Reply #5 on: September 11, 2017, 10:16:45 pm »
As others have mentioned before: Don't try to get any useful information from source code using regular expressions. You will faill.

DelphiAST is a really great parser as long as your files don't contain FPC related keywords. It will do a much better job than any regular expression.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: [TRegExpr] How to get all uses library's from pascal file ?
« Reply #6 on: September 11, 2017, 10:24:05 pm »
FPC comes with a similar parser, fcl-passrc. It has improved enormously in the past year.

Thaddy

  • Hero Member
  • *****
  • Posts: 14204
  • Probably until I exterminate Putin.
Re: [TRegExpr] How to get all uses library's from pascal file ?
« Reply #7 on: September 11, 2017, 10:28:12 pm »
FPC comes with a similar parser, fcl-passrc. It has improved enormously in the past year.
Yes, but requires trunk? It will however parse everything and in all fpc modes. at least regarding the units. Something the other tools mentioned can't do at all.
Specialize a type, not a var.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: [TRegExpr] How to get all uses library's from pascal file ?
« Reply #8 on: September 11, 2017, 10:30:26 pm »
Yes, but requires trunk?

Did you test fixes?

Jurassic Pork

  • Hero Member
  • *****
  • Posts: 1228
Re: [TRegExpr] How to get all uses library's from pascal file ?
« Reply #9 on: September 12, 2017, 12:54:21 am »
hello,
Yes, but requires trunk?
the package fcl-passrc is there in my Lazarus release 1.8RC3. To see all the units used in a file you can use the unit passsrcutil from this package.
Exemple to  read the units used in a file :
Code: Pascal  [Select][+][-]
  1. implementation
  2. uses passrcutil;
  3. {$R *.lfm}
  4. { TForm1 }
  5. procedure TForm1.Button1Click(Sender: TObject);
  6.  var filename: string;
  7.      PasAnalyser: TPasSrcAnalysis;
  8.      PasList : TStrings;
  9. begin
  10. if OpenDialog1.Execute then
  11.    begin
  12.    filename := OpenDialog1.Filename;
  13.    end
  14.    else exit;
  15.     PasAnalyser:=TPasSrcAnalysis.Create(Nil);
  16.     PasList:=TStringList.Create;
  17.     PasAnalyser.FileName:=filename;
  18.     Memo1.Clear;
  19.     Memo1.Append('File : ' + filename);
  20.     Memo1.Append('======  Interface Units =======');
  21.     PasAnalyser.GetInterfaceUnits(PasList);
  22.     Memo1.Append(PasList.Text);
  23.     Memo1.Append('======  Implementation Units =======');
  24.     PasList.Clear;
  25.     PasAnalyser.GetImplementationUnits(PasList);
  26.     Memo1.Append(PasList.Text);
  27.     FreeAndNil(PasAnalyser);
  28.     FreeAndNil(PasList);
  29. end;
  30. end.

Friendly, J.P
Jurassic computer : Sinclair ZX81 - Zilog Z80A à 3,25 MHz - RAM 1 Ko - ROM 8 Ko

Thaddy

  • Hero Member
  • *****
  • Posts: 14204
  • Probably until I exterminate Putin.
Re: [TRegExpr] How to get all uses library's from pascal file ?
« Reply #10 on: September 12, 2017, 09:17:09 am »
hello,
Yes, but requires trunk?
the package fcl-passrc is there in my Lazarus release 1.8RC3. To see all the units used in a file you can use the unit passsrcutil from this package.

I was referring to the current implementation and improvements that Marco was referring to.
You are right that even the older implementations can parse the "used units" correctly, but the trunk implementation is now very close to what the compiler parses.
And that is only in trunk.
Specialize a type, not a var.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: [TRegExpr] How to get all uses library's from pascal file ?
« Reply #11 on: September 12, 2017, 01:30:48 pm »
And that is only in trunk.

Everything up to a few weeks before the RC1 release was merged to trunk. IOW the bulk is available in fixes and 3.0.4rc1

soerensen3

  • Full Member
  • ***
  • Posts: 213
Re: [TRegExpr] How to get all uses library's from pascal file ?
« Reply #12 on: September 12, 2017, 03:20:29 pm »
Another option would be to use CodeTools, which is also used by the CodeExplorer of the IDE.

Don't forget to add the CodeTools package to the project dependencies!
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   {$IFDEF UNIX}{$IFDEF UseCThreads}
  7.   cthreads,
  8.   {$ENDIF}{$ENDIF}
  9.   Classes,
  10.   sysutils,
  11.   CodeToolManager,
  12.   CodeTree, CodeCache
  13.   { you can add units after this };
  14.  
  15. var
  16.   Code: TCodeBuffer;
  17.   Tool: TCodeTool;
  18.   i: Integer;
  19.  
  20.   procedure ExtractUsesSectionFromFile( AFileName: String );
  21.   var
  22.     Main, Impl: TStrings;
  23.     j: Integer;
  24.   begin
  25.     Code:= CodeToolBoss.LoadFile( ExpandFileName( AFileName ), False, False );
  26.     if ( not Assigned( Code )) then
  27.       raise Exception.Create( 'Could not load the unit file: ' + AFileName );
  28.     Tool:= nil;
  29.     if ( not CodeToolBoss.Explore( Code, Tool, False, True )) then
  30.       raise Exception.Create( 'The code of the unit file could not be parsed as it contains errors: ' + AFileName );
  31.  
  32.     if ( not Assigned( Tool )) then
  33.       Tool:= TCodeTool( CodeToolBoss.GetCodeToolForSource( Code, False, False ));
  34.  
  35.     Tool.FindUsedUnitFiles( Main, Impl );
  36.     WriteLn( 'Used units of ', AFileName );
  37.     WriteLn( 'Used units in uses section:' );
  38.  
  39.     for j:= 0 to Main.Count - 1 do
  40.       WriteLn( Main[ j ]);
  41.     //WriteLn( Main.Text );
  42.     WriteLn();
  43.     WriteLn( 'Used units in implementation section:' );
  44.     WriteLn( Impl.Text );
  45.     Main.Free;
  46.     Impl.Free;
  47.   end;
  48.  
  49. begin
  50.   if ( ParamCount > 0 ) then
  51.     for i:= 1 to ParamCount do
  52.       ExtractUsesSectionFromFile( ParamStr( i ))
  53.   else
  54.     WriteLn( 'Error: no files passed as parameter' );
  55. end.
  56.  
It requires that there are no syntax errors in the file. However CodeTools is a little less strict than the compiler. Please note that you do not need to free instances of TCodeBuffer or TCodeTool as they are managed by CodeTools itself. If you use it with units that use includes not in the same directory, this method will fail. That is because the package or project file is not parsed by default.
You can add an include directory manually like this:

Code: Pascal  [Select][+][-]
  1. procedure AddIncludePath( Directory: String );
  2.   var
  3.     IncPathTemplate: TDefineTemplate;
  4.   begin
  5.     Directory:= ExpandFileName( Directory );
  6.  
  7.     // add a sub template to extend the include search path #IncPath.
  8.     IncPathTemplate:= TDefineTemplate.Create(
  9.       '', // optional: the name of the template, useful for finding it later
  10.       '', // optional: a description
  11.       IncludePathMacroName,
  12.       IncludePathMacro + ';' + Directory
  13.       ,da_DefineRecurse
  14.       );
  15.     // add the include path template to the tree
  16.     CodeToolBoss.DefineTree.Add( IncPathTemplate );
  17.   end;
Lazarus 1.9 with FPC 3.0.4
Target: Manjaro Linux 64 Bit (4.9.68-1-MANJARO)

 

TinyPortal © 2005-2018