Mega Code Archive

 
Categories / Delphi / Examples
 

Your own evaluator

Title: Your own evaluator Question: Having a string logic that does your checking or setting of your component propertys Answer: // Please vote or leafe messages so we all learn from eachother :) The example is a project that i reused http://www.xs4all.nl/~suusie/Pieter/Programs/MapingComponentsToGui.zip I modified it so you can check and set some propertys in the object. the source i posted is pure the object so if you dont want to type or want to see it all work just check out the component attachment . Ok heres the deal you have validations on your object that are user controleble. You can store them like strings and do checking like this I made a simple example that explains the use of the object. If you want to do more validationm you wil have to write a mechanism that wil allow more statements to be saved and executed. Ik my self used a Collection Class for this .. Not included in the example . procedure TForm1.ButtonSetAndCheckClick(Sender: TObject); var LogicParcer: TLogicParcer; aVariant,BVariant,CVariant: Variant; begin LogicParcer := TLogicParcer.Create; try // set the logic parcers eval object to be able to have acces to // those propertys LogicParcer.EvalObject := ExampleComponent; aVariant := LogicParcer.CalcValue('5 if Vartype(aVariant) varBoolean then raise Exception.Create('Invalid if statement'); BVariant := LogicParcer.CalcValue('4 * 5'); if Vartype(BVariant) = varEmpty then raise Exception.Create('Not a value assigned'); CVariant := LogicParcer.CalcValue('True'); if Vartype(CVariant) varBoolean then raise Exception.Create('Invalid if check statement'); // this is how you cold parce the logic if aVariant then LogicParcer.SetPersistentProp('AFloat', ExampleComponent,BVariant); if CVariant then raise Exception.Create('Error text here '); finally LogicParcer.free; end; end; unit LogicParcer; interface uses Classes, Sysutils; // Graphics, Controls, Forms, Dialogs, // StdCtrls; const TokenSet: set of char = ['+', '-', '*', '/', '^', '|', '=', '!', '&', '']; type TLogixType = (ltToken, tlValue, ltRecurse, ltObject, ltFunction); TLogixNode = class(TObject) LogixType: TLogixType; Value: Variant; end; TLogicParcer = class private FEvalObject: TPersistent; function EvalMax(AString: string): string; procedure FindBeginAndEndPosOfBracets(const AValue: string; var Abeginpos, AEndPos: Integer); function GetObjectValue(AObject: string): Variant; function CalcValueFromlist(Alist: Tlist): Variant; function Evalmin(AString: string): string; Function EvalToDate(aString : String ) : String ; procedure SetEvalObject(const Value: TPersistent); { Private declarations } public // Easy acces to objects bij string function GetPersistentProp(AName: string; aPersistent: TPersistent): Variant; procedure SetPersistentProp(AName: string; aPersistent: TPersistent; Value: Variant); function CalcValue(AValue: string): Variant; // USed in evaluating Object propertys defined lik [SomeProp] including // nestled operations like [somePersistendprop.SomeProp property EvalObject: TPersistent read FEvalObject write SetEvalObject; { Public declarations } end; implementation uses math, contnrs, TypInfo; function TLogicParcer.CalcValue(AValue: string): Variant; var AList: Tobjectlist; i, y, EndPos: Integer; ALogicNode: TLogixNode; TempStr: string; begin try // spaties strippen for i := Length(AValue) downto 1 do begin if AValue[i] = ' ' then delete(AValue, i, 1); end; AList := Tobjectlist.Create; AList.OwnsObjects := False; try // function Search // min while Pos('Min', AValue) 0 do begin i := Pos('min', AValue) + 3; FindBeginAndEndPosOfBracets(AValue, i, EndPos); TempStr := copy(AValue, i + 1, EndPos - i); TempStr := Evalmin(TempStr); delete(AValue, i - 3, (EndPos - i) + 5); insert(TempStr, AValue, i); end; // max while Pos('Max', AValue) 0 do begin i := Pos('max', AValue) + 3; FindBeginAndEndPosOfBracets(AValue, i, EndPos); TempStr := copy(AValue, i + 1, EndPos - i); TempStr := Evalmax(TempStr); delete(AValue, i - 3, (EndPos - i) + 5); insert(TempStr, AValue, i); end; // ToDate while Pos('ToDate', AValue) 0 do begin i := Pos('ToDate', AValue) + 6; FindBeginAndEndPosOfBracets(AValue, i, EndPos); TempStr := copy(AValue, i + 1, EndPos - i); TempStr := EvalToDate(TempStr); delete(AValue, i - 6, (EndPos - i) + 8); insert(TempStr, AValue, i-6); end; i := 1; while i begin // Brackets Value if AValue[i] = '(' then begin FindBeginAndEndPosOfBracets(AValue, i, EndPos); ALogicNode := TLogixNode.Create; AList.Add(ALogicNode); ALogicNode.LogixType := ltRecurse; ALogicNode.Value := copy(AValue, i + 1, EndPos - i); ALogicNode.Value := CalcValue(VarToStr(ALogicNode.Value)); i := EndPos + 2; end else if AValue[i] in TokenSet then // Token value begin ALogicNode := TLogixNode.Create; AList.Add(ALogicNode); ALogicNode.LogixType := ltToken; TempStr := copy(AValue, i, 1); ALogicNode.Value := TempStr; Inc(i); end else // object of nummer of boolean begin TempStr := ''; while not (AValue[i] in TokenSet + ['(', #0]) do begin TempStr := TempStr + AValue[i]; inc(i); end; ALogicNode := TLogixNode.Create; AList.Add(ALogicNode); ALogicNode.LogixType := tlValue; ALogicNode.Value := ''; if (UpperCase(tempstr) = 'FALSE') or (UpperCase(tempstr) = 'TRUE') then begin ALogicNode.LogixType := tlValue; ALogicNode.Value := (UpperCase(tempstr) = 'TRUE'); end else begin for y := 1 to Length(tempstr) do begin // is het een nummer ?? if not (TempStr[y] in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', 'E']) then begin ALogicNode.Value := GetObjectValue(tempstr); ALogicNode.LogixType := ltObject; end; end; // is de waarde gevult ?? zo niet dan is het een Nummer if VarToStr(ALogicNode.Value) = '' then ALogicNode.Value := StrToFloat(tempstr); end; end; end; Result := CalcValueFromlist(AList); // end while i finally for i := 0 to AList.Count - 1 do begin TObject(AList[i]).free; end; AList.free; end; except on e: Exception do begin Result := E.Message; end; end; end; procedure TLogicParcer.FindBeginAndEndPosOfBracets(const AValue: string; var Abeginpos, AEndPos: Integer); var i, BracetsCount: Integer; begin BracetsCount := 0; for i := Abeginpos to length(AValue) do begin if AValue[i] = '(' then inc(BracetsCount) else if AValue[i] = ')' then Dec(BracetsCount); if BracetsCount = 0 then begin AEndPos := i - 1; exit; end; end; raise EMathError.Create(Format('bracets not closed in %s', [AValue])); end; function TLogicParcer.GetObjectValue(AObject: string): Variant; var i: Integer; Day, Jear, Month: Word; TempStr, TempMonth: string; begin // nul datum 30#12#1899 if (AObject = '') or (AObject[1] '[') or (AObject[Length(AObject)] ']') then exit; if POS('#', AObject) 0 then begin AObject[Length(AObject)] := ' '; AObject[1] := ' '; for i := 1 to Length(AObject) do begin if AObject[i] = '#' then AObject[i] := '-'; end; AObject := Trim(AObject); if StrToInt(AObject[1] + AObject[2]) = 0 then begin i := Length(AObject); // jaren while (AObject[i] in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']) do begin TempStr := AObject[i] + TempStr; dec(i); end; dec(i); // maanden while (AObject[i] in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']) do begin TempMonth := AObject[i] + TempMonth; dec(i); end; Jear := 1899; Month := 12; Day := 30; Jear := Jear + StrToInt(TempStr); Result := EncodeDate(jear, month, day); end else Result := StrToDate(AObject); end else if AObject = '[TODAY]' then result := Date else begin AObject[Length(AObject)] := ' '; AObject[1] := ' '; AObject := Trim(AObject); Result := GetPersistentProp(AObject, FEvalObject); end; if TVarData(result).VType = varEmpty then Result := AObject ; end; function TLogicParcer.CalcValueFromlist(Alist: Tlist): Variant; var i: Integer; begin Result := 0; // Check if Alist.Count = 1 then begin result := TlogixNode(Alist[0]).Value; exit; end; if VarToStr(TlogixNode(AList[0]).Value) '!' then begin if Alist.Count if (TLogixNode(Alist[0]).LogixType = lttoken) or (TlogixNode(Alist[Alist.Count - 1]).LogixType = lttoken) then raise EMathError.Create('Error in Expression Token found at begin or end of list'); end; // berekening // '^' // '*', // '/', // '+','-', // ,'|','=','!','&','' // meneer = machtsVerheffen i := Alist.Count - 1; while i = 0 do begin if TLogixNode(AList[i]).LogixType = ltToken then begin if TLogixNode(AList[i]).Value = '^' then begin TLogixNode(AList[i]).Value := Power(TLogixNode(AList[i - 1]).Value, TLogixNode(AList[i + 1]).Value); TLogixNode(AList[i]).LogixType := tlValue; TLogixNode(alist[i + 1]).free; Alist.Delete(i + i); TLogixNode(alist[i - 1]).free; Alist.Delete(i - i); dec(i, 2); end else dec(i); end else dec(i); end; // van = vermenigvuldigen i := Alist.Count - 1; while i = 0 do begin if TLogixNode(AList[i]).LogixType = ltToken then begin if TLogixNode(AList[i]).Value = '*' then begin TLogixNode(AList[i]).Value := TLogixNode(AList[i - 1]).Value * TLogixNode(AList[i + 1]).Value; TLogixNode(AList[i]).LogixType := tlValue; TLogixNode(alist[i + 1]).free; Alist.Delete(i + 1); TLogixNode(alist[i - 1]).free; Alist.Delete(i - 1); dec(i, 2); end else dec(i); end else dec(i); end; // dalen = Delen i := 0; while i begin if TLogixNode(AList[i]).LogixType = ltToken then begin if TLogixNode(AList[i]).Value = '/' then begin TLogixNode(AList[i]).Value := TLogixNode(AList[i - 1]).Value / TLogixNode(AList[i + 1]).Value; TLogixNode(AList[i]).LogixType := tlValue; TLogixNode(alist[i + 1]).free; Alist.Delete(i + 1); TLogixNode(alist[i - 1]).free; Alist.Delete(i - 1); end else inc(i); end else inc(i); end; // Wacht doen weniet // Op = Optellen i := Alist.Count - 1; while i = 0 do begin if TLogixNode(AList[i]).LogixType = ltToken then begin if TLogixNode(AList[i]).Value = '+' then begin TLogixNode(AList[i]).Value := TLogixNode(AList[i - 1]).Value + TLogixNode(AList[i + 1]).Value; TLogixNode(AList[i]).LogixType := tlValue; TLogixNode(alist[i + 1]).free; Alist.Delete(i + 1); TLogixNode(alist[i - 1]).free; Alist.Delete(i - 1); dec(i, 2); end else dec(i); end else dec(i); end; // Antwoord = aftrekken i := Alist.Count - 1; while i = 0 do begin if TLogixNode(AList[i]).LogixType = ltToken then begin if TLogixNode(AList[i]).Value = '-' then begin TLogixNode(AList[i]).Value := TLogixNode(AList[i - 1]).Value - TLogixNode(AList[i + 1]).Value; TLogixNode(AList[i]).LogixType := tlValue; TLogixNode(alist[i + 1]).free; Alist.Delete(i + 1); TLogixNode(alist[i - 1]).free; Alist.Delete(i - 1); dec(i, 2); end else dec(i); end else dec(i); end; // Booleanse vergelijking i := Alist.Count - 1; while i = 0 do begin if TLogixNode(AList[i]).LogixType = ltToken then begin if (TLogixNode(AList[i]).Value = '=') or (TLogixNode(AList[i]).Value = ' (TLogixNode(AList[i]).Value = '') then begin if TLogixNode(AList[i - 1]).LogixType = ltToken then begin if (TLogixNode(AList[i - 1]).Value = ' or (TLogixNode(AList[i - 1]).Value = '') then begin TLogixNode(AList[i]).Value := TLogixNode(AList[i - 1]).Value + TLogixNode(AList[i]).Value; TLogixNode(AList[i - 1]).free; alist.Delete(i - 1); dec(i); end else raise EMathError.Create('Not a valid equasion'); end; if TLogixNode(AList[i]).Value = '=' then TLogixNode(AList[i]).Value := (TLogixNode(AList[i - 1]).Value = TLogixNode(AList[i + 1]).Value) else if TLogixNode(AList[i]).Value = ' TLogixNode(AList[i]).Value := (TLogixNode(AList[i - 1]).Value else if TLogixNode(AList[i]).Value = '' then TLogixNode(AList[i]).Value := (TLogixNode(AList[i - 1]).Value TLogixNode(AList[i + 1]).Value) else if TLogixNode(AList[i]).Value = ' TLogixNode(AList[i]).Value := (TLogixNode(AList[i - 1]).Value else if TLogixNode(AList[i]).Value = '=' then TLogixNode(AList[i]).Value := (TLogixNode(AList[i - 1]).Value = TLogixNode(AList[i + 1]).Value) else if TLogixNode(AList[i]).Value = '' then TLogixNode(AList[i]).Value := (TLogixNode(AList[i - 1]).Value TLogixNode(AList[i + 1]).Value); TLogixNode(AList[i]).LogixType := tlValue; TLogixNode(alist[i + 1]).free; Alist.Delete(i + 1); TLogixNode(alist[i - 1]).free; Alist.Delete(i - 1); dec(i, 2); end else dec(i); end else dec(i); end; // booleanse operatoren // and i := Alist.Count - 1; while i = 0 do begin if TLogixNode(AList[i]).LogixType = ltToken then begin if TLogixNode(AList[i]).Value = '&' then begin TLogixNode(AList[i]).Value := TLogixNode(AList[i - 1]).Value and TLogixNode(AList[i + 1]).Value; TLogixNode(AList[i]).LogixType := tlValue; TLogixNode(alist[i + 1]).free; Alist.Delete(i + 1); TLogixNode(alist[i - 1]).free; Alist.Delete(i - 1); dec(i, 2); end else dec(i); end else dec(i); end; // or i := Alist.Count - 1; while i = 0 do begin if TLogixNode(AList[i]).LogixType = ltToken then begin if TLogixNode(AList[i]).Value = '|' then begin TLogixNode(AList[i]).Value := TLogixNode(AList[i - 1]).Value or TLogixNode(AList[i + 1]).Value; TLogixNode(AList[i]).LogixType := tlValue; TLogixNode(alist[i + 1]).free; Alist.Delete(i + 1); TLogixNode(alist[i - 1]).free; Alist.Delete(i - 1); dec(i, 2); end else dec(i); end else dec(i); end; // not i := Alist.Count - 1; while i = 0 do begin if TLogixNode(AList[i]).LogixType = ltToken then begin if TLogixNode(AList[i]).Value = '!' then begin TLogixNode(AList[i]).Value := not TLogixNode(AList[i + 1]).Value; TLogixNode(AList[i]).LogixType := tlValue; TLogixNode(alist[i + 1]).free; Alist.Delete(i + 1); dec(i); end else dec(i); end else dec(i); end; if Alist.Count 1 then raise EMathError.Create('Error After calc list count 1'); Result := TLogixNode(Alist[0]).Value; end; function TLogicParcer.EvalMax(AString: string): string; var i: Integer; a, b: Extended; sa, sb: string; begin i := length(AString); while not (AString[i] = ',') do begin sb := AString[i] + sb; dec(i); if i = 1 then exit; end; dec(i); while not (AString[i] = #0) do begin sa := AString[i] + sa; dec(i); end; a := StrToFloat(VarToStr(CalcValue(sa))); b := StrToFloat(VarToStr(CalcValue(sb))); result := FloatToStr(max(a, b)); end; function TLogicParcer.Evalmin(AString: string): string; var i: Integer; a, b: Extended; sa, sb: string; begin i := length(AString); while not (AString[i] = ',') do begin sb := AString[i] + sb; dec(i); if i = 1 then exit; end; dec(i); while not (AString[i] = #0) do begin sa := AString[i] + sa; dec(i); end; a := StrToFloat(VarToStr(CalcValue(sa))); b := StrToFloat(VarToStr(CalcValue(sb))); result := FloatToStr(Min(a, b)); end; procedure TLogicParcer.SetEvalObject(const Value: TPersistent); begin FEvalObject := Value; end; procedure TLogicParcer.SetPersistentProp(AName: string; APersistent: TPersistent; Value: Variant); var PropList: PPropList; PropCount: Integer; ClassTypeInfo: PTypeInfo; ClassTypeData: PTypeData; i: integer; Propname, NextName: string; begin if APersistent = nil then exit; ClassTypeInfo := APersistent.ClassInfo; ClassTypeData := GetTypeData(ClassTypeInfo); PropCount := ClassTypeData.PropCount - 1; if pos('.', AName) 0 then begin Propname := copy(AName, 1, pos('.', AName) - 1); NextName := copy(AName, pos('.', AName) + 1, Length(AName) - pos('.', AName) + 1); end else Propname := AName; // reserveer geheugen GetMem(PropList, SizeOf(PPropInfo) * ClassTypeData.PropCount); // Error trap try // Vul de prop list GetPropInfos(APersistent.ClassInfo, PropList); for i := 0 to PropCount do begin if (PropList[i]^.Name = Propname) and (NextName = '') then case PropList[i]^.PropType^.Kind of tkString, tkLString, tkWString, tkWChar, tkChar: begin SetStrProp(APersistent, PropList[i], VarToStr(Value)); end; tkInteger, tkEnumeration: begin if VarToStr(Value) '' then SetOrdProp(APersistent, PropList[i], StrToInt(VarToStr(Value))); end; tkFloat: begin if (PropList[i]^.PropType^.Name = 'TDateTime') then SetFloatProp(APersistent, PropList[i], VarToDateTime(Value)) else SetFloatProp(APersistent, PropList[i], StrToFloat(VarToStr(Value))); end; end; // end case // recursion logic if PropList[i]^.PropType^.Kind = tkClass then if GetObjectProp(APersistent, PropList[i]) is TPersistent then begin if (PropList[i]^.Name = Propname) and (NextName '') then SetPersistentProp(NextName, TPersistent(GetObjectProp(APersistent, PropList[i])), Value); end; end; // end i finally FreeMem(PropList, SizeOf(PPropInfo) * ClassTypeData.PropCount); end; end; function TLogicParcer.GetPersistentProp(AName: string; APersistent: TPersistent): Variant; var PropList: PPropList; PropCount: Integer; ClassTypeInfo: PTypeInfo; ClassTypeData: PTypeData; i: integer; Propname, NextName: string; begin if APersistent = nil then exit; ClassTypeInfo := APersistent.ClassInfo; ClassTypeData := GetTypeData(ClassTypeInfo); PropCount := ClassTypeData.PropCount - 1; if pos('.', AName) 0 then begin Propname := copy(AName, 1, pos('.', AName) - 1); NextName := copy(AName, pos('.', AName) + 1, Length(AName) - pos('.', AName) + 1); end else Propname := AName; // reserveer geheugen GetMem(PropList, SizeOf(PPropInfo) * ClassTypeData.PropCount); // Error trap try // Vul de prop list GetPropInfos(APersistent.ClassInfo, PropList); for i := 0 to PropCount do begin if (PropList[i]^.Name = Propname) and (NextName = '') then case PropList[i]^.PropType^.Kind of tkString, tkLString, tkWString, tkWChar, tkChar: begin Result := GetStrProp(APersistent, PropList[i]); end; tkInteger, tkEnumeration: begin Result := GetOrdProp(APersistent, PropList[i]); end; tkFloat: begin if (PropList[i]^.PropType^.Name = 'TDateTime') then Result := VarFromDateTime(GetFloatProp(APersistent, PropList[i])) else Result := GetFloatProp(APersistent, PropList[i]); end; end; // end case // recursion logic if PropList[i]^.PropType^.Kind = tkClass then if GetObjectProp(APersistent, PropList[i]) is TPersistent then begin If (GetObjectProp(APersistent, PropList[i]) is TCollection) and (NextName ='Count') then Result := TCollection (GetObjectProp(APersistent, PropList[i])).Count else if (PropList[i]^.Name = Propname) and (NextName '') then Result := GetPersistentProp(NextName, TPersistent(GetObjectProp(APersistent, PropList[i]))); end; end; // end i finally FreeMem(PropList, SizeOf(PPropInfo) * ClassTypeData.PropCount); end; end; function TLogicParcer.EvalToDate(aString: String): String; var i : Integer ; begin Result := VarToStr(CalcValue(aString)); for i := 1 to length(Result) do if result[i] = '-' then result[i] := '#' ; Result := '[' + result + ']' ; end; end.