很久以前(如果我没记错的话是在2005年),有一个SIG对各种表达式解析器进行了比较。结果在以下链接中:
http://www.mindspring.com/~rbwinston/ParserTestFiles.zip
其中包括Renate Schaaf的经典Turbo Pascal。
一般来说,速度更快的生成本地代码,但是不可移植,并且可能需要修复DEP等问题。
自己编写基本的编译器并不难,在许多编程课程中是标准任务。我使用FPC / Delphi编写了一个(现在作为“Symbolic”包含在freepascal分发中),后来将其转换为Java(作为Java字符串处理练习。有时我仍然会在夜晚惊醒)。
它的SVN位置是
http://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/packages/symbolic/
自己留个记号:我还有一些未完成的代码需要添加用户定义函数和布尔运算。总有一天要完成它 :-)
您正在寻找一种可以评估表达式的工具。
由于Delphi是一种编译语言,它没有内置支持。
但是,有外部工具可以帮助您完成这项任务。
例如:来自RemObjects的免费Pascal脚本引擎可以满足您的需求。
--jeroen
TEvaluator
答案投了赞成票(: - Jeroen Wiert Pluimers不可能,除非解析字符串。你如何将未知数x转换为浮点数?
你可以使用我的单元,它还很基础,但我还在编写中,目前它可以处理基本的BODMAS,但完成后我会发布整个单元。
Unit BODMAS;
Interface
Uses
System.SysUtils,
Math;
{
!!!!!!!!!!!!!!!!!!!!!! GLOBAL DEFINITIONS !!!!!!!!!!!!!!!!!!!!
EXPR = EXPRESSION
CURRENTPOS = POSSITION OF THE CURRENT OPPERATOR OF WHICH MATH IS BEING PERFORMED
}
Function EvalFunction(Expr: String): String;
Implementation
Function PrevOppPos(Expr: String; CurrentPos: Integer): Integer; // GETS THE PREVIOUS OPPERATOR
Var
I: Integer;
bSet: Boolean;
Begin
// THEORY
// KEEP MOVING POSITIONS DOWN FROM I ... ( MEANING < WAY IN EXPR)
// UNTIL AN OPPERATOR IS FOUND. IF NO OPPERATOR IS FOUND THE RESULT
// WILL BE THE BEGINING OF THE EXPRESSION
I := CurrentPos - 1;
bSet := False;
While ((I <= CurrentPos) AND (I >= 1)) OR (bSet = False) Do
Begin
// CHECK IF THE CHACHARACTER OF POSITION I IN EXPR IS AN OPPERATOR
// "." AND "," IS NOT AN OPPERATOR!!
If Expr[I] In ['(', ')', '+', '-', 'x', '/'] Then
Begin
Result := I;
bSet := True;
Dec(I); // Dec 1 more time to break loop
End;
Dec(I);
If (I = 0) AND (NOT(bSet)) Then
Begin
Result := 1;
bSet := True;
End;
End;
End;
Function NextOppPos(Expr: String; CurrentPos: Integer): Integer;
Var
I: Integer;
bSet: Boolean;
Begin
// THEORY
// KEEP MOVING POSITIONS UP FROM I ... ( MEANING > WAY IN EXPR)
// UNTIL AN OPPERATOR IS FOUND. IF NO OPPERATOR IS FOUND THE RESULT
// WILL BE THE LENGHT OF THE EXPRESSION
I := CurrentPos + 1;
bSet := False;
While ((I <= Length(Expr)) AND (I >= CurrentPos)) OR (bSet = False) Do
Begin
// CHECK IF THE CHACHARACTER OF POSITION I IN EXPR IS AN OPPERATOR
// "." AND "," IS NOT AN OPPERATOR!!
If Expr[I] In ['(', ')', '+', '-', 'x', '/'] Then
Begin
Result := I;
bSet := True;
Inc(I); // Inc 1 more time to break loop
End;
Inc(I);
If (I = Length(Expr) + 1) AND (NOT(bSet)) Then
Begin
Result := Length(Expr);
bSet := True;
End;
End;
End;
// EVALUATE BRACKET EXPRESSION
Function EvalBracetExpr(Expr: String): String;
Var
OppCount, I: Integer;
Ans: String;
NewExpr: String;
nOpp, pOpp, OppPos: Integer;
nExpr, pExpr: String;
Begin
Ans := '';
// EVALUATE EXPRESSION
// ALL MULTIPLICATION IN BRACKETS
While Pos('x', Expr) <> 0 Do
Begin
OppPos := Pos('x', Expr); // Opperator Position
nOpp := NextOppPos(Expr, OppPos); // Next Opperator Position
pOpp := PrevOppPos(Expr, OppPos); // Previous Opperator Position
// COPY FROM THE OPPERATOR POS TO THE LENGTH OF THE EXPRESSION - THE POSITION OF THE NEXT EXPRESSION
// When Next opperator is the length of the expression
If nOpp = Length(Expr) Then
nExpr := Copy(Expr, OppPos + 1, Length(Expr) - (Length(Expr) - 1))
Else
nExpr := Copy(Expr, OppPos + 1, Length(Expr) - nOpp);
// COPY FROM THE PREVIOUS OPPERATOR POS TO THE OPPERATOR POSITION -1
pExpr := Copy(Expr, pOpp + 1, (OppPos - 1) - pOpp);
Delete(Expr, pOpp, nOpp);
Ans := Ans + FloatToStr(StrToFloat(pExpr) * StrToFloat(nExpr));
End;
// ALL ADDITION IN BRACKETS
While Pos('+', Expr) <> 0 Do
Begin
OppPos := Pos('+', Expr); // Opperator Position
nOpp := NextOppPos(Expr, OppPos); // Next Opperator Position
pOpp := PrevOppPos(Expr, OppPos); // Previous Opperator Position
// COPY FROM THE OPPERATOR POS TO THE LENGTH OF THE EXPRESSION - THE POSITION OF THE NEXT EXPRESSION
// When Next opperator is the length of the expression
If nOpp = Length(Expr) Then
nExpr := Copy(Expr, OppPos + 1, Length(Expr) - (Length(Expr) - 1))
Else
nExpr := Copy(Expr, OppPos + 1, Length(Expr) - nOpp - 1);
// COPY FROM THE PREVIOUS OPPERATOR POS TO THE OPPERATOR POSITION -1
pExpr := Copy(Expr, pOpp + 1, (OppPos - 1) - pOpp);
Delete(Expr, pOpp, nOpp);
Ans := Ans + FloatToStr(StrToFloat(pExpr) + StrToFloat(nExpr));
End;
Result := Ans;
End;
// EVALUTE ADDITION EXPRESSION
Function EvalAddExpr(Expr: String): String;
Var
Expr1, Expr2: String;
Begin
Expr1 := Copy(Expr, 1, Pos('+', Expr) - 1);
Expr2 := Copy(Expr, Pos('+', Expr) + 1, Length(Expr));
Result := FloatToStr(StrToFloat(Expr1) + StrToFloat(Expr2));
End;
Function EvalFunction(Expr: String): String;
Var
bOPos, bCPos: Integer; // bracket Open/Closed Position
sExpr: String;
FinalExpr: String;
OppPos: Integer;
PrevOpp, NextOpp: Integer;
Begin
While Pos('(', Expr) <> 0 Do
Begin
// Find first open bracket
bOPos := Pos('(', Expr);
// Find first closed bracket
bCPos := Pos(')', Expr);
// Get the expression between the 2 brackets
sExpr := Copy(Expr, bOPos, bCPos);
// Remove sExpr from the Expression
Delete(Expr, bOPos, bCPos + 1 - bOPos);
// Concatenate the expression of what was before the bracket and that after the bracket, as well as the result in the middle
FinalExpr := Copy(Expr, 1, bOPos - 1) + EvalBracetExpr(sExpr) + Copy(Expr, bOPos, Length(Expr));
// Return the result
Expr := FinalExpr;
End;
While Pos('+', Expr) <> 0 Do
Begin
// 1) Find the first + opperator in expression
OppPos := Pos('+', Expr);
// 2) find first part of expression
PrevOpp := PrevOppPos(Expr, OppPos);
// 3) find the next part of the expression
NextOpp := NextOppPos(Expr, OppPos);
// 4) get the full expression between the opperators
//
// if prev opp <> 1 then
// move indicator 1 pos ahead
If PrevOpp <> 1 Then
Inc(PrevOpp);
// if next opp <> len of expr then
// move indicator 1 pos back
If NextOpp <> Length(Expr) Then
Dec(NextOpp);
sExpr := Copy(Expr, PrevOpp, NextOpp);
// 5) evaluating expression
Delete(Expr, PrevOpp, NextOpp);
FinalExpr := Copy(Expr, 1, PrevOpp-1) + EvalAddExpr(sExpr) + Copy(Expr, PrevOpp, Length(Expr));
End;
Result := Expr;
End;
End.
Parser10
是由 Renate Schaaf 开发的经典数学解析器,最后由 Hallvard Vassbotn 更新。请参见 Parsing a string formula to an integer result。 - LU RD