From b0eb94ed80f3f20910bca956f91080c1750cf0dc Mon Sep 17 00:00:00 2001 From: sekelsenmat Date: Tue, 4 Mar 2008 23:34:41 +0000 Subject: [PATCH] Adds objective-c parser from Skalogryz. git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@370 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- bindings/pascocoa/parser/ObjCParserTypes.pas | 532 +++++++++++++++++++ bindings/pascocoa/parser/input.txt | 161 ++++++ bindings/pascocoa/parser/objcparser.lpi | 88 +++ bindings/pascocoa/parser/objcparser.pas | 83 +++ 4 files changed, 864 insertions(+) create mode 100755 bindings/pascocoa/parser/ObjCParserTypes.pas create mode 100755 bindings/pascocoa/parser/input.txt create mode 100755 bindings/pascocoa/parser/objcparser.lpi create mode 100755 bindings/pascocoa/parser/objcparser.pas diff --git a/bindings/pascocoa/parser/ObjCParserTypes.pas b/bindings/pascocoa/parser/ObjCParserTypes.pas new file mode 100755 index 000000000..aa3195e91 --- /dev/null +++ b/bindings/pascocoa/parser/ObjCParserTypes.pas @@ -0,0 +1,532 @@ +unit ObjCParserTypes; + +interface + +{$ifdef fpc}{$mode delphi}{$endif fpc} + +uses + Classes; + +type + TTokenType = (tt_Ident, tt_Symbol, tt_None); + + TCharSet = set of Char; + + + TTokenPair = record + Open : AnsiString; + Close : AnsiString; + end; + + TTokenTable = class(TObject) + SpaceChars : TCharSet; + CmtBlock : array of TTokenPair; + CmtCount : Integer; + CmtLine : TStrings; + Symbols : TCharSet; + constructor Create; + destructor Destroy; override; + end; + + TTextParser = class(TObject) + public + Buf : AnsiString; + Index : Integer; + TokenTable : TTokenTable; + function SkipComments: Boolean; + function FindNextToken(var Token: AnsiString; var TokenType: TTokenType): Boolean; + constructor Create; + end; + + { TEntity } + + TEntity = class(TObject) + public + Items : TList; + constructor Create; + destructor Destroy; override; + procedure Parse(AParser: TTextParser); virtual; abstract; + end; + + { TParameterDef } + + TResultTypeDef = class(TEntity) + _isRef : Boolean; + _TypeName : AnsiString; + procedure Parse(AParser: TTextParser); override; + end; + + TParameterDef = class(TEntity) + _Res : TResultTypeDef; + _Name : AnsiString; + procedure Parse(AParser: TTextParser); override; + function GetResultType: TResultTypeDef; + end; + + { TParamDescr } + + TParamDescr = class(TEntity) + public + _Descr : AnsiString; + procedure Parse(AParser: TTextParser); override; + end; + + { TClassMethodDef } + + TClassMethodDef = class(TEntity) + _IsClassMethod : Boolean; // is class function as delphi would say + _CallChar : AnsiChar; // + or - + _Name : AnsiString; + procedure Parse(AParser: TTextParser); override; + function GetResultType: TResultTypeDef; + end; + + { TClassDef } + + TClassDef = class(TEntity) + public + _ClassName : AnsiString; + _SuperClass : AnsiString; + _Category : AnsiString; + procedure Parse(AParser: TTextParser); override; + end; + + { TObjCHeader } + + TObjCHeader = class(TEntity) + public + constructor Create; + procedure Parse(AParser: TTextParser); override; + end; + + +const + EoLnChars : TCharSet = [#10,#13]; + InvsChars : TCharSet = [#32,#9]; + +procedure SkipLine(const s: AnsiString; var index: Integer); +procedure SetCComments(Table: TTokenTable); +procedure SetCSymbols(var ch: TCharSet); + +function CreateObjCTokenTable: TTokenTable; + +implementation + +function CreateObjCTokenTable: TTokenTable; +begin + Result := TTokenTable.Create; + SetCComments(Result); + SetCSymbols(Result.Symbols); + Result.SpaceChars := EoLnChars + InvsChars; +end; + +procedure SetCSymbols(var ch: TCharSet); +begin + ch := ['(',')', '{','}', ':', '-','+','<','>','*',';'] +end; + +procedure SetCComments(Table: TTokenTable); +begin + SetLength(Table.CmtBlock, 1); + Table.CmtCount := 1; + Table.CmtBlock[0].Open := '/*'; + Table.CmtBlock[0].Close := '*/'; + Table.CmtLine.Add('//'); +end; + +function ScanWhile(const s: AnsiString; var index: Integer; const ch: TCharSet): AnsiString; +var + i : Integer; +begin + Result := ''; + if (index <= 0) or (index > length(s)) then Exit; + for i := index to length(s) do + if not (s[i] in ch) then begin + if i = index then Result := '' + else Result := Copy(s, index, i - index); + index := i; + Exit; + end; + Result := Copy(s, index, length(s) - index + 1); + index := length(s) + 1; +end; + +function ScanTo(const s: AnsiString; var index: Integer; const ch: TCharSet): AnsiString; +var + i : Integer; +begin + Result := ''; + if (index <= 0) or (index > length(s)) then Exit; + for i := index to length(s) do + if (s[i] in ch) then begin + if i = index then Result := '' + else Result := Copy(s, index, i - index); + index := i; + Exit; + end; + Result := Copy(s, index, length(s) - index + 1); + index := length(s) + 1; +end; + +{ TTextParser } + +function IsSubStr(const sbs, s: AnsiString; index: Integer): Boolean; +var + i : Integer; + j : Integer; +begin + Result := false; + if length(sbs) > length(s) - index then Exit; + j := index; + for i := 1 to length(sbs) do begin + if sbs[i] <> s[j] then Exit; + inc(j); + end; + Result := true; +end; + +procedure SkipCommentBlock(const s: AnsiString; var index: Integer; const closecmt: AnsiString); +begin + if closecmt = '' then begin + index := length(s) + 1; + Exit; + end; + while index <= length(s) do begin + ScanTo(s, index, [closecmt[1]]); + if IsSubStr(closecmt, s, index) then begin + inc(index, length(closecmt)); + Exit; + end else + inc(index); + end; +end; + +procedure SkipLine(const s: AnsiString; var index: Integer); +begin + ScanTo(s, index, EoLnChars); + ScanWhile(s, index, EoLnChars); +end; + +constructor TTextParser.Create; +begin + + Index := 1; + +end; + + + +function TTextParser.FindNextToken(var Token: AnsiString; var TokenType: TTokenType): Boolean; +var + srch : TCharSet; + blck : TCharSet; + i : Integer; + t : AnsiString; +begin + Result := Index <= length(Buf); + if not Result then Exit; + + srch := TokenTable.SpaceChars; + blck := []; + for i := 0 to TokenTable.CmtCount - 1 do begin + t := TokenTable.CmtBlock[i].Open[1]; + if t <> '' then blck := blck + [t[1]]; + end; + for i := 0 to TokenTable.CmtLine.Count - 1 do begin + t := TokenTable.CmtLine[i]; + if t <> '' then blck := blck + [t[1]]; + end; + srch := srch + blck; + + Token := ''; + Result := false; + TokenType := tt_Ident; + while (not Result) and (index <= length(Buf)) do begin + ScanWhile(Buf, index, TokenTable.SpaceChars); + if (Buf[index] in TokenTable.Symbols) then begin + if (not (Buf[index] in blck)) or (not SkipComments) then begin + Result := true; + TokenType := tt_Symbol; + Token := Buf[index]; + inc(index); + Exit; + end; + end else begin + Token := Token + ScanTo(Buf, index, srch+TokenTable.Symbols); + if (Buf[index] in blck) then begin + Result := SkipComments; + Result := Result or (Buf[index] in TokenTable.SpaceChars); + if not Result then begin + Token := Token + Buf[index]; + inc(index); + end; + end else + Result := true; + Result := Result and (Token <> ''); + end; + + end; {of while} + if not Result then TokenType := tt_None; +end; + +function TTextParser.SkipComments: Boolean; +var + i : Integer; +begin + Result := false; + for i := 0 to TokenTable.CmtCount - 1 do + if IsSubStr(TokenTable.CmtBlock[i].Open, Buf, index) then begin + inc(index, length(TokenTable.CmtBlock[i].Open)); + SkipCommentBlock(Buf, index, TokenTable.CmtBlock[i].Close); + Result := true; + Exit; + end; + for i := 0 to TokenTable.CmtLine.Count - 1 do + if IsSubStr(TokenTable.CmtLine[i], Buf, index) then begin + SkipLine(Buf, index); + Result := true; + Exit; + end; +end; + +{ TTokenTable } + +constructor TTokenTable.Create; +begin + CmtLine := TStringList.Create; +end; + +destructor TTokenTable.Destroy; +begin + CmtLine.Free; + inherited; +end; + +{ TEntity } + +constructor TEntity.Create; +begin + inherited; + Items := TList.Create; +end; + +destructor TEntity.Destroy; +begin + Items.Free; + inherited Destroy; +end; + +{ TClassDef } + +procedure TClassDef.Parse(AParser:TTextParser); +var + s : AnsiString; + tt : TTokenType; + cnt : Integer; + mtd : TClassMethodDef; +begin + AParser.FindNextToken(_ClassName, tt); + if (not AParser.FindNextToken(s, tt)) then Exit; + if tt = tt_Symbol then begin + if s[1] = ':' then + AParser.FindNextToken(_SuperClass, tt) + else if s[1] = '(' then begin + AParser.FindNextToken(_Category, tt); + AParser.FindNextToken(s, tt); + end else + Exit; + end; + + cnt := 0; + repeat + if not AParser.FindNextToken(s, tt) then begin + s := ''; + exit; + end; + + if s = '{' then inc(cnt) + else if s = '}' then dec(cnt) + else if (cnt = 0) then begin + //todo: better parsing + if s[1] ='#' then SkipLine(AParser.buf, AParser.Index); + if (s = '+') or (s = '-') then begin + dec(AParser.Index ); // roll back a single character + mtd := TClassMethodDef.Create; + mtd.Parse(AParser); + Items.Add(mtd); + end; + end; + until (s = '@end') or (s = ''); +end; + +{ TObjCHeader } + +constructor TObjCHeader.Create; +begin + + inherited Create; + +end; + + + +procedure TObjCHeader.Parse(AParser:TTextParser); +var + s : AnsiString; + tt : TTokenType; + cl : TClassDef; +begin + while AParser.FindNextToken(s, tt) do begin + if s = '@interface' then begin + cl := TClassDef.Create; + cl.Parse(AParser); + Items.Add(cl); + end; + end; +end; + +{ TClassMethodDef } + +function TClassMethodDef.GetResultType: TResultTypeDef; +var + i : integer; +begin + + for i := 0 to Items.Count - 1 do + + if TObject(Items[i]) is TResultTypeDef then begin + + Result := TResultTypeDef(Items[i]); + + Exit; + + end; + + Result := nil; + +end; + + + +procedure TClassMethodDef.Parse(AParser:TTextParser); +var + s : AnsiString; + tt : TTokenType; + res : TResultTypeDef; + para : TParameterDef; + des : TParamDescr; +begin + AParser.FindNextToken(s, tt); + if (s <> '+') and (s <> '-') then Exit; + _CallChar := s[1]; + _IsClassMethod := _CallChar = '+'; + + AParser.FindNextToken(s, tt); + if (tt = tt_Symbol) and(s = '(') then begin + // _Class methods can be with out type + dec(AParser.Index); + res := TResultTypeDef.Create; + res.Parse(AParser); + Items.Add(res); + end; + AParser.FindNextToken(_Name, tt); + + if _Name = '_id' then + _Name := '_id'; + + while AParser.FindNextToken(s, tt) do begin + if s = ';' then + Exit + else if s = ':' then begin + para := TParameterDef.Create; + para.Parse(AParser); + Items.Add(para); + end else if tt = tt_Ident then begin + des := TParamDescr.Create; + des._Descr := s; + Items.Add(des) + end; + + end; +// AParser.FindNextToken() +end; + +{ TParameterDef } + +function TParameterDef.GetResultType: TResultTypeDef; +begin + + Result := _Res; + +end; + + + +procedure TParameterDef.Parse(AParser:TTextParser); +var + tt : TTokenType; +begin + _Res := TResultTypeDef.Create; + Items.Add(_Res); + _Res.Parse(AParser); + AParser.FindNextToken(_Name, tt) +end; + +{ TResultTypeDef } + + +procedure TResultTypeDef.Parse(AParser: TTextParser); +var + s : AnsiString; + tt : TTokenType; +begin + + AParser.FindNextToken(s, tt); + + if (tt <> tt_Symbol) and (s <> '(') then Exit; + + AParser.FindNextToken(_TypeName, tt); + + if _TypeName = 'unsigned' then begin + + AParser.FindNextToken(s, tt); + + _TypeName := _TypeName + ' ' + s; + + end; + + if tt <> tt_Ident then Exit; // an error + + + + AParser.FindNextToken(s, tt); + + if (tt = tt_Symbol) and (s = '*') then begin + + _isRef := true; + + AParser.FindNextToken(s, tt); + + end; + + if s <> ')' then ; // an error + +end; + + + +{ TParamDescr } + + +procedure TParamDescr.Parse(AParser: TTextParser); +var + tt : TTokenType; +begin + + AParser.FindNextToken(_Descr, tt); + +end; + + + +end. diff --git a/bindings/pascocoa/parser/input.txt b/bindings/pascocoa/parser/input.txt new file mode 100755 index 000000000..8d393db5e --- /dev/null +++ b/bindings/pascocoa/parser/input.txt @@ -0,0 +1,161 @@ +H:\ObjectiveC\AppKit.h +H:\ObjectiveC\AppKitDefines.h +H:\ObjectiveC\AppKitErrors.h +H:\ObjectiveC\NSAccessibility.h +H:\ObjectiveC\NSActionCell.h +H:\ObjectiveC\NSAffineTransform.h +H:\ObjectiveC\NSAlert.h +H:\ObjectiveC\NSAnimation.h +H:\ObjectiveC\NSAppleScriptExtensions.h +H:\ObjectiveC\NSApplication.h +H:\ObjectiveC\NSApplicationScripting.h +H:\ObjectiveC\NSArrayController.h +H:\ObjectiveC\NSATSTypesetter.h +H:\ObjectiveC\NSAttributedString.h +H:\ObjectiveC\NSBezierPath.h +H:\ObjectiveC\NSBitmapImageRep.h +H:\ObjectiveC\NSBox.h +H:\ObjectiveC\NSBrowser.h +H:\ObjectiveC\NSBrowserCell.h +H:\ObjectiveC\NSButton.h +H:\ObjectiveC\NSButtonCell.h +H:\ObjectiveC\NSCachedImageRep.h +H:\ObjectiveC\NSCell.h +H:\ObjectiveC\NSCIImageRep.h +H:\ObjectiveC\NSClipView.h +H:\ObjectiveC\NSColor.h +H:\ObjectiveC\NSColorList.h +H:\ObjectiveC\NSColorPanel.h +H:\ObjectiveC\NSColorPicker.h +H:\ObjectiveC\NSColorPicking.h +H:\ObjectiveC\NSColorSpace.h +H:\ObjectiveC\NSColorWell.h +H:\ObjectiveC\NSComboBox.h +H:\ObjectiveC\NSComboBoxCell.h +H:\ObjectiveC\NSControl.h +H:\ObjectiveC\NSController.h +H:\ObjectiveC\NSCursor.h +H:\ObjectiveC\NSCustomImageRep.h +H:\ObjectiveC\NSDatePicker.h +H:\ObjectiveC\NSDatePickerCell.h +H:\ObjectiveC\NSDocument.h +H:\ObjectiveC\NSDocumentController.h +H:\ObjectiveC\NSDocumentScripting.h +H:\ObjectiveC\NSDragging.h +H:\ObjectiveC\NSDrawer.h +H:\ObjectiveC\NSEPSImageRep.h +H:\ObjectiveC\NSErrors.h +H:\ObjectiveC\NSEvent.h +H:\ObjectiveC\NSFileWrapper.h +H:\ObjectiveC\NSFont.h +H:\ObjectiveC\NSFontDescriptor.h +H:\ObjectiveC\NSFontManager.h +H:\ObjectiveC\NSFontPanel.h +H:\ObjectiveC\NSForm.h +H:\ObjectiveC\NSFormCell.h +H:\ObjectiveC\NSGlyphGenerator.h +H:\ObjectiveC\NSGlyphInfo.h +H:\ObjectiveC\NSGraphics.h +H:\ObjectiveC\NSGraphicsContext.h +H:\ObjectiveC\NSHelpManager.h +H:\ObjectiveC\NSImage.h +H:\ObjectiveC\NSImageCell.h +H:\ObjectiveC\NSImageRep.h +H:\ObjectiveC\NSImageView.h +H:\ObjectiveC\NSInputManager.h +H:\ObjectiveC\NSInputServer.h +H:\ObjectiveC\NSInterfaceStyle.h +H:\ObjectiveC\NSKeyValueBinding.h +H:\ObjectiveC\NSLayoutManager.h +H:\ObjectiveC\NSLevelIndicator.h +H:\ObjectiveC\NSLevelIndicatorCell.h +H:\ObjectiveC\NSMatrix.h +H:\ObjectiveC\NSMenu.h +H:\ObjectiveC\NSMenuItem.h +H:\ObjectiveC\NSMenuItemCell.h +H:\ObjectiveC\NSMenuView.h +H:\ObjectiveC\NSMovie.h +H:\ObjectiveC\NSMovieView.h +H:\ObjectiveC\NSNib.h +H:\ObjectiveC\NSNibConnector.h +H:\ObjectiveC\NSNibControlConnector.h +H:\ObjectiveC\NSNibDeclarations.h +H:\ObjectiveC\NSNibLoading.h +H:\ObjectiveC\NSNibOutletConnector.h +H:\ObjectiveC\NSObjectController.h +H:\ObjectiveC\NSOpenGL.h +H:\ObjectiveC\NSOpenGLView.h +H:\ObjectiveC\NSOpenPanel.h +H:\ObjectiveC\NSOutlineView.h +H:\ObjectiveC\NSPageLayout.h +H:\ObjectiveC\NSPanel.h +H:\ObjectiveC\NSParagraphStyle.h +H:\ObjectiveC\NSPasteboard.h +H:\ObjectiveC\NSPDFImageRep.h +H:\ObjectiveC\NSPersistentDocument.h +H:\ObjectiveC\NSPICTImageRep.h +H:\ObjectiveC\NSPopUpButton.h +H:\ObjectiveC\NSPopUpButtonCell.h +H:\ObjectiveC\NSPrinter.h +H:\ObjectiveC\NSPrintInfo.h +H:\ObjectiveC\NSPrintOperation.h +H:\ObjectiveC\NSPrintPanel.h +H:\ObjectiveC\NSProgressIndicator.h +H:\ObjectiveC\NSQuickDrawView.h +H:\ObjectiveC\NSResponder.h +H:\ObjectiveC\NSRulerMarker.h +H:\ObjectiveC\NSRulerView.h +H:\ObjectiveC\NSSavePanel.h +H:\ObjectiveC\NSScreen.h +H:\ObjectiveC\NSScroller.h +H:\ObjectiveC\NSScrollView.h +H:\ObjectiveC\NSSearchField.h +H:\ObjectiveC\NSSearchFieldCell.h +H:\ObjectiveC\NSSecureTextField.h +H:\ObjectiveC\NSSegmentedCell.h +H:\ObjectiveC\NSSegmentedControl.h +H:\ObjectiveC\NSShadow.h +H:\ObjectiveC\NSSimpleHorizontalTypesetter.h +H:\ObjectiveC\NSSlider.h +H:\ObjectiveC\NSSliderCell.h +H:\ObjectiveC\NSSound.h +H:\ObjectiveC\NSSpeechRecognizer.h +H:\ObjectiveC\NSSpeechSynthesizer.h +H:\ObjectiveC\NSSpellChecker.h +H:\ObjectiveC\NSSpellProtocol.h +H:\ObjectiveC\NSSpellServer.h +H:\ObjectiveC\NSSplitView.h +H:\ObjectiveC\NSStatusBar.h +H:\ObjectiveC\NSStatusItem.h +H:\ObjectiveC\NSStepper.h +H:\ObjectiveC\NSStepperCell.h +H:\ObjectiveC\NSStringDrawing.h +H:\ObjectiveC\NSTableColumn.h +H:\ObjectiveC\NSTableHeaderCell.h +H:\ObjectiveC\NSTableHeaderView.h +H:\ObjectiveC\NSTableView.h +H:\ObjectiveC\NSTabView.h +H:\ObjectiveC\NSTabViewItem.h +H:\ObjectiveC\NSText.h +H:\ObjectiveC\NSTextAttachment.h +H:\ObjectiveC\NSTextContainer.h +H:\ObjectiveC\NSTextField.h +H:\ObjectiveC\NSTextFieldCell.h +H:\ObjectiveC\NSTextList.h +H:\ObjectiveC\NSTextStorage.h +H:\ObjectiveC\NSTextStorageScripting.h +H:\ObjectiveC\NSTextTable.h +H:\ObjectiveC\NSTextView.h +H:\ObjectiveC\NSTokenField.h +H:\ObjectiveC\NSTokenFieldCell.h +H:\ObjectiveC\NSToolbar.h +H:\ObjectiveC\NSToolbarItem.h +H:\ObjectiveC\NSTreeController.h +H:\ObjectiveC\NSTypesetter.h +H:\ObjectiveC\NSUserDefaultsController.h +H:\ObjectiveC\NSUserInterfaceValidation.h +H:\ObjectiveC\NSView.h +H:\ObjectiveC\NSWindow.h +H:\ObjectiveC\NSWindowController.h +H:\ObjectiveC\NSWindowScripting.h +H:\ObjectiveC\NSWorkspace.h diff --git a/bindings/pascocoa/parser/objcparser.lpi b/bindings/pascocoa/parser/objcparser.lpi new file mode 100755 index 000000000..7a0d9bcda --- /dev/null +++ b/bindings/pascocoa/parser/objcparser.lpi @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bindings/pascocoa/parser/objcparser.pas b/bindings/pascocoa/parser/objcparser.pas new file mode 100755 index 000000000..19e24ca6a --- /dev/null +++ b/bindings/pascocoa/parser/objcparser.pas @@ -0,0 +1,83 @@ +program Project1; + +{$mode delphi}{$H+} + +uses + Classes, SysUtils, ObjCParserUtils, ObjCParserTypes; + { add your units here } + +procedure ReadAndParseFile(const FileName: AnsiString; outdata: TStrings); +var + hdr : TObjCHeader; + txt : TTextParser; + s : AnsiString; +begin + if not FileExists(FileName) then Exit; + s := StrFromFile(FileName); + hdr := TObjCHeader.Create; + txt := TTextParser.Create; + txt.TokenTable := CreateObjCTokenTable; + try + txt.Buf := s; + try + hdr.Parse(txt); + except + end; + outdata.Add(''); + outdata.Add('// ' + FileName); + outdata.Add(''); + ReportHeader(hdr, outdata); + finally + hdr.Free; + txt.TokenTable.Free; + txt.Free; + end; +end; + +procedure GetParams(var InpFile, OutFile: AnsiString); +begin + InpFile := ParamStr(1); + OutFile := ParamStr(2); +end; + +var + inpf, outf : AnsiString; + f : Text; + st : TStrings; + fn : AnsiString; + i : integer; +begin + inpf := ''; outf := ''; + GetParams(inpf, outf); + writeln('input file: ', inpf); + writeln('output file: ', outf); + if not FileExists(inpf) then begin + writeln('input file does not exists or anavailable'); + Exit; + end; + + st := TStringList.Create; + try + Assign(f, inpf); Reset(f); + while not eof(f) do begin + readln(f, fn); + try + ReadAndParseFile(fn, st); + except + end; + end; + Close(f); + + Assign(f, outf); Rewrite(f); + try + for i := 0 to st.Count - 1 do + writeln(f, st[i]); + except + end; + Close(f); + + finally + st.Free; + end; +end. +