我如何构建一个const数组?

时间:2013-10-23 03:25:45

标签: 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;

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

3 个答案:

答案 0 :(得分: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);

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;

函数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;

您可以将上述两个函数组合到一个函数中,该函数将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;

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

答案 1 :(得分:4)

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

TVarRec是一个变体记录,这意味着它可以包含许多不同类型的值。它有一个字段VType,用于指示它所包含的值的类型。在其他字段中,一次只有一个具有有效值。设置VType字段,然后设置相应的值字段,例如VIntegerVString

请注意,某些字段确实是指针,例如VVariantVInt64。当您指定这些指针值时,您需要确保只要Format需要它们,它们指向的任何内容仍然可访问且有效。

其他字段是其实际值类型的无类型版本。其中包括VAnsiStringVInterface。当您指定这些字段时,请注意它们不会保持普通AnsiStringIUnknown变量的常用引用计数,因此请再次观察这些变量的生命周期。

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

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

答案 2 :(得分:2)

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;

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