mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-12 14:09:31 +02:00
fpvectorial: Implements support for infix to RPN formula conversion for left-associative operators
git-svn-id: trunk@44394 -
This commit is contained in:
parent
796e552c53
commit
5d6b6286f1
@ -789,6 +789,8 @@ type
|
|||||||
procedure Render(ADest: TFPCustomCanvas; ARenderInfo: TvRenderInfo; ADestX: Integer = 0;
|
procedure Render(ADest: TFPCustomCanvas; ARenderInfo: TvRenderInfo; ADestX: Integer = 0;
|
||||||
ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0); virtual;
|
ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0); virtual;
|
||||||
procedure GenerateDebugTree(ADestRoutine: TvDebugAddItemProc; APageItem: Pointer); virtual;
|
procedure GenerateDebugTree(ADestRoutine: TvDebugAddItemProc; APageItem: Pointer); virtual;
|
||||||
|
class function GetPrecedenceFromKind(AKind: TvFormulaElementKind): Byte; // 0 is the smallest precedence
|
||||||
|
class function IsLeftAssociativeFromKind(AKind: TvFormulaElementKind): Boolean;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TvFormula }
|
{ TvFormula }
|
||||||
@ -1398,7 +1400,7 @@ var
|
|||||||
GvVectorialFormats: array of TvVectorialFormatData;
|
GvVectorialFormats: array of TvVectorialFormatData;
|
||||||
|
|
||||||
const
|
const
|
||||||
FormulaOperators = [fekSubtraction, fekMultiplication, fekSum, fekFraction];
|
FormulaOperators = [fekSubtraction, fekMultiplication, fekSum, fekFraction, fekRoot, fekPower];
|
||||||
|
|
||||||
procedure RegisterVectorialReader(
|
procedure RegisterVectorialReader(
|
||||||
AReaderClass: TvVectorialReaderClass;
|
AReaderClass: TvVectorialReaderClass;
|
||||||
@ -4485,6 +4487,29 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// http://en.wikipedia.org/wiki/Shunting-yard_algorithm
|
||||||
|
class function TvFormulaElement.GetPrecedenceFromKind(
|
||||||
|
AKind: TvFormulaElementKind): Byte;
|
||||||
|
begin
|
||||||
|
Result := 0;
|
||||||
|
case AKind of
|
||||||
|
fekSubtraction, fekSum: Result := 2;
|
||||||
|
fekMultiplication, fekFraction: Result := 3;
|
||||||
|
//fekRoot, // A root. For example sqrt(something). Number gives the root, usually 2, and inside it goes a Formula
|
||||||
|
fekPower: Result := 4;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// See http://en.wikipedia.org/wiki/Shunting-yard_algorithm
|
||||||
|
class function TvFormulaElement.IsLeftAssociativeFromKind(
|
||||||
|
AKind: TvFormulaElementKind): Boolean;
|
||||||
|
begin
|
||||||
|
Result := True;
|
||||||
|
case AKind of
|
||||||
|
fekPower: Result := False;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TvFormula }
|
{ TvFormula }
|
||||||
|
|
||||||
procedure TvFormula.CallbackDeleteElement(data, arg: pointer);
|
procedure TvFormula.CallbackDeleteElement(data, arg: pointer);
|
||||||
@ -4562,12 +4587,30 @@ var
|
|||||||
procedure PopFromStackIntoList(APopTopOperators: Boolean; APopUntilParenteses: Boolean);
|
procedure PopFromStackIntoList(APopTopOperators: Boolean; APopUntilParenteses: Boolean);
|
||||||
var
|
var
|
||||||
lElement: TvFormulaElement;
|
lElement: TvFormulaElement;
|
||||||
|
lAllowContinue: Boolean;
|
||||||
begin
|
begin
|
||||||
while OperatorStack.Count > 0 do
|
while OperatorStack.Count > 0 do
|
||||||
begin
|
begin
|
||||||
lElement := OperatorStack.Pop() as TvFormulaElement;
|
lElement := OperatorStack.Pop() as TvFormulaElement;
|
||||||
if APopTopOperators and (not (lElement.Kind in FormulaOperators)) then Exit;
|
|
||||||
|
// while there is an operator token, o2, at the top of the stack, and
|
||||||
|
// either o1 is left-associative and its precedence is equal to that of o2,
|
||||||
|
// or o1 has precedence less than that of o2,
|
||||||
|
if APopTopOperators then
|
||||||
|
begin
|
||||||
|
if not (lElement.Kind in FormulaOperators) then Exit;
|
||||||
|
|
||||||
|
lAllowContinue := TvFormulaElement.IsLeftAssociativeFromKind(lElement.Kind)
|
||||||
|
and (TvFormulaElement.GetPrecedenceFromKind(lElement.Kind) =
|
||||||
|
TvFormulaElement.GetPrecedenceFromKind(CurItem.Kind));
|
||||||
|
lAllowContinue := lAllowContinue or
|
||||||
|
(TvFormulaElement.GetPrecedenceFromKind(lElement.Kind) >
|
||||||
|
TvFormulaElement.GetPrecedenceFromKind(CurItem.Kind));
|
||||||
|
if not lAllowContinue then Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
if APopUntilParenteses and (lElement.Kind = fekParentesesOpen) then Exit;
|
if APopUntilParenteses and (lElement.Kind = fekParentesesOpen) then Exit;
|
||||||
|
|
||||||
FElements.Add(lElement);
|
FElements.Add(lElement);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
Loading…
Reference in New Issue
Block a user