unit UCxParser;
{==========================================================================}
{ Expression Evaluator v1.4 for Delphi }
{ Copyright ?1997 by BitSoft Development, L.L.C. }
{ Modify by zzy }
{ Modify by linhw }
{ 1、增加了中文函数的支持 }
{ 增加函数Asin,Acos,Tan }
{ 2、增加对符号处理 }
{ 中括号为注释 }
{ 花括号与括号相同 }
{ 3、大符号支持 +-*/ }
{==========================================================================}
interface
uses
Windows,
SysUtils, Messages, Classes, Graphics, Controls, Forms, Dialogs;
type
TGetVarEvent = procedure(Sender: TObject;
VarName: string;
var
Value: Extended;
var Found: Boolean) of object;
TParseErrorEvent = procedure(Sender: TObject;
ParseError: Integer)
of object;
const
ParserStackSize = 60;
MaxFuncNameLen = 8;
ExpLimit = 11356;
SqrLimit = 1E2466;
MaxExpLen = 6;
TotalErrors = 7;
ErrParserStack = 1;
ErrBadRange = 2;
ErrExpression = 3;
ErrOperator = 4;
ErrOpenParen = 5;
ErrOpCloseParen = 6;
ErrInvalidNum = 7;
type
ErrorRange = 0..TotalErrors;
TokenTypes = (Plus, Minus, Times, Divide, Expo, OParen, CParen, Num,
Func, EOL, Bad, ERR, Modu,Iif);
TokenRec = record
State: Byte;
case Byte of
0: (Value: Extended);
2: (FuncName: string[MaxFuncNameLen]);
end;
type
TCxParser = class(TComponent)
private
FInput: string;
FOnGetVar: TGetVarEvent;
FOnParseError: TParseErrorEvent;
protected
CurrToken: TokenRec;
MathError: Boolean;
Stack: array[1..ParserStackSize] of TokenRec;
StackTop: 0..ParserStackSize;
TokenError: ErrorRange;
TokenLen: Word;
TokenType: TokenTypes;
procedure OmitMemo;
function GetNextchar(aindex: integer): char;
function GotoState(Production: Word): Word;
function IsFunc(S: string): Boolean;
function IsVar(var Value: Extended): Boolean;
function NextToken: TokenTypes;
procedure Push(Token: TokenRec);
procedure Pop(var Token: TokenRec);
procedure Reduce(Reduction: Word);
procedure Shift(State: Word);
function IsCalChar(AIndex: integer): char;
public
Position: Word;
ParseError: Boolean;
ParseValue: Extended;
constructor Create;
procedure Parse;
published
property OnGetVar: TGetVarEvent read FOnGetVar write FOnGetVar;
property OnParseError: TParseErrorEvent read FOnParseError
write FOnParseError;
property ParseString: string read FInput write FInput;
end;
implementation
uses
math;
const
Letters: set of Char = ['<', 'A'..'Z', 'a'..'z'];
Numbers: set of Char = ['0'..'9'];
const
cCharCn: array[#32..#126] of string[2] =
(
{ }' ', {!} '!', {"} '"', {#} '#', { } '$', {%} '%', {&} '&', {'}
''', {(} '(',
{)}')', {*} '*', {+} '+', {,} ',', {-} '-', {.} '。', {/} '/', {0} '0',
{1}'1',
{2}'2', {3} '3', {4} '4', {5} '5', {6} '6', {7} '7', {8} '8', {9}
'9', {:} ':',
{;}';', {<} '<', {=} '=', {>} '>', {?} '?', {@} '@', {A} 'A', {B}
'B',
{C}'C',
{D}'D', {E} 'E', {F} 'F', {G} 'G', {H} 'H', {I} 'I', {J} 'J', {K}
'K', {L} 'L',
{M}'M', {N} 'N', {O} 'O', {P} 'P', {Q} 'Q', {R} 'R', {S} 'S', {T}
'T', {U} 'U',
{V}'V', {W} 'W', {X} 'X', {Y} 'Y', {Z} 'Z', {[} '[', {/} '\', {]}
']', {^} '^',
{_}'_', {`} '`', {a} 'a', {b} 'b', {c} 'c', {d} 'd', {e} 'e', {f}
'f', {g} 'g',
{h}'h', {i} 'i', {j} 'j', {k} 'k', {l} 'l', {m} 'm', {n} 'n', {o}
'o', {p} 'p',
{q}'q', {r} 'r', {s} 's', {t} 't', {u} 'u', {v} 'v', {w} 'w', {x}
'x', {y} 'y',
{z}'z', {{} '{', {|} '|', { } '}', {~} '~');
function GBTextToStr(mText: string): string;
{ 返回字符串转换成半角字符串 }
var
I: Integer;
J: Char;
S: string;
begin
Result := '';
for I := 1 to Length(WideString(mText))do
begin
S := WideString(mText);
if Length(S) > 1 then
begin
for J := #32 to #126do
if cCharCn[J] = S then
begin
S := J;
Break;
end;
if S = '.' then
S := '.';
end;
Result := Result + S;
end;
end;
{ GBTextToStr }
constructor TCxParser.Create;
begin
// inherited Create(AOwner);
{ defaults }
FInput := '';
end;
function TCxParser.GotoState(Production: Word): Word;
{ Finds the new state based on the just-completed production and the
top state. }
var
State: Word;
begin
GotoState := 0;
State := Stack[StackTop].State;
if (Production <= 3) then
begin
case State of
0: GotoState := 1;
9: GotoState := 19;
20: GotoState := 28;
end;
{ case }
end
else
if Production <= 6 then
begin
case State of
0, 9, 20: GotoState := 2;
12: GotoState := 21;
13: GotoState := 22;
end;
{ case }
end
else
if (Production <= 8) or (Production = 100) then
begin
case State of
0, 9, 12, 13, 20: GotoState := 3;
14: GotoState := 23;
15: GotoState := 24;
16: GotoState := 25;
40: GotoState := 80;
end;
{ case }
end
else
if Production <= 10 then
begin
case State of
0, 9, 12..16, 20, 40: GotoState := 4;
end;
{ case }
end
else
if Production <= 12 then
begin
case State of
0, 9, 12..16, 20, 40: GotoState := 6;
5: GotoState := 17;
end;
{ case }
end
else
begin
case State of
0, 5, 9, 12..16, 20, 40: GotoState := 8;
end;
{ case }
end;
end;
{ GotoState }
function TCxParser.IsFunc(S: string): Boolean;
{ Checks to see if the parser is about to read a function }
var
P, SLen: Word;
FuncName: string;
begin
P := Position;
FuncName := '';
while (P <= Length(FInput)) and (FInput[P] in ['A'..'Z', 'a'..'z', '0'..'9',
'_']) or (bytetype(FInput, P) <> mbSingleByte)do
//Add by zzy加入中文函数处理
begin
FuncName := FuncName + FInput[P];
Inc(P);
end;
{ while }
if Uppercase(FuncName) = S then
begin
SLen := Length(S);
CurrToken.FuncName := UpperCase(Copy(FInput, Position, SLen));
Inc(Position, SLen);
IsFunc := True;
end { if }
else
IsFunc := False;
end;
{ IsFunc }
function TCxParser.IsVar(var Value: Extended): Boolean;
var
VarName: string;
VarFound: Boolean;
begin
VarFound := False;
VarName := '';
while (Position <= Length(FInput))do
begin
VarName := VarName + FInput[Position];
Inc(Position);
if Finput[Position - 1] = '>' then
break;
end;
{ while }
if Assigned(FOnGetVar) then
FOnGetVar(Self, VarName, Value, VarFound);
IsVar := VarFound;
end;
{ IsVar }
function GetNumS(S, SubS: string): Integer;
{某个字符串中子串的个数}
var
s1, s2: string;
{某个字符串中子串的个数}
begin
{注意最后一个不是subs时直接调用GetNums}
result := -1;
if s = '' then
exit;
s1 := stringreplace(s, subs, '