lazarus-ccr/applications/idlparser/idlparser.pas
2012-03-19 14:10:59 +00:00

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.