
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@2356 8e941d3f-bd1b-0410-a28a-d453659cc2b4
539 lines
16 KiB
ObjectPascal
539 lines
16 KiB
ObjectPascal
unit idlParser;
|
|
|
|
{ Unit which parses idl (interface description language) files into a TIDLList
|
|
struct.
|
|
|
|
Copyright (C) 2012 Joost van der Sluis/CNOC joost@cnoc.nl
|
|
|
|
This library is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU Library General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or (at your
|
|
option) any later version with the following modification:
|
|
|
|
As a special exception, the copyright holders of this library give you
|
|
permission to link this library with independent modules to produce an
|
|
executable, regardless of the license terms of these independent modules,and
|
|
to copy and distribute the resulting executable under terms of your choice,
|
|
provided that you also meet, for each linked independent module, the terms
|
|
and conditions of the license of that module. An independent module is a
|
|
module which is not derived from or based on this library. If you modify
|
|
this library, you may extend this exception to your version of the library,
|
|
but you are not obligated to do so. If you do not wish to do so, delete this
|
|
exception statement from your version.
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; if not, write to the Free Software Foundation,
|
|
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
}
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils,contnrs;
|
|
|
|
type
|
|
TMemberType=(mtFunc,mtAttribute,mtConst);
|
|
TParamInOutType=(piNormal,piOut,piIn,piInOut);
|
|
|
|
{ TIDLMemberParameter }
|
|
|
|
TIDLMemberParameter = class
|
|
private
|
|
FParamInOutType: TParamInOutType;
|
|
FParamName: string;
|
|
FParamType: string;
|
|
FParamTypeUnsigned: boolean;
|
|
public
|
|
property ParamType : string read FParamType write FParamType;
|
|
property ParamTypeUnsigned: boolean read FParamTypeUnsigned write FParamTypeUnsigned;
|
|
property ParamName: string read FParamName write FParamName;
|
|
property ParamInOutType: TParamInOutType read FParamInOutType write FParamInOutType;
|
|
end;
|
|
|
|
TIDLMemberParameterList = class(TObjectList);
|
|
|
|
{ TIDLMember }
|
|
|
|
TIDLMember = class
|
|
private
|
|
FMemberName: string;
|
|
FMemberReadonly: boolean;
|
|
FMemberType: TMemberType;
|
|
FParams: TIDLMemberParameterList;
|
|
FReturnType: string;
|
|
FConstValue: string;
|
|
FReturnTypeUnsigned: boolean;
|
|
public
|
|
constructor Create; virtual;
|
|
destructor Destroy; override;
|
|
property MemberType : TMemberType read FMemberType write FMemberType;
|
|
property ReturnType : string read FReturnType write FReturnType;
|
|
property ReturnTypeUnsigned: boolean read FReturnTypeUnsigned write FReturnTypeUnsigned;
|
|
property MemberName: string read FMemberName write FMemberName;
|
|
property MemberReadonly: boolean read FMemberReadonly write FMemberReadonly;
|
|
property Params: TIDLMemberParameterList read FParams;
|
|
property ConstValue: string read FConstValue write FConstValue;
|
|
end;
|
|
|
|
TIDLMemberList = class(TObjectList);
|
|
|
|
TIDL = class
|
|
private
|
|
FInterfaceName: string;
|
|
FInterfaceType: string;
|
|
Fmembers: TIDLMemberList;
|
|
FUUID: string;
|
|
public
|
|
constructor Create; virtual;
|
|
destructor Destroy; override;
|
|
property InterfaceName: string read FInterfaceName write FInterfaceName;
|
|
property InterfaceType: string read FInterfaceType write FInterfaceType;
|
|
property UUID: string read FUUID write FUUID;
|
|
property members: TIDLMemberList read Fmembers;
|
|
end;
|
|
|
|
TIDLList = class(TObjectList);
|
|
|
|
|
|
procedure ParseFile(const AnIdlList: TIDLList; const IDLtext: tstrings);
|
|
|
|
implementation
|
|
|
|
const
|
|
idlInterface = 'interface';
|
|
idlUUID = 'uuid';
|
|
idlattribute = 'attribute';
|
|
idlconst = 'const';
|
|
idlreadonly = 'readonly';
|
|
idlInterfaceEnd = ';';
|
|
idlUnsigned = 'unsigned';
|
|
idlMemberEnd = ';';
|
|
idlInterfaceTypeSeparator = ':';
|
|
idlInterfaceBlockStart = '{';
|
|
idlInterfaceBlockEnd = '}';
|
|
idlStartMultiLineComment = '/*';
|
|
idlEndMultiLineComment = '*/';
|
|
idlStartExtension = '%{';
|
|
idlEndExtension = '%}';
|
|
idlStartSingleLineComment = '//';
|
|
idlEndSingleLineComment = #10;
|
|
idlStartIDLAttributesBlock = '[';
|
|
idlEndIDLAttributesBlock = ']';
|
|
idlStartUUID = '(';
|
|
idlEndUUID = ')';
|
|
idlSeparateFuncParams = ',';
|
|
idlStartFuncParams = '(';
|
|
idlEndFuncParams = ')';
|
|
idlParamIn = 'in';
|
|
idlParamOut = 'out';
|
|
idlConstAssign = '=';
|
|
|
|
procedure ParseFile(const AnIdlList: TIDLList; const IDLtext: tstrings);
|
|
|
|
type TParseState = (psBegin,
|
|
psMultiLineComment,
|
|
psSingleLineComment,
|
|
psInterface,
|
|
psInterfaceType,
|
|
psInterfaceBlock,
|
|
psInterfaceBlockFuncName,
|
|
psInterfaceBlockFuncParams,
|
|
psInterfaceBlockFuncParamName,
|
|
psInterfaceAfterFuncParams,
|
|
psParamAttributeBlock,
|
|
psConstValue,
|
|
psIDLAttributes,
|
|
psSearchUUID,
|
|
psUUID,
|
|
psExtension,
|
|
psWord);
|
|
|
|
var
|
|
PriorState: TParseState;
|
|
ParseState: TParseState;
|
|
IDLString: string;
|
|
pCurrent: pchar;
|
|
AWord: string;
|
|
LineNr: integer;
|
|
pWordStart: pchar;
|
|
wordchars: set of char;
|
|
UUIDAttribute: string;
|
|
CurrentIDL: TIDL;
|
|
CurrentIDLMember: TIDLMember;
|
|
CurrentIDLMemberParam: TIDLMemberParameter;
|
|
IsAttribute, IsReadonly: boolean;
|
|
IsConst: boolean;
|
|
IsParamIn, IsParamOut: boolean;
|
|
IsUnsigned: boolean;
|
|
|
|
function CheckChar(const ACheckForString: string; ASetParseState: TParseState): boolean;
|
|
begin
|
|
result := false;
|
|
if CompareChar(pCurrent^,ACheckForString[1], length(ACheckForString))=0 then
|
|
begin
|
|
ParseState := ASetParseState;
|
|
inc(pcurrent,length(ACheckForString));
|
|
result := True;
|
|
end;
|
|
end;
|
|
|
|
function CheckChar(const ACheckForString: string; ASetParseState, ASetPriorParseState: TParseState): boolean;
|
|
begin
|
|
result := CheckChar(ACheckForString, ASetParseState);
|
|
if result then
|
|
PriorState:=ASetPriorParseState;
|
|
end;
|
|
|
|
function CheckStartWord(ASetParseState, ASetPriorParseState: TParseState; AllowMinus: boolean = false): boolean;
|
|
begin
|
|
result := false;
|
|
wordchars:=['a'..'z','A'..'Z','0'..'9','_'];
|
|
if AllowMinus then include(wordchars,'-');
|
|
if pCurrent^ in wordchars then
|
|
begin
|
|
pWordStart:=pCurrent;
|
|
PriorState:=ASetPriorParseState;
|
|
ParseState := ASetParseState;
|
|
inc(pcurrent);
|
|
result := True;
|
|
end;
|
|
end;
|
|
|
|
function CheckEndWord(ASetParseState: TParseState): boolean;
|
|
var
|
|
i: integer;
|
|
begin
|
|
result := false;
|
|
if not (pCurrent^ in wordchars) then
|
|
begin
|
|
i := pCurrent-pWordStart;
|
|
SetLength(AWord,i);
|
|
move(pWordStart^,AWord[1],i);
|
|
if PriorState = psInterface then
|
|
CurrentIDL.InterfaceName:=AWord
|
|
else if PriorState = psInterfaceType then
|
|
CurrentIDL.InterfaceType:=AWord
|
|
else if PriorState = psSearchUUID then
|
|
UUIDAttribute:=AWord
|
|
else if PriorState = psInterfaceBlockFuncName then
|
|
CurrentIDLMember.MemberName:=AWord
|
|
else if PriorState = psInterfaceBlockFuncParamName then
|
|
CurrentIDLMemberParam.ParamName:=AWord;
|
|
ParseState := ASetParseState;
|
|
result := True;
|
|
end;
|
|
end;
|
|
|
|
function CheckStartConst: boolean;
|
|
begin
|
|
result := CheckChar(idlConstAssign,psConstValue);
|
|
if Result then
|
|
begin
|
|
pWordStart:=pCurrent;
|
|
ParseState := psConstValue;
|
|
inc(pcurrent);
|
|
end;
|
|
end;
|
|
|
|
function CheckEndConst: boolean;
|
|
var
|
|
i: integer;
|
|
begin
|
|
result := CheckChar(idlMemberEnd,psInterfaceBlock);
|
|
if result then
|
|
begin
|
|
i := pCurrent-pWordStart-1;
|
|
SetLength(AWord,i);
|
|
move(pWordStart^,AWord[1],i);
|
|
CurrentIDLMember.ConstValue:=AWord;
|
|
ParseState := psInterfaceBlock;
|
|
inc(pcurrent);
|
|
end;
|
|
end;
|
|
|
|
function CheckInterfaceStart: boolean;
|
|
begin
|
|
result := CheckChar(idlInterface, psInterface);
|
|
if result then
|
|
begin
|
|
CurrentIDL := TIDL.Create;
|
|
AnIdlList.Add(CurrentIDL);
|
|
CurrentIDL.UUID:=UUIDAttribute;
|
|
UUIDAttribute:='';
|
|
end;
|
|
end;
|
|
|
|
function CheckFuncStart: boolean;
|
|
begin
|
|
result := CheckStartWord(psWord, psInterfaceBlockFuncName);
|
|
if result then
|
|
begin
|
|
CurrentIDLMember := TIDLMember.Create;
|
|
if Isconst then
|
|
CurrentIDLMember.MemberType:=mtConst
|
|
else if IsAttribute then
|
|
CurrentIDLMember.MemberType:=mtAttribute
|
|
else
|
|
CurrentIDLMember.MemberType:=mtFunc;
|
|
CurrentIDLMember.MemberReadonly:=IsReadonly;
|
|
IsAttribute:=false;
|
|
IsConst:=false;
|
|
IsReadonly:=false;
|
|
CurrentIDL.members.Add(CurrentIDLMember);
|
|
end;
|
|
end;
|
|
|
|
function CheckParamStart: boolean;
|
|
begin
|
|
result := CheckStartWord(psWord, psInterfaceBlockFuncParamName);
|
|
if result then
|
|
begin
|
|
CurrentIDLMemberParam := TIDLMemberParameter.Create;
|
|
if IsParamIn and IsParamOut then
|
|
CurrentIDLMemberParam.ParamInOutType:=piInOut
|
|
else if IsParamIn then
|
|
CurrentIDLMemberParam.ParamInOutType:=piIn
|
|
else if IsParamOut then
|
|
CurrentIDLMemberParam.ParamInOutType:=piOut
|
|
else
|
|
CurrentIDLMemberParam.ParamInOutType:=piNormal;
|
|
IsParamIn:=false;
|
|
IsParamOut:=false;
|
|
CurrentIDLMember.Params.Add(CurrentIDLMemberParam);
|
|
end;
|
|
end;
|
|
|
|
function CheckAttributeStart: boolean;
|
|
begin
|
|
result := CheckChar(idlattribute, psInterfaceBlock);
|
|
if result then
|
|
IsAttribute := True;
|
|
end;
|
|
|
|
function CheckConstStart: boolean;
|
|
begin
|
|
result := CheckChar(idlconst, psInterfaceBlock);
|
|
if result then
|
|
IsConst := True;
|
|
end;
|
|
|
|
function CheckUnsigned: boolean;
|
|
begin
|
|
result := CheckChar(idlUnsigned, ParseState);
|
|
if result then
|
|
IsUnsigned := True;
|
|
end;
|
|
|
|
|
|
function CheckAttributeReadOnly: boolean;
|
|
begin
|
|
result := CheckChar(idlreadonly, psInterfaceBlock);
|
|
if result then
|
|
IsReadonly := True;
|
|
end;
|
|
|
|
function CheckParamIn: boolean;
|
|
begin
|
|
result := CheckChar(idlParamIn, psInterfaceBlockFuncParams);
|
|
if result then
|
|
IsParamIn := True;
|
|
end;
|
|
|
|
function CheckParamOut: boolean;
|
|
begin
|
|
result := CheckChar(idlParamOut, psInterfaceBlockFuncParams);
|
|
if result then
|
|
IsParamOut := True;
|
|
end;
|
|
|
|
|
|
begin
|
|
LineNr := 0;
|
|
ParseState:=psBegin;
|
|
IDLString:=IDLtext.Text;
|
|
if length(IDLString)=0 then
|
|
Exit;
|
|
|
|
IsAttribute:=false;
|
|
IsReadonly:=false;
|
|
IsUnsigned:=false;
|
|
IsConst:=false;
|
|
IsParamIn:=false;
|
|
IsParamOut:=false;
|
|
UUIDAttribute:='';
|
|
pCurrent:=@IDLString[1];
|
|
while pCurrent^ <> #0 do
|
|
begin
|
|
case ParseState of
|
|
psBegin:
|
|
begin
|
|
if not (CheckChar(idlStartMultiLineComment,psMultiLineComment,ParseState) or
|
|
CheckChar(idlStartExtension,psExtension,ParseState) or
|
|
CheckInterfaceStart or
|
|
CheckChar(idlStartIDLAttributesBlock,psIDLAttributes,ParseState) or
|
|
CheckChar(idlInterface,psInterface)) then
|
|
inc(pCurrent);
|
|
end;
|
|
psMultiLineComment:
|
|
begin
|
|
if not (CheckChar(idlEndMultiLineComment,PriorState)) then
|
|
inc(pCurrent);
|
|
end;
|
|
psExtension:
|
|
begin
|
|
if not (CheckChar(idlEndExtension,PriorState)) then
|
|
inc(pCurrent);
|
|
end;
|
|
psSingleLineComment:
|
|
begin
|
|
if not (CheckChar(idlEndSingleLineComment,PriorState)) then
|
|
inc(pCurrent);
|
|
end;
|
|
psParamAttributeBlock:
|
|
begin
|
|
if not (CheckChar(idlEndIDLAttributesBlock,PriorState)) then
|
|
inc(pCurrent);
|
|
end;
|
|
psIDLAttributes:
|
|
begin
|
|
if not (CheckChar(idlEndIDLAttributesBlock,psBegin) or
|
|
CheckChar(idlUUID, psSearchUUID)) then
|
|
inc(pCurrent);
|
|
end;
|
|
psSearchUUID:
|
|
begin
|
|
if not (CheckChar(idlStartUUID,psUUID) or
|
|
CheckChar(idlEndUUID, psIDLAttributes)) then
|
|
inc(pCurrent);
|
|
end;
|
|
psUUID:
|
|
begin
|
|
if not CheckStartWord(psWord,psSearchUUID,true) then
|
|
inc(pCurrent);
|
|
end;
|
|
psInterface, psInterfaceType:
|
|
begin
|
|
if not (CheckStartWord(psWord,ParseState) or
|
|
CheckChar(idlInterfaceBlockStart,psInterfaceBlock,ParseState) or
|
|
CheckChar(idlStartMultiLineComment,psMultiLineComment,ParseState) or
|
|
CheckChar(idlStartSingleLineComment,psSingleLineComment,ParseState) or
|
|
CheckChar(idlStartExtension,psExtension,ParseState) or
|
|
CheckChar(idlInterfaceTypeSeparator, psInterfaceType) or
|
|
CheckChar(idlInterfaceEnd, psBegin)) then
|
|
inc(pCurrent);
|
|
end;
|
|
psInterfaceBlock:
|
|
begin
|
|
if not (CheckChar(idlInterfaceBlockEnd,psInterface) or
|
|
CheckChar(idlStartMultiLineComment,psMultiLineComment,ParseState) or
|
|
CheckChar(idlStartExtension,psExtension,ParseState) or
|
|
CheckChar(idlStartSingleLineComment,psSingleLineComment,ParseState) or
|
|
CheckChar(idlStartIDLAttributesBlock,psParamAttributeBlock,ParseState) or
|
|
CheckAttributeStart or
|
|
CheckAttributeReadOnly or
|
|
CheckConstStart or
|
|
CheckUnsigned or
|
|
CheckFuncStart) then
|
|
inc(pCurrent)
|
|
end;
|
|
psInterfaceBlockFuncName:
|
|
begin
|
|
if CurrentIDLMember.ReturnType = '' then
|
|
begin
|
|
CurrentIDLMember.ReturnType:=aword;
|
|
CurrentIDLMember.ReturnTypeUnsigned := IsUnsigned;
|
|
IsUnsigned:=false;
|
|
end;
|
|
if not (CheckStartWord(psWord, psInterfaceBlockFuncName) or
|
|
CheckChar(idlStartFuncParams,psInterfaceBlockFuncParams) or
|
|
CheckChar(idlMemberEnd,psInterfaceBlock) or
|
|
CheckStartConst or
|
|
CheckChar(idlStartMultiLineComment,psMultiLineComment,ParseState)) then
|
|
inc(pCurrent)
|
|
end;
|
|
psInterfaceBlockFuncParams:
|
|
begin
|
|
if not (CheckChar(idlStartMultiLineComment,psMultiLineComment,ParseState) or
|
|
CheckChar(idlStartIDLAttributesBlock,psParamAttributeBlock,ParseState) or
|
|
CheckParamIn or
|
|
CheckParamOut or
|
|
CheckUnsigned or
|
|
CheckParamStart or
|
|
CheckChar(idlEndFuncParams,psInterfaceAfterFuncParams)) then
|
|
inc(pCurrent)
|
|
end;
|
|
psInterfaceAfterFuncParams:
|
|
begin
|
|
// voor een definitie als: 'nsIDOMNode setNamedItem(in nsIDOMNode arg) raises(DOMException);'
|
|
// negeer in dat geval alles na de parameters
|
|
if not (CheckChar(idlStartMultiLineComment,psMultiLineComment,ParseState) or
|
|
CheckChar(idlMemberEnd,psInterfaceBlock)) then
|
|
inc(pCurrent)
|
|
end;
|
|
|
|
psInterfaceBlockFuncParamName:
|
|
begin
|
|
if CurrentIDLMemberParam.ParamType = '' then
|
|
begin
|
|
CurrentIDLMemberParam.ParamType:=aword;
|
|
CurrentIDLMemberParam.ParamTypeUnsigned := IsUnsigned;
|
|
IsUnsigned:=false;
|
|
end;
|
|
if not (CheckStartWord(psWord, psInterfaceBlockFuncParamName) or
|
|
CheckChar(idlStartMultiLineComment,psMultiLineComment,ParseState) or
|
|
CheckChar(idlSeparateFuncParams,psInterfaceBlockFuncParams) or
|
|
CheckChar(idlEndFuncParams,psInterfaceAfterFuncParams)) then
|
|
inc(pCurrent)
|
|
end;
|
|
psConstValue:
|
|
begin
|
|
if not (CheckChar(idlStartMultiLineComment,psMultiLineComment,ParseState) or
|
|
CheckChar(idlStartSingleLineComment,psSingleLineComment,ParseState) or
|
|
CheckEndConst) then
|
|
inc(pCurrent)
|
|
end;
|
|
psWord:
|
|
begin
|
|
if not CheckEndWord(PriorState) then
|
|
inc(pCurrent);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{ TIDLMember }
|
|
|
|
constructor TIDLMember.Create;
|
|
begin
|
|
FParams := TIDLMemberParameterList.create;
|
|
end;
|
|
|
|
destructor TIDLMember.Destroy;
|
|
begin
|
|
FParams.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
{ TIDL }
|
|
|
|
constructor TIDL.Create;
|
|
begin
|
|
Fmembers := TIDLMemberList.create;
|
|
end;
|
|
|
|
destructor TIDL.Destroy;
|
|
begin
|
|
Fmembers.free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
end.
|
|
|