我想在我程序中实现以下功能。用户输入字符串表达式如‘mysum(7,5) + mysum(6,3)’
其中mysum是我已经定义的一个求和函数,我如何才能求得整个字符串表达式的值呢?似乎要用到编译知识,哪位高手能给个源码最好了。

解决方案 »

  1.   

    将你这些函数放在dll里面.
    使用显示加载的方式.
    在GetProcAddress函数里面,可以将函数名以文本的方式传进去
      

  2.   

    主要是进行字符串处理,可以这样,假定str存放着那个字符串表达式‘mysum(7,5) + mysum(6,3)’
    那么
    function Calcular(str:string):integer;
    var
    ii,i:integer;
    ss,d,k:integer;
    begin
    ss:=0;
    if pos('mysum',str)=0 then
    begin  
    i:=pos('(',str);//查找左括号位置
    ii:=pos(',',str);//查找逗号位置
    d:=strtoint(copy(str,i+1,ii-i-1));//取得第一个参数
    i:=pos(')',str);//查找右括号位置
    k:=strtoint(copy(str,ii+1,i-ii-1));//取得第二个参数
    ss:=ss+mysum(d,k);
    delete(str,1,i);//从字符串把第一个函数删除掉,以便继续处理
    end;
    if pos('+',str)=0 then //判断后面的是不是加号,如果是再处理
      begin
      end;
    ...如此处理下去就可以了,当然我上面仅仅给你处理了下那个mysum函数,其它的你照着进行就可以了...
    end;  
      

  3.   

    TO suton 
    不太明白你的意思。能不能说得再详细点?TO hys_427 
    你的方法只能处理这个特定的表达式。而我要处理的表达式是用户随机输入的,而且函数也不止这一个啊,再者还可能函数嵌套。我需要一个完善解决的方法。各位请多多指教啊。
      

  4.   

    我觉得2楼的方案很不错,不过对于楼主的问题,我有如下解决方案:1、在用户输入的字符串中,读取各数字,运算符号,以及函数(比如mysum),保存在某位置
    2、调用函数,取得返回值,然后按照运算法则进行运算,求得结果。现在关键是如何在用户输入的字符串中找到这个mysum函数,并获得这个函数的变量。
      

  5.   

    有关表达式求值有多个解决方案:
    1:只是求值的可用Colin Wilson 的 TExpressionEvaluator,那个可以计算一般表达式的值,但不能定义函数
    2:可自定义函数的,可用RxLib的TRxCalculator,它可定义函数,但功能一般
    3:可直接运行VBScript/JAVAScript的MicroSoft Script Control,它可以直接在delphi中安装,并能在delphi中运行VBScript/JAVAScript。
    你的实现:
       ScriptControl1.Language:='JavaScript';
      ScriptControl1.ExecuteStatement('x=10;y=100');
      ScriptControl1.ExecuteStatement('function mysum(a,b) { return a+b; }');
      ShowMessage(ScriptControl1.Eval('mysum(7,5) + mysum(6,3)'));
    4.pascal_interpreter:支持简单的Pascal Scrip,可在用户界面编译运行pascal脚本
    5.更强大的可使用RemObjects Pascal Script,它支持强大的pascal脚本(inno setup就用它)
      

  6.   

    TO wyxcode 
    我没太明白2楼的意思,你明白吗?
    你的思路和hys_427相似,可以通过字符串比较判断是否是函数名,然后调用相应函数求值。不过这种方法似乎不够科学,也不知道能不能处理所有情况。
      

  7.   

    TO keiy
    果然高手。
    1是不行的
    2我没试过,你说功能一般,估计不能满足我的要求。
    3我听说过,没用过,不知道处理复杂函数好用不好用,再就是如果里面有变量怎么处理?变量可能来自于程序的其他部分。
    4、5 我就不知道了,得研究研究了。
    希望这里面有满足需要的方案。
    谢谢啊。希望高手们能给出更多更好的解决方案。讨论出一个既简单又完善的结果来。
      

  8.   

    我还是推荐MicroSoft Script Control的方法,更明白的例子:
    procedure TForm1.FormActivate(Sender: TObject);
    begin
    ScriptControl1.Language:='JavaScript';
    ScriptControl1.ExecuteStatement('function mysum(a,b) { return a+b; }');
    //你还可以定义更多的函数
    end;procedure TForm1.Button1Click(Sender: TObject);
    begin
    Edit2.Text:= ScriptControl1.Eval(Edit1.Text);
    end;你在Edit1中写mysum(7,5) + mysum(6,3),按Button1,Edit2就为21
    当然,你可以在Edit1中写任何符合JAVAScript的表达式,都可以,如:
    x=1;y=2;x+100*y 结果为201
    你甚至可以在edit1中写自己的函数,如
    function test(x,y) { return x-y; } ; test(100,2)
    结果为98
    再写test(1,2)
    结果为-1
    当然,你可以将计算写在程序中,如:
    procedure TForm1.Button2Click(Sender: TObject);
    var
    s:string;
    begin
    s:='mysum(7,5) + mysum(6,3)';
    Edit2.Text:= ScriptControl1.Eval(s);
    end;结果为21;
      

  9.   

    不知道处理复杂函数好用不好用
    :----->
    JAVAScript是一门语言,任何复杂的函数基本都能处理,何况它自己有一套函数
    ---------------------------
    再就是如果里面有变量怎么处理?变量可能来自于程序的其他部分
    :--->
    当然可以,就按上面的例子:
    rocedure TForm1.Button2Click(Sender: TObject);
    var
      x1,y1:integer;
      x2,y2:integer;
      s:string;
    begin
    x1:=7;
    y1:=5;
    x2:=6;
    y2:=3;
    s:=format('mysum(%d,%d) + mysum(%d,%d)',[x1,y1,x2,y2]);
    Edit2.Text:= ScriptControl1.Eval(s);
    end;
      

  10.   

    试了以下,估计MicroSoft Script Control不行,处理不了表达式里有delphi的数据类型的情况。
      

  11.   

    嗯。问题的目的,好果是作为一个课题,深入研究下去,很好,很艰辛;如果只是为了解决当前具体的需求,那还是建议楼主选用解释型的语言,例如VB/VBScript、VFP、JavaScript之类的。至少,要象楼上那样,在Delphi程序里创建这些对象----实际上还是使用了这些语言。Delphi不是万能工具,把它当做解决一切问题的利器,首先就是方向的错误。
    遇到问题,首先要根据问题选择顺手的工具。
    再比如,要做一个动画,还是Flash方便;要处理一幅图,可以用PhotoShop。
      

  12.   

    比如ScriptControl1.ExecuteStatement('function mysum(a,b) { return a+b; }'); 
    函数作为一个字符串传给ScriptControl,可是字符串长度有限,函数体很长怎么处理?我试了,ScriptControl1.ExecuteStatement('function mysum(a,b)');
           ScriptControl1.ExecuteStatement('{ return a+b; }'); 
    这样写执行会出错啊。
      

  13.   


    如果都是基本类型,MicroSoft Script Control可以处理,如double,你也可转成string传给MSC
    但如果是复杂类型,你要将它传给MSC,就比较繁了(但不是不能处理)
    如果楼主一定要一个符合PASCAL的角本,那可以好好研究下RemObjects Pascal Script,如果用过inno setup
    就可以知道它的强大功能了
      

  14.   

    TO lihuasoft 
    我要实现的这个功能是一个程序的一部分,所以就局限在delphi的开发工具上了。
    我也只想能解决当前的需求就好,可是这个需求比我在题目中说的复杂,我在“地基”那里只是举了个例子。
    实际上字符串表达式里包括自定义函数,函数参数可能是指针或者记录类型也可能是个全局变量,这样一个综合的表达式求值问题才是我要解决的。
    还请多多指教。
      

  15.   

    给你个我早些时候写的东西,献丑了{******************************************************************************}
    { @UnitName     : uStack.pas                                                   }
    { @Project      : Common                                                       }
    { @Copyright    : Budded Software Studio                                       }
    { @Author       : Budded                                                       }
    { @Description  :                                                  }
    { @FileVersion  : 1.0.0.0                                                      }
    { @CreateDate   : 2005-03-01                                                   }
    { @Comment      :                                                              }
    { @LastUpdate   : Budded, 2005-03-01                                           }
    { @History      : Created By Budded, 2005-03-01 11:00                          }
    {******************************************************************************}
    unit uStack;interfaceuses
      Classes, Variants;type
      TArrayVariant = array of Variant;  TStack = class
      private
        FList: TArrayVariant;
        function GetCount: Integer;
      public
        constructor Create; 
        destructor Destroy; override;    property Count: Integer read GetCount;
        function Push(const Value: Variant): Boolean;
        function Peek: Variant;
        function Pop: Variant;
      end;
    implementationuses SysUtils;{ TStack }const
      CONST_ERROR_NODATA = 'Error: There''s no data in the Stack!';constructor TStack.Create;
    begin
      SetLength(FList, 0);
    end;destructor TStack.Destroy;
    begin
      SetLength(FList, 0);  inherited;
    end;function TStack.GetCount: Integer;
    begin
      Result := Length(FList);
    end;function TStack.Peek: Variant;
    begin
      if Count > 0 then
        Result := FList[Count - 1]
      else raise Exception.Create(CONST_ERROR_NODATA);
    end;function TStack.Pop: Variant;
    begin
      if Count > 0 then
      begin
        Result := FList[Count - 1];
        SetLength(FList, Count - 1);
      end
      else raise Exception.Create(CONST_ERROR_NODATA);
    end;function TStack.Push(const Value: Variant): Boolean;
    begin
      Result := True;
      try
        SetLength(FList, Count + 1);
        FList[Count - 1] := Value;
      except    // wrap up
        Result := False;
      end;      // try / except
    end;end.
      

  16.   

    继续{******************************************************************************}
    { @UnitName     : uCalculator.pas                                              }
    { @Project      : Common                                                       }
    { @Copyright    : Budded Software Studio                                       }
    { @Author       : Budded                                                       }
    { @Description  : 算术表达式解析器                                 }
    { @FileVersion  : 1.0.0.0                                                      }
    { @CreateDate   : 2005-03-01                                                   }
    { @Comment     : 表达式自左向右解析,遵循左结合法则                            }
    { @LastUpdate   : Budded, 2005-03-01                                           }
    { @History      : Created By Budded, 2005-03-01 11:00                          }
    {******************************************************************************}
    unit uCalculator;interfaceuses
      SysUtils, Classes, Types, uStack;type
      // 参数类型
      TParam = record
        Param: String;                                              // 参数
        Value: Double;                                              // 参数值
      end;
      TParamArray = array of TParam;                                // 参数列表类型  // 计算数据类型:None, 操作符,操作数,参数
      TCalcState = (csNone, csOperator, csNumber, csParam);         //  // 操作符类型
      TOperator = (
        oPower, oMulitiple, oDevide, oMod, oAdd, oSub,              // 数学算子
        oABS, oPow, oSqr, oSqt, oLog, oLn, oLdexp, oFact,                 //
        oSin, oCos, oTan, oCot,                                     // 三角函数
        oGreater, oLess, oNoGreater, oNoLess, oEqual, oUnEqual,     // 关系算子
        oAnd, oOr, oNot,                                            // 逻辑算子
        oComma, oBracketL, oBracketR);  // 操作符类型
      TOperatorRight = record
        Operator: Char;                                             // 操作符
        Rights: Byte;                                               // 运算优先级
        Pseudocode: String[5];                                      // 伪代码
        OperandCount: Byte;                                         // 操作数个数
      end;  TCalculator = class(TObject)
      private
        FStackOperators: TStack;                                    // 操作符堆栈
        FStackNumbers: TStack;                                      // 操作数堆栈    FCalcState: TCalcState;                                     // 当前操作数类型
        FCalcString: String;                                        // 当前操作数零时变量    FParamArray: TParamArray;                                   // 参数列表
        FCalcExpression: String;
        procedure SetCalcExpression(const Value: String);
        function GetOperatorType(const AChar: Char): TOperator;
      protected          
        procedure DoCalc;                                           // 双目计算
        procedure ParseChar(const AChar: Char);                     // 解析表达式中字符    function PushOperator(const AOperator: TOperator): Boolean; // 操作符入栈
        function PushNumber(const ANumber: Double): Boolean;        // 操作数入栈
        function PushParam(const AParam: String): Boolean;          // 变量入栈    function PopOperator: TOperator;                            // 操作符出栈
        function PopNumber: Double;                                 // 操作数出栈    function PeekOperator: TOperator;                           // 查看操作符
      public
        constructor Create;
        destructor Destroy; override;    // 计算表达式
        property CalcExpression: String read FCalcExpression write SetCalcExpression;
        function Calc: Double; overload;
        function CalcBool: Boolean; overload;
        function Calc(const Expression: String): Double; overload;
        function CalcBool(const Expression: String): Boolean; overload;    // 添加参数
        procedure AddParam(const Param: String; const Value: Double);
        procedure ClearParam;
      end;
    implementationuses
      Math;{ TCalculator }const
      CONST_EPSILON = 1e-10;  SetOfNumber: Set of Char = ['0'..'9', '.'];              // 操作数集合  Operators: array[TOperator]of TOperatorRight =           // 操作符表
        (
        // 数学运算符
         (Operator: '^'; Rights: 20; Pseudocode: ''; OperandCount: 2),              // 乘方
         (Operator: '*'; Rights: 30; Pseudocode: ''; OperandCount: 2),              // 乘
         (Operator: '/'; Rights: 30; Pseudocode: 'Div'; OperandCount: 2),           // 除
         (Operator: '%'; Rights: 30; Pseudocode: 'Mod'; OperandCount: 2),           // 取模
         (Operator: '+'; Rights: 40; Pseudocode: 'Plus'; OperandCount: 2),          // 加
         (Operator: '-'; Rights: 40; Pseudocode: 'Sub'; OperandCount: 2),           // 减    // 扩展数学运算符 Operator预留段:#180--#255
         (Operator: #180; Rights: 10; Pseudocode: 'ABS'; OperandCount: 1),          // ABS(X)
         (Operator: #181; Rights: 10; Pseudocode: 'Pow'; OperandCount: 2),          // Pow(X, Y)
         (Operator: #182; Rights: 10; Pseudocode: 'Sqr'; OperandCount: 1),          // Sqr(X)
         (Operator: #183; Rights: 10; Pseudocode: 'Sqt'; OperandCount: 1),          // Sqrt(X)
         (Operator: #184; Rights: 10; Pseudocode: 'Log'; OperandCount: 2),          // Log(Base, Exp)
         (Operator: #185; Rights: 10; Pseudocode: 'Ln'; OperandCount: 1),           // Ln(X)
         (Operator: #186; Rights: 10; Pseudocode: 'Ldexp'; OperandCount: 1),        // Ldexp
         (Operator: #187; Rights: 10; Pseudocode: 'Fact'; OperandCount: 1),         // Factorial    // 三角函数 预留段:#150--#179
         (Operator: #150; Rights: 10; Pseudocode: 'Sin'; OperandCount: 1),          // Sin
         (Operator: #151; Rights: 10; Pseudocode: 'Cos'; OperandCount: 1),          // Cos
         (Operator: #152; Rights: 10; Pseudocode: 'Tan'; OperandCount: 1),          // Tan
         (Operator: #153; Rights: 10; Pseudocode: 'Cot'; OperandCount: 1),          // Cotan    // 关系运算符 预留段:#128--#149
         (Operator: '>'; Rights: 50; Pseudocode: ''; OperandCount: 2),              // 大于
         (Operator: '<'; Rights: 50; Pseudocode: ''; OperandCount: 2),              // 小于
         (Operator: #128; Rights: 50; Pseudocode: '<='; OperandCount: 2),           // 不大于
         (Operator: #129; Rights: 50; Pseudocode: '>='; OperandCount: 2),           // 不小于
         (Operator: '='; Rights: 60; Pseudocode: ''; OperandCount: 2),              // 等于
         (Operator: #130; Rights: 60; Pseudocode: '<>'; OperandCount: 2),           // 不等于    // 逻辑运算符
         (Operator: '&'; Rights: 87; Pseudocode: 'and'; OperandCount: 2),           // And
         (Operator: '|'; Rights: 88; Pseudocode: 'or'; OperandCount: 2),            // or
         (Operator: '!'; Rights: 15; Pseudocode: 'not'; OperandCount: 1),           // not, 单目操作符    // 其它运算符
         (Operator: ','; Rights: 99; Pseudocode: ''; OperandCount: 0),              // 逗号
         (Operator: '('; Rights: 0; Pseudocode: ''; OperandCount: 0),               // 左括号
         (Operator: ')'; Rights: 100; Pseudocode: ''; OperandCount: 0)              // 右括号
        );
    procedure TCalculator.AddParam(const Param: String; const Value: Double);
    var
      Len: Integer;
    begin
      if Length(Param) > 0 then
      begin
        Len := Length(FParamArray);
        SetLength(FParamArray, Len + 1);    FParamArray[Len].Param := Param;
        FParamArray[Len].Value := Value;
      end;
    end;function TCalculator.Calc: Double;
    var
      iLoop: Integer;
    begin
      Result := 0.00;
      FStackOperators := TStack.Create;
      FStackNumbers := TStack.Create;
      try
        FCalcState := csNone;
        for iLoop := 1 to Length(CalcExpression) do    // Iterate
          ParseChar(CalcExpression[iLoop]);    ParseChar(Operators[oComma].Operator);    while FStackOperators.Count > 0 do             // 计算剩余
          DoCalc;    if FStackNumbers.Count = 1 then
          Result := PopNumber;                         // 从栈中获取计算结果    if IsZero(Result, CONST_EPSILON) then
          Result := 0.00;
      finally   // wrap up
        FStackOperators.Free;
        FStackNumbers.Free;
      end;      // try / finally
    end;
      

  17.   

    看来只能寄希望于RemObjects Pascal Script了,我去找个来看看。
      

  18.   

    function TCalculator.Calc(const Expression: String): Double;
    begin
      CalcExpression := Expression;
      Result := Calc;
    end;function TCalculator.CalcBool: Boolean;
    var
      FR: Double;
    begin
      FR := Calc;
      Result := not IsZero(FR, CONST_EPSILON);
    end;function TCalculator.CalcBool(const Expression: String): Boolean;
    var
      FR: Double;
    begin
      FR := Calc(Expression);
      Result := not IsZero(FR, CONST_EPSILON);
    end;procedure TCalculator.ClearParam;
    begin
      SetLength(FParamArray, 0);
    end;constructor TCalculator.Create;
    begin
      ClearParam;
      AddParam('INF', Infinity);
      AddParam('PI', PI);
    end;destructor TCalculator.Destroy;
    begin
      ClearParam;  inherited;
    end;procedure TCalculator.DoCalc;  function CalcSingle(const AOperator: TOperator): Double;         // 单目操作符
      var
        iLoop: Integer;
        Base: Double;
      begin
        Result := 0.00;
        Base := PopNumber;    case AOperator of  // case
          oNot:
            Result := IfThen(IsZero(Base, CONST_EPSILON), 1, 0);         //      oABS:
            Result := Abs(Base);
          oSqr:
            Result := Sqr(Base);
          oSqt:
            Result := Sqrt(Abs(Base));
          oLn:
            Result := Ln(Base);
          oFact:
            begin
              Result := Round(Base);
              for iLoop := Round(Base) - 1 downto 1 do
              try
                Result := Result * iLoop;
              except
                Result := Infinity;
              end;
            end;
          oSin:
            Result := Sin(Base);
          oCos:
            Result := Cos(Base);
          oTan:
            Result := Tan(Base);
          oCot:
            Result := Cot(Base);
        end;       // end case
      end;
      function CalcDouble(const AOperator: TOperator): Double;         // 双目操作符
      var
        Base, Exponent: Double;
      begin
        Result := 0.00;    Exponent := PopNumber;
        Base := PopNumber;    case AOperator of    // case
          oPower, oPow:
            Result := Power(Base, Exponent);
          oMulitiple:
            Result := Base * Exponent;
          oDevide:
            if SameValue(Exponent, 0) then
              Result := Infinity
            else Result := Base / Exponent;
          oMod:
            if SameValue(Round(Exponent), 0) then
              Result := Infinity
            else Result := Round(Base) mod Round(Exponent);
          oAdd:
            Result := Base + Exponent;
          oSub:
            Result := Base - Exponent;
          oLog:
            Result := LogN(Base, Exponent);
          oLdexp:
            Result := Ldexp(Base, Round(Exponent));      oGreater:
            Result := IfThen(Base > Exponent, 1, 0);
          oLess:
            Result := IfThen(Base < Exponent, 1, 0);
          oNoGreater:
            Result := IfThen(Base <= Exponent, 1, 0);
          oNoLess:
            Result := IfThen(Base >= Exponent, 1, 0);
          oEqual:
            Result := IfThen((Base = Exponent) or SameValue(Base, Exponent, CONST_EPSILON), 1, 0);
          oUnEqual:
            Result := IfThen((Base = Exponent) or SameValue(Base, Exponent, CONST_EPSILON), 0, 1);      oAnd:
            Result := IfThen((Base > CONST_EPSILON) and (Exponent > CONST_EPSILON), 1, 0);
          oOr:
            Result := IfThen((Base > CONST_EPSILON) or (Exponent > CONST_EPSILON), 1, 0);
        end;
      end;var
      Operator: TOperator;
      FCalcResult: Double;
    begin
      Operator := PopOperator;
      if not (Operator in [oBracketL, oBracketR]) then
      begin
        case Operators[Operator].OperandCount of    // case
          1: FCalcResult := CalcSingle(Operator);
          2: FCalcResult := CalcDouble(Operator);
        else FCalcResult := 0.00;       // case else
        end;         // end case    PushNumber(FCalcResult);           // 计算结果入栈
      end;
    end;function TCalculator.GetOperatorType(const AChar: Char): TOperator;
    var
      iLoop: TOperator;
    begin
      Result := TOperator(-1);
      for iLoop := Low(TOperator) to High(TOperator) do    // Iterate
        if AChar = Operators[iLoop].Operator then
        begin
          Result := iLoop;
          Break;
        end;
    end;procedure TCalculator.ParseChar(const AChar: Char);  function GetCalcCharState(const AChar: Char): TCalcState;
      begin
        Result := csParam;
        if AChar in SetOfNumber then
          Result := csNumber
        else if GetOperatorType(AChar) in [Low(TOperator)..High(TOperator)] then
               Result := csOperator;
      end;
    var
      CalcCharState: TCalcState;
      TempDouble: Double;
    begin
      CalcCharState := GetCalcCharState(AChar);
      try
        case CalcCharState of  // case
          csNumber, csParam:
            FCalcString := FCalcString + AChar;
          csOperator:
            begin
              case FCalcState of    // case
                csNumber:
                  if TryStrToFloat(FCalcString, TempDouble) then
                    PushNumber(TempDouble)
                  else raise Exception.Create('Invalid Number Input!');
                csParam:
                  if not PushParam(FCalcString) then
                    raise Exception.Create('Invalid Parameter Input!');
              end;         // end case          FCalcString := '';
              if not PushOperator(GetOperatorType(AChar)) then
                raise Exception.Create('Invalid Operator Input!');
            end;
        end;       // end case
      finally
        FCalcState := CalcCharState;  // 保存当前字符类型
      end;
    end;function TCalculator.PeekOperator: TOperator;
    begin
      Result := TOperator(FStackOperators.Peek);
    end;function TCalculator.PopNumber: Double;
    begin
      Result := Double(FStackNumbers.Pop);
    end;function TCalculator.PopOperator: TOperator;
    begin
      Result := TOperator(FStackOperators.Pop);
    end;function TCalculator.PushNumber(const ANumber: Double): Boolean;
    begin
      Result := FStackNumbers.Push(ANumber);
    end;function TCalculator.PushOperator(const AOperator: TOperator): Boolean;  function OperatorCanPush: Boolean;
      var
        oOperator: TOperator;
      begin
        Result := True;
        if FStackOperators.Count > 0 then
        begin
          oOperator := PeekOperator;                            // 得到栈顶操作符
          Result := (oOperator = oBracketL) or
            (Operators[AOperator].Rights < Operators[oOperator].Rights);
        end;
      end;begin
      Result := True;
      if AOperator <> oComma then
      begin
        { 判断入栈操作符与栈顶操作符优先级 }
        while not OperatorCanPush do
          DoCalc;    if AOperator <> oBracketR then
          Result := FStackOperators.Push(AOperator)
        else begin
               PopOperator;
               Result := True;
             end;
      end;
    end;
      

  19.   

    还有个尾巴function TCalculator.PushParam(const AParam: String): Boolean;
    var
      iLoop: Integer;
    begin
      Result := False;
      for iLoop := Low(FParamArray) to High(FParamArray) do    // Iterate
      begin
        // SameText is not Case Sensitive
        if SameText(FParamArray[iLoop].Param, AParam) then
        begin
          Result := PushNumber(FParamArray[iLoop].Value);
          Break;
        end;
      end;    // end for
    end;procedure TCalculator.SetCalcExpression(const Value: String);  function StringReplaceEx(const S, OldPattern, NewPattern: string;
        Flags: TReplaceFlags): string;
      var
        SearchStr, Patt, NewStr: string;
        Offset: Integer;
      begin
        if rfIgnoreCase in Flags then
        begin
          SearchStr := UpperCase(S);
          Patt := UpperCase(OldPattern);
        end else
        begin
          SearchStr := S;
          Patt := OldPattern;
        end;
        NewStr := S;
        Result := '';
        while SearchStr <> '' do
        begin
          Offset := Pos(Patt, SearchStr);
          if Offset = 0 then
          begin
            Result := Result + NewStr;
            Break;
          end;
          Result := Result + Copy(NewStr, 1, Offset - 1) + NewPattern;
          NewStr := Copy(NewStr, Offset + Length(OldPattern), MaxInt);
          if not (rfReplaceAll in Flags) then
          begin
            Result := Result + NewStr;
            Break;
          end;
          SearchStr := Copy(SearchStr, Offset + Length(Patt), MaxInt);
        end;
      end;var
      iLoop: TOperator;
      PseudoCode: String;
      Operator: String;
      RFlag: TReplaceFlags;
    begin
      FCalcExpression := StringReplaceEx(Value, ' ', '', [rfReplaceAll]);  // 替换伪代码
      RFlag := [rfReplaceAll, rfIgnoreCase];
      for iLoop := Low(TOperator) to High(TOperator) do
      begin
        PseudoCode := Trim(Operators[iLoop].Pseudocode);
        if Length(PseudoCode) <> 0 then
        begin
          Operator := Operators[iLoop].Operator;
          FCalcExpression := StringReplaceEx(FCalcExpression, Pseudocode, Operator, RFlag);
        end;
      end;  
    end;end.
      

  20.   

    TO budded 
    这么工整的代码啊,我一定得好好看看。谢谢了。
      

  21.   


    {首先向楼上各位无私奉献的朋友学习了然后我也写了一段, 只是提供一个思路, 通用性极不强, 楼主可以无视而过}unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;type
      TForm1 = class(TForm)
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }    procedure Test(Str: string);  published    function MyFunc1(A, B: integer): integer;
        function MyFunc2(A, B: integer): integer;  end;var
      Form1: TForm1;implementation{$R *.dfm}{ TForm1 }function TForm1.MyFunc1(A, B: integer): integer;
    begin
      Result := A + B;
    end;function TForm1.MyFunc2(A, B: integer): integer;
    begin
      Result := A * B;
    end;procedure TForm1.Test(Str: string);
    var
      I, J: integer;
      FuncName: string;
      Var1, Var2: integer;
      SS: TStringList;
      pFunc: Pointer;
      Rst: integer;
    begin
      Str := StringReplace(Str, #32, '', [rfReplaceAll]);
      FuncName := Copy(Str, 1, Pos('(', Str)-1);
      SS := TStringList.Create;
      I := Pos('(', Str);
      J := Pos(')', Str);
      SS.Text := StringReplace(Copy(Str, I+1, J-I-1), ',', #10, [rfReplaceAll]);
      try
        Var1 := StrtoInt(SS[0]);
      except
        Var1 := PInteger(Self.FieldAddress(SS[0]))^;
      end;
      try
        Var2 := StrtoInt(SS[1]);
      except
        Var2 := PInteger(Self.FieldAddress(SS[1]))^;
      end;
      pFunc := Self.MethodAddress(FuncName);
      asm
        mov eax, Self
        mov edx, Var1
        mov ecx, Var2
        call [pFunc]
        mov Rst, eax
      end;
      Showmessage(InttoStr(Rst));
      SS.Free;
    end;procedure TForm1.Button1Click(Sender: TObject);
    begin
      Test('MyFunc1(55,44)');
      Test('MyFunc2(3,5)');
    end;end.
      

  22.   

    PS:上面我的想法,还未弄完。比如,尽管加了判断Var是常数或类成员变量的检测,但尚未弄。暂时不想弄了。  ^_^
      

  23.   


    那段汇编以及它前面一句 的作用是:寻到Func地址,然后将参数传入寄存器,并调用这个Func,返回值放入Rst。
    如果有多个参数(不固定),可以通过计算,多余参数压栈处理----这个倒不是难关。现在问题有一个最大的难关是:前面的实现方法(包括我的),貌似都不能实现变量的处理。这是最大的难关。因为Delphi程序编译后,普通变量名字已不复存在,通过名字又何处去寻?即使象Func那样,可以利用RTTI,但普通变量做不到,至少需要成员变量是类类型的,或者接口类型的----但你要的是普通变量。
      

  24.   

    续楼上:如果沿着我的思路发展,有一种解决难关的办法:Form.Create时,把所有全局变量的名字和内存地址记录下来,比如记录到一个TStringList。然后,在解释字符串时,如果函数参数不为数字,就去这里面找“变量”。关于指针,可以在字串中以[X]的形式表示。
      

  25.   

    TO lihuasoft
    不太明白你的意思。处理这个问题不涉及到编译后的问题吧?
    有变量的话也是在编译前就确定好的了,怎么涉及到编译后按变量名寻址呢?
      

  26.   


    1、你的程序如果用Delphi写,总是要编译后才能运行2、你的需求是:要在编译后运行过程中找源程序代码中的“变量”并让它参与运算3、Delphi程序编译后,在Pascal源代码中声明的变量名字(如var X:integer中的X),在可执行程序中已经不存在了,编译器直接把它们处理为地址。4、也正是因为如此,在无数层楼之前,我就建议你全部采用解释型的编程语言。解释型语言有真正意义上的宏替换可供你使用。宏替换
      

  27.   

    楼主可以去看FastReport的代码,里面有这个解释方面的
      

  28.   

    TO lihuasoft
    呵呵,是啊,忘了你说的这个第二条了。的确是编译后的寻址问题。
      

  29.   

    RemObject Pascal Script.
      

  30.   

    我正在看RemObject Pascal Script. 
    有进展了会告诉大家。
      

  31.   

    将23楼代码重新改进了一下,发贴在:http://topic.csdn.net/u/20080923/19/daae97fa-1fbc-475a-a998-ada94ee23e82.html因这种思路明显不适用于扩展,所以新发贴。只供楼主参考。
      

  32.   

    我试了试RemObject Pascal Script. 感觉这是个功能比较全面的工具。
    可以实现变量的传递,记录类型的支持,可惜不支持指针。使用RemObject Pascal Script,字符串表达式不用自己分析,所以代码写起来也比较容易。我准备采用这种方式了。积极讨论的我都想给分,可惜分数不多,大家多担待吧。