我如何构建一个const数组?

Sam*_*Sam 7 delphi

我正在实现一个解释器,我的解释器将支持的一个功能就像Delphi的Format.事实上,我正在使用我的函数SysUtils.Format.但是,我在构建函数的第二个参数时遇到了问题array of TVarRec.

假设我有以下代码.现在,我只假设解释代码需要访问哪些Delphi变量(iVar1iVar2),但我仍然不知道如何将它们放入Format需要(arFormatArgs)的结构中.

type TFormatArgs = array of TVarRec;

procedure RunInterpretedFormatFunction;
var
  iMyAge: integer;
  iMyIQ: integer;
  sCode: string;
  sText: string;
begin
  iMyAge := 5;
  iMyIQ := -5;
  sCode := 'Format(''My age is %d and my IQ is %d'', [iMyAge, iMyIQ])';
  sText := FormatThis(sCode, iMyAge, iMyIQ);
end;

function FormatThis(sFormatCode: string; iVar1: integer; iVar2: integer): string;
var
  sFormatString: string;
  arFormatArgs: TFormatArgs;
begin
  sFormatString := GetFormatString(sFormatCode); // I can implement this function
  arFormatArgs := ConstructFormatArgs(iVar1, iVar2); // NEED HELP HERE!
  result := SysUtils.Format(sFormatString, arFormatArgs);
end;
Run Code Online (Sandbox Code Playgroud)

如何ConstructFormatArgs在Delphi(而不是Assembly)中实现我的功能?

Gle*_*rse 6

const数组使您可以自由地添加字符串,整数,浮点数等,并将这些格式化为字符串.您可以添加的项目数量没有限制.

Delphi处理这个问题的方式是const数组实际上是TVarRec的数组.

TVarRec是以下类型的记录:

TVarRec = record
  case Byte of
    vtInteger:    (VInteger: Integer; VType: Byte);
    vtBoolean:    (VBoolean: Boolean);
    vtChar:       (VChar: Char);
    vtExtended:   (VExtended: PExtended);
    vtString:     (VString: PShortString);
    vtPointer:    (VPointer: Pointer);
    vtPChar:      (VPChar: PChar);
    vtObject:     (VObject: TObject);
    vtClass:      (VClass: TClass);
    vtWideChar:   (VWideChar: WideChar);
    vtPWideChar:  (VPWideChar: PWideChar);
    vtAnsiString: (VAnsiString: Pointer);
    vtCurrency:   (VCurrency: PCurrency);
    vtVariant:    (VVariant: PVariant);
Run Code Online (Sandbox Code Playgroud)

其中的值的类型由值TVarRec确定VType.

这使您可以灵活地将您希望的类型添加到const数组中,就像在Format()函数中一样:

格式('%s是一个字符串,%d是一个整数',['string',10]);

在您自己的过程中使用const数组没什么大不了的.看看这个例子:

 procedure VarArraySample( AVarArray : array of const );
  var
    i : integer;
  begin
    for i := 0 to High(AVarArray) do
      do_something;
  end;
Run Code Online (Sandbox Code Playgroud)

函数High()返回数组的最后一个索引.

您还可以转换TVarRec的内容.这个例子来自Delphi的在线帮助,并进行了一些修改.该函数将TVarRec转换为字符串:

function VarRecToStr( AVarRec : TVarRec ) : string;
  const
    Bool : array[Boolean] of string = ('False', 'True');
  begin
    case AVarRec.VType of
      vtInteger:    Result := IntToStr(AVarRec.VInteger);
      vtBoolean:    Result := Bool[AVarRec.VBoolean];
      vtChar:       Result := AVarRec.VChar;
      vtExtended:   Result := FloatToStr(AVarRec.VExtended^);
      vtString:     Result := AVarRec.VString^;
      vtPChar:      Result := AVarRec.VPChar;
      vtObject:     Result := AVarRec.VObject.ClassName;
      vtClass:      Result := AVarRec.VClass.ClassName;
      vtAnsiString: Result := string(AVarRec.VAnsiString);
      vtCurrency:   Result := CurrToStr(AVarRec.VCurrency^);
      vtVariant:    Result := string(AVarRec.VVariant^);
    else
      result := '';
    end;
  end;
Run Code Online (Sandbox Code Playgroud)

您可以将上面的两个函数组合到一个函数中,该函数将const数组中的所有元素转换为一个字符串:

function VarArrayToStr( AVarArray : array of const ) : string;
  var
    i : integer;
  begin
    result := '';
    for i := 0 to High(AVarArray) do
      result := result + VarRecToStr( AVarArray[i] );
  end;
Run Code Online (Sandbox Code Playgroud)

您现在可以创建自己的Format()函数.Format()函数扫描%,并用const数组中的值替换%something,具体取决于格式说明符和精度说明符.


Rob*_*edy 5

如您所知,array of constarray of TVarRec. 要构造一个,首先声明诸如数组,然后设置每个元素的值,就像设置任何其他数组一样。

TVarRec是一个变体记录,这意味着它可以保存许多不同类型的值。它有一个字段,VType,表示它所持有的值的类型。在其他字段中,一次只有一个具有有效值。设置VType字段,然后设置对应的值字段,如VIntegerVString

请注意,某些字段实际上是指针,例如VVariantVInt64。当您分配这些指针值时,您需要确保它们指向的任何内容在需要时都保持可访问和有效Format

其他字段是其真实值类型的无类型版本。这些包括VAnsiStringVInterface。当您分配给这些字段时,请注意它们不会像普通AnsiStringIUnknown变量那样维护通常的引用计数,因此再次注意这些变量的生命周期。

编译器通常是唯一生成此类数组的东西,因此几乎没有可用的参考代码来了解它们是如何构建的。相反,您可以查看使用 const 数组的其他代码。例如,几年前我为 JCL实现了一个 Unicode 感知Format函数。它使用有限状态机一次解析一个字符的格式字符串。每次解析完一个参数字符串时,它都会从输入数组中获取相应的参数,并根据字符串和参数类型对其进行格式化。

它使用最少的汇编程序,只是为了提高效率,而不是因为它确实是必要的。作为参考,所有汇编程序都在注释中附有等效的 Delphi 代码。


Sam*_*Sam 5

在https://groups.google.com/forum/#!topic/borland.public.delphi.objectpascal/-xb6O0qX2zc找到此代码

procedure test(numArgs:integer; MyFormattingString:string);    
var
  v:array of tvarrec;
  i:integer;
begin
  setlength(v, numArgs);
  for i:=1 to numArgs do
  begin
    v[i-1].vtype:=vtpchar;
    v[i-1].vtpchar:=strnew(pchar(myDataSet.FieldByName(inttostr(i)).asstring));
  end;
  memo1.lines.add(Format(MyFormattingString,v);
  for i:=1 to numArgs do strdispose(v[i-1].vtpchar);
end;
Run Code Online (Sandbox Code Playgroud)

没有回答我必须处理的所有问题,但我想我现在知道如何构建 TVarRec 数组。