unit uengShaderFileExpression; {$mode objfpc}{$H+} {$I uengShaderFile.inc} interface uses Classes, SysUtils, variants, uengShaderPart, uengShaderFileParser, uengShaderPartKeyValuePair; type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TengExpressionItem = class(TengShaderPart) public function GetValue: Variant; virtual; constructor Create(const aLine, aCol: Integer); reintroduce; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TengExpressionValue = class(TengExpressionItem) private fValue: Variant; public property Value: Variant read fValue; function GetText: String; override; function GetValue: Variant; override; constructor Create(const aValue: Variant; const aLine, aCol: Integer); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TengExpressionVariable = class(TengExpressionItem) private fName: String; fPart: TengShaderPartKeyValuePair; public property Name: String read fName; property Part: TengShaderPartKeyValuePair read fPart; function GetText: String; override; function GetValue: Variant; override; constructor Create(const aName: String; const aPart: TengShaderPartKeyValuePair; const aLine, aCol: Integer); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TengExpressionGroup = class(TengExpressionItem) private fChild: TengExpressionItem; protected function GetCount: Integer; override; function GetChild(const aIndex: Integer): TengShaderPart; override; public property Child: TengExpressionItem read fChild; function GetText: String; override; function GetValue: Variant; override; constructor Create(const aChild: TengExpressionItem; const aLine, aCol: Integer); destructor Destroy; override; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TengExpressionOperation = class(TengExpressionItem) protected function GetWeight: Integer; virtual; public property Weight: Integer read GetWeight; function ExchangeFirst(const aItem: TengExpressionItem): TengExpressionItem; virtual; function ExchangeLast(const aItem: TengExpressionItem): TengExpressionItem; virtual; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TengExpressionUnaryOperator = ( opBinaryNot, opLogicalNot ); TengExpressionUnaryOperation = class(TengExpressionOperation) private fChild: TengExpressionItem; fUnaryOp: TengExpressionUnaryOperator; protected function GetWeight: Integer; override; function GetCount: Integer; override; function GetChild(const aIndex: Integer): TengShaderPart; override; public property Child: TengExpressionItem read fChild; property UnaryOp: TengExpressionUnaryOperator read fUnaryOp; function GetText: String; override; function GetValue: Variant; override; function ExchangeFirst(const aItem: TengExpressionItem): TengExpressionItem; override; function ExchangeLast(const aItem: TengExpressionItem): TengExpressionItem; override; constructor Create(const aUnaryOp: TengExpressionUnaryOperator; const aChild: TengExpressionItem; const aLine, aCol: Integer); destructor Destroy; override; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TengExpressionBinaryOperator = ( //order of elements in this enum is also the weight of the operators opBinaryOr, opBinaryAnd, opBinaryXor, // binary opMultiply, opDivide, opAdd, opSubtract, // arithmetic opLogicalOr, opLogicalAnd, opLogicalXor, // logical opEquals, opLesser, opGreater, opLEquals, opGEquals, opUnequals // comparison ); TengExpressionBinaryOperation = class(TengExpressionOperation) private fFirst: TengExpressionItem; fSecond: TengExpressionItem; fBinaryOp: TengExpressionBinaryOperator; protected function GetWeight: Integer; override; function GetCount: Integer; override; function GetChild(const aIndex: Integer): TengShaderPart; override; public property First: TengExpressionItem read fFirst write fFirst; property Second: TengExpressionItem read fSecond write fSecond; property BinaryOp: TengExpressionBinaryOperator read fBinaryOp; function GetText: String; override; function GetValue: Variant; override; function ExchangeFirst(const aItem: TengExpressionItem): TengExpressionItem; override; function ExchangeLast(const aItem: TengExpressionItem): TengExpressionItem; override; constructor Create(const aOperator: TengExpressionBinaryOperator; const aFirst, aSecond: TengExpressionItem; const aLine, aCol: Integer); destructor Destroy; override; end; function ParseExpression(const aParent: TengShaderPart; const aParams: TengTokenParameterList; aIndex: Integer): TengExpressionItem; implementation uses uengShaderFileConstants, uengShaderFileTypes, uengShaderFileHelper, uengShaderPartScope, uengShaderFile; const EXPRESSION_UNARY_OPERATIONS: array[TengExpressionUnaryOperator] of String = ( TOKEN_OP_BINARY_NOT, //opBinaryNot TOKEN_OP_LOGICAL_NOT //opLogicalNot ); EXPRESSION_BINARY_OPERATIONS: array[TengExpressionBinaryOperator] of String = ( TOKEN_OP_BINARY_OR, //opBinaryOr TOKEN_OP_BINARY_AND, //opBinaryAnd TOKEN_OP_BINARY_XOR, //opBinaryXor TOKEN_OP_MULTIPLY, //opMultiply TOKEN_OP_DIVIDE, //opDivide TOKEN_OP_ADD, //opAdd TOKEN_OP_SUBTRACT, //opSubtract TOKEN_OP_LOGICAL_OR, //opLogicalOr TOKEN_OP_LOGICAL_AND, //opLogicalAnd TOKEN_OP_LOGICAL_XOR, //opLogicalXor TOKEN_OP_EQUALS, //opEquals TOKEN_OP_LESSER, //opLesser TOKEN_OP_GREATER, //opGreater TOKEN_OP_LEQUALS, //opLEquals TOKEN_OP_GEQUALS, //opGEquals TOKEN_OP_UNEQUALS //opUnequals ); UNARY_OPERATION_WEIGHTS: array[TengExpressionUnaryOperator] of Integer = ( 00, //opBinaryNot 00 //opLogicalNot ); BINARY_OPERATION_WEIGHTS: array[TengExpressionBinaryOperator] of Integer = ( 01, //opBinaryOr 02, //opBinaryAnd 03, //opBinaryXor 04, //opMultiply 05, //opDivide 06, //opAdd 07, //opSubtract 14, //opLogicalOr 15, //opLogicalAnd 16, //opLogicalXor 08, //opEquals 09, //opLesser 10, //opGreater 11, //opLEquals 12, //opGEquals 13 //opUnequals ); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengExpressionItem//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionItem.GetValue: Variant; begin result := Unassigned; // DUMMY end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TengExpressionItem.Create(const aLine, aCol: Integer); begin inherited Create(nil); fLine := aLine; fCol := aCol; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengExpressionValue/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionValue.GetText: String; begin result := TOKEN_CHAR_QUOTE + fValue + TOKEN_CHAR_QUOTE; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionValue.GetValue: Variant; begin result := fValue; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TengExpressionValue.Create(const aValue: Variant; const aLine, aCol: Integer); begin inherited Create(aLine, aCol); fValue := aValue; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengExpressionVariable//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionVariable.GetText: String; begin result := fName; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionVariable.GetValue: Variant; begin result := Unassigned; if Assigned(fPart) then result := fPart.Value; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TengExpressionVariable.Create(const aName: String; const aPart: TengShaderPartKeyValuePair; const aLine, aCol: Integer); begin inherited Create(aLine, aCol); fName := aName; fPart := aPart; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengExpressionGroup/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionGroup.GetCount: Integer; begin result := 1; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionGroup.GetChild(const aIndex: Integer): TengShaderPart; begin if (aIndex >= 0) and (aIndex < 1) then result := fChild else raise EengOutOfRange.Create(0, 0, aIndex, self); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionGroup.GetText: String; begin if Assigned(fChild) then result := TOKEN_OP_GROUP_BEGIN + fChild.GetText + TOKEN_OP_GROUP_END else result := ''; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionGroup.GetValue: Variant; begin if Assigned(fChild) then result := fChild.GetValue else result := Unassigned; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TengExpressionGroup.Create(const aChild: TengExpressionItem; const aLine, aCol: Integer); begin inherited Create(aLine, aCol); fChild := aChild; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// destructor TengExpressionGroup.Destroy; begin FreeAndNil(fChild); inherited Destroy; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengExpressionOperation/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionOperation.GetWeight: Integer; begin result := -1; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionOperation.ExchangeFirst(const aItem: TengExpressionItem): TengExpressionItem; begin result := nil; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionOperation.ExchangeLast(const aItem: TengExpressionItem): TengExpressionItem; begin result := nil; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengExpressionUnaryOperation////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionUnaryOperation.GetWeight: Integer; begin result := UNARY_OPERATION_WEIGHTS[fUnaryOp]; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionUnaryOperation.GetCount: Integer; begin result := 1; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionUnaryOperation.GetChild(const aIndex: Integer): TengShaderPart; begin if (aIndex >= 0) and (aIndex < 1) then result := fChild else raise EengOutOfRange.Create(0, 0, aIndex, self); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionUnaryOperation.GetText: String; begin if not Assigned(fChild) then EengExpression.Create('no child assigned', self); result := {$IFDEF SHADER_FILE_EXPRESSION_ADD_BRACKET}TOKEN_OP_GROUP_BEGIN+{$ENDIF} EXPRESSION_UNARY_OPERATIONS[fUnaryOp] + ' ' + fChild.GetText {$IFDEF SHADER_FILE_EXPRESSION_ADD_BRACKET}+TOKEN_OP_GROUP_END{$ENDIF}; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionUnaryOperation.GetValue: Variant; var v: Variant; begin if not Assigned(fChild) then raise EengExpression.Create('no child assigned', self); try case fUnaryOp of opBinaryNot: begin v := fChild.GetValue; result := not Integer(v); end; opLogicalNot: begin v := fChild.GetValue; result := not Boolean(v); end; else result := inherited GetValue; end; except on ex: Exception do raise EengInvalidParamter.Create( ex.Message + '("' + GetText + '" ==> ' + EXPRESSION_UNARY_OPERATIONS[fUnaryOp] + ' ' + v + '")', Line, Col, Filename, self); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionUnaryOperation.ExchangeFirst(const aItem: TengExpressionItem): TengExpressionItem; begin result := fChild; fChild := aItem; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionUnaryOperation.ExchangeLast(const aItem: TengExpressionItem): TengExpressionItem; begin result := fChild; fChild := aItem; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TengExpressionUnaryOperation.Create(const aUnaryOp: TengExpressionUnaryOperator; const aChild: TengExpressionItem; const aLine, aCol: Integer); begin inherited Create(aLine, aCol); fChild := aChild; fUnaryOp := aUnaryOp; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// destructor TengExpressionUnaryOperation.Destroy; begin FreeAndNil(fChild); inherited Destroy; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengExpressionBinaryOperation///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionBinaryOperation.GetWeight: Integer; begin result := BINARY_OPERATION_WEIGHTS[fBinaryOp]; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionBinaryOperation.GetCount: Integer; begin result := 2; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionBinaryOperation.GetChild(const aIndex: Integer): TengShaderPart; begin if (aIndex < 0) and (aIndex >= 2) then raise EengOutOfRange.Create(0, 1, aIndex, self); case aIndex of 0: result := fFirst; 1: result := fSecond; else result := nil; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionBinaryOperation.GetText: String; begin if not Assigned(fFirst) or not Assigned(fSecond) then raise EengExpression.Create('first or second item not assigned'); result := {$IFDEF SHADER_FILE_EXPRESSION_ADD_BRACKET}TOKEN_OP_GROUP_BEGIN +{$ENDIF} fFirst.GetText + ' ' + EXPRESSION_BINARY_OPERATIONS[fBinaryOp] + ' ' + fSecond.GetText {$IFDEF SHADER_FILE_EXPRESSION_ADD_BRACKET} + TOKEN_OP_GROUP_END{$ENDIF}; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionBinaryOperation.GetValue: Variant; var v1: Variant; v2: Variant; begin if not Assigned(fFirst) or not Assigned(fSecond) then raise EengExpression.Create('first or second item not assigned'); v1 := fFirst.GetValue; v2 := fSecond.GetValue; try case fBinaryOp of opBinaryOr: result := (Integer(v1) or Integer(v2)); opBinaryAnd: result := (Integer(v1) and Integer(v2)); opBinaryXor: result := (Integer(v1) xor Integer(v2)); opMultiply: result := (v1 * v2); opDivide: result := (v1 / v2); opAdd: result := (v1 + v2); opSubtract: result := (v1 - v2); opLogicalOr: result := (Boolean(v1) or Boolean(v2)); opLogicalAnd: result := (Boolean(v1) and Boolean(v2)); opLogicalXor: result := (Boolean(v1) xor Boolean(v2)); opEquals: result := (v1 = v2); opLesser: result := (v1 < v2); opGreater: result := (v1 > v2); opLEquals: result := (v1 <= v2); opGEquals: result := (v1 >= v2); opUnequals: result := (v1 <> v2); else result := inherited GetValue; end; except on ex: Exception do raise EengInvalidParamter.Create( ex.Message + ' ("' + GetText + '" ==> "' + v1 + ' ' + EXPRESSION_BINARY_OPERATIONS[fBinaryOp] + ' ' + v2 + '")', self); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionBinaryOperation.ExchangeFirst(const aItem: TengExpressionItem): TengExpressionItem; begin result := fFirst; fFirst := aItem; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionBinaryOperation.ExchangeLast(const aItem: TengExpressionItem): TengExpressionItem; begin result := fSecond; fSecond := aItem; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TengExpressionBinaryOperation.Create(const aOperator: TengExpressionBinaryOperator; const aFirst, aSecond: TengExpressionItem; const aLine, aCol: Integer); begin inherited Create(aLine, aCol); fBinaryOp := aOperator; fFirst := aFirst; fSecond := aSecond; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// destructor TengExpressionBinaryOperation.Destroy; begin FreeAndNil(fFirst); FreeAndNil(fSecond); inherited Destroy; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// type TExpectedParam = (exVariable, exValue, exGroupBegin, exGroupEnd, exUnaryOperation, exBinaryOperation); TExpectedParams = set of TExpectedParam; TExpressionParser = class(TObject) private fParent: TengShaderPart; fParamPos: Integer; fParams: TengTokenParameterList; private function NextParam(out aParam: TengTokenParameter): Boolean; function IsUnaryOperation(const aParam: String; out aOperator: TengExpressionUnaryOperator): Boolean; function IsBinaryOperation(const aParam: String; out aOperator: TengExpressionBinaryOperator): Boolean; procedure RaiseEx(const aMsg: String; const aParam: TengTokenParameter; aName: String = ''); function Move(var aItem: TengExpressionItem): TengExpressionItem; function Merge(aOld, aNew: TengExpressionItem): TengExpressionItem; function GetExpr(const aExpected: TExpectedParams): TengExpressionItem; public function GetGroup: TengExpressionItem; constructor Create(const aParent: TengShaderPart; const aParams: TengTokenParameterList; const aIndex: Integer); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TExpressionParser///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TExpressionParser.NextParam(out aParam: TengTokenParameter): Boolean; begin inc(fParamPos); result := (fParamPos < fParams.Count); if result then aParam := fParams[fParamPos] else FillByte(aParam{%H-}, SizeOf(aParam), 0); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TExpressionParser.IsUnaryOperation(const aParam: String; out aOperator: TengExpressionUnaryOperator): Boolean; begin result := true; for aOperator in TengExpressionUnaryOperator do if (aParam = EXPRESSION_UNARY_OPERATIONS[aOperator]) then exit; result := false; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TExpressionParser.IsBinaryOperation(const aParam: String; out aOperator: TengExpressionBinaryOperator): Boolean; begin result := true; for aOperator in TengExpressionBinaryOperator do if (aParam = EXPRESSION_BINARY_OPERATIONS[aOperator]) then exit; result := false; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TExpressionParser.RaiseEx(const aMsg: String; const aParam: TengTokenParameter; aName: String = ''); begin if (aName = '') then aName := aParam.Name; raise EengExpression.Create(aMsg + ' ' + aParam.Name, aParam.Line, aParam.Col, fParent.Filename, fParent); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TExpressionParser.Move(var aItem: TengExpressionItem): TengExpressionItem; begin result := aItem; aItem := nil; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TExpressionParser.Merge(aOld, aNew: TengExpressionItem): TengExpressionItem; var o, n: TengExpressionOperation; tmp: TengExpressionItem; begin result := nil; try if not Assigned(aOld) then begin result := aNew; exit; end else if not Assigned(aNew) then begin result := aOld; exit; end else if (aOld is TengExpressionOperation) and (aNew is TengExpressionOperation) then begin o := (aOld as TengExpressionOperation); n := (aNew as TengExpressionOperation); if (n.Weight < o.Weight) then begin tmp := n.ExchangeFirst(o.ExchangeLast(n)); aNew := nil; result := aOld; end else begin tmp := n.ExchangeFirst(o); aOld := nil; result := aNew; end; if Assigned(tmp) then raise EengExpressionInternal.Create(1, fParent); end else if (aOld is TengExpressionOperation) then begin o := (aOld as TengExpressionOperation); o.ExchangeLast(aNew); aNew := nil; result := aOld; end else if (aNew is TengExpressionOperation) then begin n := (aNew as TengExpressionOperation); n.ExchangeFirst(aOld); aOld := nil; result := aNew; end;; except FreeAndNil(aOld); FreeAndNil(aNew); result := nil; raise; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TExpressionParser.GetExpr(const aExpected: TExpectedParams): TengExpressionItem; var uOp: TengExpressionUnaryOperator; bOp: TengExpressionBinaryOperator; item: TengExpressionItem; param: TengTokenParameter; sr: TengSearchResults; walker: TengKeyValuePairSearchWalker; tmp: TengShaderPart; begin item := nil; result := nil; try if NextParam(param) then begin // GroupBegin if (param.Name = TOKEN_OP_GROUP_BEGIN) then begin if not (exGroupBegin in aExpected) then RaiseEx('unexpected', param); item := GetGroup; result := TengExpressionGroup.Create(Move(item), param.Col, param.Line); // GroupEnd end else if (param.Name = TOKEN_OP_GROUP_END) then begin if not (exGroupEnd in aExpected) then RaiseEx('unexpected', param); // UnaryOperation end else if IsUnaryOperation(param.Name, uOp) then begin if not (exUnaryOperation in aExpected) then RaiseEx('unexpected operation:', param); item := GetExpr([exVariable, exValue, exGroupBegin, exUnaryOperation]); result := TengExpressionUnaryOperation.Create(uOp, Move(item), param.Line, param.Col); // BinaryOperation end else if IsBinaryOperation(param.Name, bOp) then begin if not (exBinaryOperation in aExpected) then RaiseEx('unexpected operation:', param); item := GetExpr([exVariable, exValue, exGroupBegin, exUnaryOperation]); item := TengExpressionBinaryOperation.Create(bOp, nil, Move(item), param.Line, param.Col); result := Merge(result, item); // Value end else if param.Quoted and IsValidIdentifier(param.Name) then begin if not (exValue in aExpected) then RaiseEx('unexpected value:', param); result := TengExpressionValue.Create(param.Name, param.Line, param.Col); // Variable end else if IsValidIdentifier(param.Name) then begin if not (exVariable in aExpected) then RaiseEx('unexpected variable:', param); sr := TengSearchResults.Create; walker := TengKeyValuePairSearchWalker.Create(sr); try walker.Name := param.Name; walker.SearchFlags := [sfSearchChildren, sfSearchParents, sfSearchInherited]; walker.ResultTypes := CengShaderPartArr.Create(TengShaderPartProperty, TengShaderPartStatic); walker.ChildrenDoNotLeave := CengShaderPartArr.Create(TengShaderPartScope); walker.ChildrenForceLeave := CengShaderPartArr.Create(TengShaderFile); walker.ParentsDoNotLeave := CengShaderPartArr.Create(TengShaderFile); walker.Run(fParent); tmp := ExtractSearchResult(fParent, param.Name, sr, [ifWarning, ifRaiseEx], param.Line, param.Col); result := TengExpressionVariable.Create(param.Name, (tmp as TengShaderPartKeyValuePair), param.Line, param.Col); finally FreeAndNil(walker); FreeAndNil(sr); end; // Unknown end else raise EengExpression.Create('invalid parameter: ' + param.Name, param.Line, param.Col, fParent.Filename, fParent); end; if not Assigned(result) and not (exGroupEnd in aExpected) then RaiseEx('unexpected', param, 'end'); except FreeAndNil(item); FreeAndNil(result); raise; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TExpressionParser.GetGroup: TengExpressionItem; var ex: TExpectedParams; item: TengExpressionItem; b: Boolean; begin item := nil; result := nil; try ex := [exVariable, exValue, exGroupBegin, exUnaryOperation]; repeat item := GetExpr(ex); b := Assigned(item); result := Merge(result, Move(item)); ex := ex + [exBinaryOperation, exGroupEnd]; until not b; except FreeAndNil(result); FreeAndNil(item); raise; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TExpressionParser.Create(const aParent: TengShaderPart; const aParams: TengTokenParameterList; const aIndex: Integer); begin fParamPos := aIndex - 1; fParams := aParams; fParent := aParent; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function ParseExpression(const aParent: TengShaderPart; const aParams: TengTokenParameterList; aIndex: Integer): TengExpressionItem; var parser: TExpressionParser; begin parser := TExpressionParser.Create(aParent, aParams, aIndex); try result := parser.GetGroup; finally FreeAndNil(parser); end; end; end.