function InnerfuseCall2(SE: TIFPasScript; Self, Address: Pointer; CallingConv: TCallingConvention; Params: PVariableManager; Res: PIFVariant; Ext: TExternalObjectToStr; ExtPtr: Pointer): Boolean; // res should already have been created with the type used for it
function ReadHeader(SE: TIfPasScript; Decl: String; var FuncName, FuncParam: String; Var CC: TCallingConvention; DefaultCC: TCallingConvention): Boolean;
implementation
function ReadHeader(SE: TIfPasScript; Decl: String; var FuncName, FuncParam: String; Var CC: TCallingConvention; DefaultCC: TCallingConvention): Boolean;
var
Parser: TIfPascalParser;
CurrVar: string;
FuncRes,
CurrType: Longint;
E: TIFParserError;
function GetType(const s: string): Longint;
var
t: PTypeRec;
begin
if (S = 'PCHAR') then
begin
t := SE.GetType('!PCHAR');
if t = nil then
begin
t := Se.AddTypeEx('!PCHAR');
t^.Ext := Pointer(1);
end;
GetType := Longint(T);
end else
if (S = 'LONGBOOL') then
begin
t := SE.GetType('!LONGBOOL');
if t = nil then
begin
t := Se.AddTypeEx('!LONGBOOL');
t^.Ext := Pointer(2);
end;
GetType := Longint(T);
end else
if (S = 'WORDBOOL') then
begin
t := SE.GetType('!WORDBOOL');
if t = nil then
begin
t := Se.AddTypeEx('!WORDBOOL');
t^.Ext := Pointer(1);
end;
GetType := Longint(T);
end else
begin
t := SE.GetType(S);
if not assigned(t) then begin GetType := 0; exit; end;
case T.atypeid of
CSV_UByte,
CSV_SByte,
CSV_UInt16,
CSV_SInt16,
CSV_UInt32,
CSV_SInt32,
CSV_Char,
CSV_Bool,
{$IFNDEF NOCLASSES}
CSV_Class,
{$ENDIF}
CSV_String{,
CSV_Record}: GetType := Longint(T);
else GetType := 0;
end;
end;
end;
begin
Parser := TIfPascalParser.Create;
ReadHeader := False;
if not Parser.SetText(Decl, E) then
begin
parser.Free;
exit;
end;
if Parser.CurrTokenId = CSTII_Procedure then
FuncRes := 0
else
FuncRes := 1;
Parser.Next;
FuncName := Parser.GetToken;
Parser.Next;
FuncParam := '';
CurrVar := '';
if Parser.CurrTokenId = CSTI_OpenRound then begin
Parser.Next;
while True do begin
if Parser.CurrTokenId = CSTI_Eof then begin
Parser.Free;
exit;
end;
if Parser.CurrTokenId = CSTII_Var then begin
CurrVar := '!';
Parser.Next;
end; {if}
while True do begin
if Parser.CurrTokenId = CSTI_Eof then begin
Parser.Free;
exit;
end;
if Parser.CurrTokenId <> CSTI_Identifier then begin
if Parser.CurrTokenId = CSTI_CloseRound then begin
Parser.Next;
break;
end; {if}
Parser.Next;
end;
end;
if FuncRes = 1 then begin
Parser.Next;
FuncRes := GetType(Parser.GetToken);
if FuncRes = 0 then begin
Parser.Free;
exit;
end;
Parser.Next;
end;
CC := ccRegister;
if Parser.CurrTokenID = CSTI_Semicolon then
begin
Parser.Next;
if Parser.CurrTokenId = CSTI_Identifier then
begin
if Parser.GetToken = 'STDCALL' then
CC := CCStdCall
else if Parser.GetToken = 'CDECL' then
CC := CCCdecl
else if Parser.GetToken = 'PASCAL' then
CC := ccPascal
else if Parser.GetToken = 'REGISTER' then
cc := ccRegister
else
cc := DefaultCC;
// Register is default.
end;
end;
FuncParam := inttostr(FuncRes) + FuncParam;
ReadHeader := True;
Parser.Free;
end;
function RealCall_Register(p: Pointer;
_EAX, _EDX, _ECX: Cardinal;
StackData: pointer;
StackDataLen: Longint; // stack length are in 4 bytes. (so 1 = 4 bytes)
ResultLength: Longint):Longint; stdcall; // make sure all things are on stack
var
r: Longint;
begin
asm
mov ecx, stackdatalen
jecxz @@2
mov eax, stackdata
@@1:
mov edx, [eax]
push edx
add eax,4
dec ecx
or ecx, ecx
jnz @@1
@@2:
mov eax,_EAX
mov edx,_EDX
mov ecx,_ECX
call p
mov ecx, resultlength
cmp ecx, 0
je @@5
cmp ecx, 1
je @@3
cmp ecx, 2
je @@4
mov r, eax
jmp @@5
@@3:
xor ecx, ecx
mov cl, al
mov r, ecx
jmp @@5
@@4:
xor ecx, ecx
mov cx, ax
mov r, ecx
@@5:
end;
result := r;
end;
function RealCall_Other(p: Pointer;
StackData: pointer;
StackDataLen: Longint; // stack length are in 4 bytes. (so 1 = 4 bytes)
ResultLength: Longint): Longint; stdcall; // make sure all things are on stack
var
R: Longint;
begin
asm
mov ecx, stackdatalen
jecxz @@2
mov eax, stackdata
@@1:
mov edx, [eax]
push edx
add eax,4
dec ecx
or ecx, ecx
jnz @@1
@@2:
call p
mov ecx, resultlength
cmp ecx, 0
je @@5
cmp ecx, 1
je @@3
cmp ecx, 2
je @@4
mov r, eax
jmp @@5
@@3:
xor ecx, ecx
mov cl, al
mov r, ecx
jmp @@5
@@4:
xor ecx, ecx
mov cx, ax
mov r, ecx
@@5:
end;
result := r;
end;
function RealCall_CDecl(p: Pointer;
StackData: pointer;
StackDataLen: Longint; // stack length are in 4 bytes. (so 1 = 4 bytes)
ResultLength: Longint): Longint; stdcall; // make sure all things are on stack
var
R: Longint;
begin
asm
mov ecx, stackdatalen
jecxz @@2
mov eax, stackdata
@@1:
mov edx, [eax]
push edx
add eax,4
dec ecx
or ecx, ecx
jnz @@1
@@2:
call p
mov ecx, resultlength
cmp ecx, 0
je @@5
cmp ecx, 1
je @@3
cmp ecx, 2
je @@4
mov r, eax
jmp @@5
@@3:
xor ecx, ecx
mov cl, al
mov r, ecx
jmp @@5
@@4:
xor ecx, ecx
mov cx, ax
mov r, ecx
@@5:
mov ecx, stackdatalen
jecxz @@2
@@6:
pop edx
dec ecx
or ecx, ecx
jnz @@6
end;
Result := R;
end;
function InnerfuseCall(SE: TIFPasScript; Self, Address: Pointer; CallingConv: TCallingConvention; Params: PVariableManager; Res: PIFVariant): Boolean; // res should already have been created with the type used for it
begin
Result := InnerfuseCall2(Se, Self, Address, CallingConv, Params, Res, nil, nil);
end;
function InnerfuseCall2(SE: TIFPasScript; Self, Address: Pointer; CallingConv: TCallingConvention; Params: PVariableManager; Res: PIFVariant; Ext: TExternalObjectToStr; ExtPtr: Pointer): Boolean; // res should already have been created with the type used for it
var
temp, Stack: ansistring;
i: Longint;
RegUsage: Byte;
EAX, EDX, ECX: Longint;
b: Boolean;
function GetPtr(fvar: PIFVariant; var CanInRegister: Boolean): string;
begin
CanInRegister := True;
result := '';
if FVar^.VType^.atypeid = CSV_Var then
begin
FVar := GetVarLink(FVar);
case FVar^.vtype^.atypeid of
{$IFNDEF NOCLASSES}
CSV_Class:
begin
Result := #0#0#0#0;
Pointer((@Result[1])^) := @(FVar^.CV_Class^.Ext);
end;
{$ENDIF}
CSV_Bool, CSV_Char, CSV_UByte, CSV_SByte:
begin
Result := #0#0#0#0;
Pointer((@Result[1])^) := @(FVar^.CV_Char);
end;
CSV_UInt16, CSV_SInt16:
begin
Result := #0#0#0#0;
Pointer((@Result[1])^) := @(FVar^.CV_UInt16);
end;
CSV_UInt32, CSV_SInt32:
begin
Result := #0#0#0#0;
Pointer((@Result[1])^) := @(FVar^.CV_UInt32);
end;
CSV_String:
begin
Result := #0#0#0#0;
Pointer((@Result[1])^) := @(FVar^.CV_Str);
end;
else
begin
exit; //invalid type
end;
end;
end else begin
case FVar^.VType^.atypeid of
{$IFNDEF NOCLASSES}
CSV_Class:
begin
Result := #0#0#0#0;
Pointer((@Result[1])^) := FVar^.CV_Class^.Ext;
end;
{$ENDIF}
CSV_Char, CSV_UByte, CSV_SByte, CSV_Bool:
begin
Result := FVar^.CV_Char + #0#0#0;
end;
CSV_UInt16, CSV_SInt16:
begin
Result := #0#0#0#0;
Word((@Result[1])^) := FVar^.CV_UInt16;
end;
CSV_UInt32, CSV_SInt32:
begin
Result := Result + #0#0#0#0;
Longint((@Result[1])^) := FVar^.CV_SInt32;
end;
CSV_String:
begin
Result := #0#0#0#0;
if FVar^.VType^.Ext = nil then
begin
if FVar^.cv_Str <> '' then
Pointer((@Result[1])^) := Pointer(FVar^.CV_Str);
end else begin
if FVar^.cv_Str <> '' then
Pointer((@Result[1])^) := Pchar(FVar^.CV_Str);
end;
end;
else
begin
exit; //invalid type
end;
end;
end;
end;
begin
InnerfuseCall2 := False;
if Address = nil then
exit; // need address
stack := '';
case CallingConv of
ccRegister:
begin
EAX := 0;
EDX := 0;
ECX := 0;
RegUsage:= 0;
if assigned(Self) then
begin
RegUsage := 1;
EAX := Longint(Self);
end;
for i := 0 to VM_Count(Params)-1 do
begin
temp := GetPtr(VM_Get(Params, i), b);
if temp = '' then exit;
if b and (regusage < 3) then
begin
case RegUsage of
0: begin EAX := Longint((@Temp[1])^); Inc(RegUsage); end;
1: begin EDX := Longint((@Temp[1])^); Inc(RegUsage); end;
2: begin ECX := Longint((@Temp[1])^); Inc(RegUsage); end;