2012-05-09 16:52:22 +02:00
|
|
|
{
|
|
|
|
Inno Setup Preprocessor
|
|
|
|
Copyright (C) 2001-2002 Alex Yackimoff
|
2020-06-25 17:09:59 +02:00
|
|
|
|
|
|
|
Inno Setup
|
|
|
|
Copyright (C) 1997-2010 Jordan Russell
|
|
|
|
Portions by Martijn Laan
|
|
|
|
For conditions of distribution and use, see LICENSE.TXT.
|
2012-05-09 16:52:22 +02:00
|
|
|
}
|
|
|
|
|
2024-08-03 16:36:50 +02:00
|
|
|
unit ISPP.Parser;
|
2012-05-09 16:52:22 +02:00
|
|
|
|
|
|
|
interface
|
|
|
|
|
2024-08-03 16:36:50 +02:00
|
|
|
uses
|
|
|
|
ISPP.Intf, ISPP.Base, ISPP.IdentMan, ISPP.CTokenizer;
|
2012-05-09 16:52:22 +02:00
|
|
|
|
|
|
|
type
|
|
|
|
|
|
|
|
TParser = class(TCTokenizer)
|
|
|
|
private
|
|
|
|
FIdentMan: IIdentManager;
|
|
|
|
FOptions: PIsppParserOptions;
|
|
|
|
function CheckLValue(const LValue: TIsppVariant): TIsppVariant;
|
|
|
|
function PrefixIncDec(LValue: TIsppVariant; Dec: Boolean): TIsppVariant;
|
|
|
|
function PostfixIncDec(LValue: TIsppVariant; Dec: Boolean): TIsppVariant;
|
|
|
|
function AssignOperation(LValue, RValue: TIsppVariant; Op: TTokenKind): TIsppVariant;
|
|
|
|
function PerformOperation(Op1, Op2: TIsppVariant; Op: TTokenKind): TIsppVariant;
|
|
|
|
function UnaryOperation(Op: TTokenKind; Op1: TIsppVariant): TIsppVariant;
|
|
|
|
protected
|
|
|
|
function Chain(Level: Byte; DoEval: Boolean): TIsppVariant;
|
|
|
|
function Factor(DoEval: Boolean): TIsppVariant;
|
|
|
|
function Assignment(DoEval: Boolean): TIsppVariant;
|
|
|
|
function Conditional(DoEval: Boolean): TIsppVariant;
|
|
|
|
function Sequentional(DoEval: Boolean): TIsppVariant;
|
|
|
|
public
|
|
|
|
constructor Create(const IdentMan: IIdentManager; const Expression: string;
|
|
|
|
Offset: Integer; Options: PIsppParserOptions);
|
|
|
|
function Evaluate: TIsppVariant;
|
|
|
|
function Expr(StopOnComma: Boolean): TIsppVariant;
|
2020-06-25 17:09:59 +02:00
|
|
|
function IntExpr(StopOnComma: Boolean): Int64;
|
2012-05-09 16:52:22 +02:00
|
|
|
function StrExpr(StopOnComma: Boolean): string;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function Parse(const VarMan: IIdentManager; const AExpr: string; Offset: Integer; Options: PIsppParserOptions): TIsppVariant;
|
|
|
|
function ParseStr(const VarMan: IIdentManager; const AExpr: string; Offset: Integer; Options: PIsppParserOptions): string;
|
2020-06-25 17:09:59 +02:00
|
|
|
function ParseInt(const VarMan: IIdentManager; const AExpr: string; Offset: Integer; Options: PIsppParserOptions): Int64;
|
2012-05-09 16:52:22 +02:00
|
|
|
|
|
|
|
implementation
|
|
|
|
|
2024-08-03 16:36:50 +02:00
|
|
|
uses
|
|
|
|
SysUtils, ISPP.Sessions, ISPP.Consts, ISPP.VarUtils;
|
2012-05-09 16:52:22 +02:00
|
|
|
|
|
|
|
function Parse(const VarMan: IIdentManager; const AExpr: string; Offset: Integer; Options: PIsppParserOptions): TIsppVariant;
|
|
|
|
begin
|
|
|
|
with TParser.Create(VarMan, AExpr, Offset, Options) do
|
|
|
|
try
|
|
|
|
Result := Evaluate
|
|
|
|
finally
|
|
|
|
Free
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function ParseStr(const VarMan: IIdentManager; const AExpr: string; Offset: Integer; Options: PIsppParserOptions): string;
|
|
|
|
begin
|
|
|
|
with TParser.Create(VarMan, AExpr, Offset, Options) do
|
|
|
|
try
|
|
|
|
Result := StrExpr(True);
|
|
|
|
EndOfExpr;
|
|
|
|
finally
|
|
|
|
Free
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2020-06-25 17:09:59 +02:00
|
|
|
function ParseInt(const VarMan: IIdentManager; const AExpr: string; Offset: Integer; Options: PIsppParserOptions): Int64;
|
2012-05-09 16:52:22 +02:00
|
|
|
begin
|
|
|
|
with TParser.Create(VarMan, AExpr, Offset, Options) do
|
|
|
|
try
|
|
|
|
Result := IntExpr(True);
|
|
|
|
EndOfExpr;
|
|
|
|
finally
|
|
|
|
Free
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ TParser }
|
|
|
|
|
|
|
|
constructor TParser.Create(const IdentMan: IIdentManager;
|
|
|
|
const Expression: string; Offset: Integer; Options: PIsppParserOptions);
|
|
|
|
begin
|
|
|
|
inherited Create(Expression, not (optPascalStrings in Options^.Options));
|
|
|
|
FExprOffset := Offset;
|
|
|
|
FIdentMan := IdentMan;
|
|
|
|
FOptions := Options;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TParser.Evaluate: TIsppVariant;
|
|
|
|
begin
|
|
|
|
Result := Expr(False);
|
|
|
|
MakeRValue(Result);
|
|
|
|
EndOfExpr;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TParser.Sequentional(DoEval: Boolean): TIsppVariant;
|
|
|
|
begin
|
|
|
|
Result := Assignment(DoEval);
|
|
|
|
while PeekAtNextToken = tkComma do
|
|
|
|
begin
|
|
|
|
NextToken;
|
|
|
|
Result := Assignment(DoEval)
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TParser.Expr(StopOnComma: Boolean): TIsppVariant;
|
|
|
|
begin
|
|
|
|
if StopOnComma then
|
|
|
|
Result := Assignment(True)
|
|
|
|
else
|
|
|
|
Result := Sequentional(True)
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TParser.Factor(DoEval: Boolean): TIsppVariant;
|
|
|
|
|
|
|
|
procedure PopulateCallContext(const CallContext: ICallContext);
|
|
|
|
const
|
|
|
|
Brackets: array[TArgGroupingStyle, Boolean] of TTokenKind =
|
|
|
|
((tkError, tkError), (tkOpenParen, tkCloseParen),
|
|
|
|
(tkOpenBracket, tkCloseBracket), (tkOpenBrace, tkCloseBrace));
|
|
|
|
type
|
|
|
|
TArgNamingState = (ansUnknown, ansNamed, ansUnnamed);
|
|
|
|
var
|
|
|
|
V: TIsppVariant;
|
|
|
|
ArgName: string;
|
|
|
|
ArgNamingState: TArgNamingState;
|
|
|
|
T: TTokenKind;
|
|
|
|
ArgFound: Boolean;
|
|
|
|
|
|
|
|
procedure GetExpression;
|
|
|
|
begin
|
|
|
|
V := Assignment(DoEval);
|
|
|
|
Store;
|
|
|
|
T := NextTokenExpect([tkComma, Brackets[CallContext.GroupingStyle, True]]);
|
|
|
|
Restore;
|
|
|
|
ArgFound := True;
|
|
|
|
end;
|
|
|
|
|
|
|
|
begin
|
|
|
|
ArgNamingState := ansUnknown;
|
|
|
|
ArgFound := False;
|
|
|
|
if PeekAtNextToken = Brackets[CallContext.GroupingStyle, False] then
|
|
|
|
begin
|
|
|
|
NextToken;
|
|
|
|
V := NULL;
|
|
|
|
ArgName := '';
|
|
|
|
T := PeekAtNextToken;
|
|
|
|
while True do
|
|
|
|
case T of
|
|
|
|
tkComma:
|
|
|
|
begin
|
|
|
|
NextToken;
|
|
|
|
CallContext.Add(ArgName, V);
|
|
|
|
V := NULL;
|
|
|
|
T := PeekAtNextToken;
|
|
|
|
end;
|
|
|
|
tkCloseParen, tkCloseBracket, tkCloseBrace:
|
|
|
|
begin
|
|
|
|
NextToken;
|
|
|
|
if ArgFound then CallContext.Add(ArgName, V);
|
|
|
|
V := NULL;
|
|
|
|
Break
|
|
|
|
end;
|
|
|
|
tkIdent:
|
|
|
|
begin
|
|
|
|
Store;
|
|
|
|
NextToken;
|
|
|
|
ArgName := TokenString;
|
|
|
|
if PeekAtNextToken <> opAssign then
|
|
|
|
begin
|
|
|
|
if ArgNamingState = ansNamed then Error(SActualParamsNamingConflict);
|
|
|
|
ArgNamingState := ansUnnamed;
|
|
|
|
ArgName := '';
|
|
|
|
Restore;
|
|
|
|
GetExpression;
|
|
|
|
end
|
|
|
|
else
|
|
|
|
begin
|
|
|
|
if ArgNamingState = ansUnnamed then Error(SActualParamsNamingConflict);
|
|
|
|
ArgNamingState := ansNamed;
|
|
|
|
NextToken;
|
|
|
|
GetExpression;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
else
|
|
|
|
begin
|
|
|
|
if ArgNamingState = ansNamed then Error(SActualParamsNamingConflict);
|
|
|
|
ArgNamingState := ansUnnamed;
|
|
|
|
ArgName := '';
|
|
|
|
GetExpression;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
var
|
2020-06-25 17:09:59 +02:00
|
|
|
I: Int64;
|
2012-05-09 16:52:22 +02:00
|
|
|
IdentType: TIdentType;
|
|
|
|
CallContext: ICallContext;
|
|
|
|
Op: TTokenKind;
|
|
|
|
ParenthesesUsed: Boolean;
|
|
|
|
begin
|
|
|
|
FillChar(Result, SizeOf(Result), 0);
|
|
|
|
case NextTokenExpect(ExpressionStartTokens) of
|
|
|
|
tkOpenParen:
|
|
|
|
begin
|
|
|
|
Result := Sequentional(DoEval);
|
|
|
|
NextTokenExpect([tkCloseParen])
|
|
|
|
end;
|
|
|
|
tkPtr:
|
|
|
|
begin
|
|
|
|
NextTokenExpect([tkIdent]);
|
|
|
|
Result.Typ := evCallContext;
|
|
|
|
if not (FIdentMan.GetIdent(TokenString, Result.AsCallContext) in
|
|
|
|
[itVariable, itMacro, itFunc]) then
|
|
|
|
Error('Variable, macro, or function required');
|
|
|
|
end;
|
|
|
|
tkIdent:
|
|
|
|
begin
|
|
|
|
CallContext := nil;
|
|
|
|
IdentType := FIdentMan.GetIdent(TokenString, CallContext);
|
|
|
|
case IdentType of
|
|
|
|
itUnknown:
|
|
|
|
if (optAllowUndeclared in FOptions.Options) and not
|
|
|
|
(PeekAtNextToken in [tkOpenParen, tkOpenBracket, tkOpenBrace]) then
|
|
|
|
begin
|
|
|
|
Result.Typ := evNull;
|
2020-08-09 01:49:07 +02:00
|
|
|
WarningMsg(SUndeclaredIdentifier, [TokenString]);
|
2012-05-09 16:52:22 +02:00
|
|
|
end
|
|
|
|
else
|
|
|
|
ErrorFmt(SUndeclaredIdentifier, [TokenString]);
|
|
|
|
itVariable, itMacro, itFunc:
|
|
|
|
begin
|
|
|
|
PopulateCallContext(CallContext);
|
|
|
|
if DoEval then
|
|
|
|
Result := CallContext.Call
|
|
|
|
end;
|
|
|
|
itDefinedFunc:
|
|
|
|
begin
|
|
|
|
ParenthesesUsed := PeekAtNextToken = tkOpenParen;
|
|
|
|
if ParenthesesUsed then NextToken;
|
|
|
|
NextTokenExpect([tkIdent]);
|
|
|
|
if DoEval then
|
|
|
|
MakeBool(Result, FIdentMan.Defined(TokenString));
|
|
|
|
if ParenthesesUsed then NextTokenExpect([tkCloseParen])
|
|
|
|
end;
|
|
|
|
itTypeOfFunc:
|
|
|
|
begin
|
|
|
|
ParenthesesUsed := PeekAtNextToken = tkOpenParen;
|
|
|
|
if ParenthesesUsed then NextToken;
|
|
|
|
NextTokenExpect([tkIdent]);
|
|
|
|
if DoEval then
|
|
|
|
MakeInt(Result, FIdentMan.TypeOf(TokenString));
|
|
|
|
if ParenthesesUsed then NextTokenExpect([tkCloseParen]);
|
|
|
|
end;
|
2012-12-16 13:30:58 +01:00
|
|
|
itDimOfFunc:
|
2012-05-09 16:52:22 +02:00
|
|
|
begin
|
|
|
|
ParenthesesUsed := PeekAtNextToken = tkOpenParen;
|
|
|
|
if ParenthesesUsed then NextToken;
|
|
|
|
NextTokenExpect([tkIdent]);
|
|
|
|
if DoEval then
|
|
|
|
MakeInt(Result, FIdentMan.DimOf(TokenString));
|
|
|
|
if ParenthesesUsed then NextTokenExpect([tkCloseParen])
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
tkNumber:
|
|
|
|
begin
|
2020-06-25 17:09:59 +02:00
|
|
|
if not TryStrToInt64(TokenString, I) then
|
2012-05-09 16:52:22 +02:00
|
|
|
ErrorFmt(SCannotConvertToInteger, [TokenString]);
|
|
|
|
MakeInt(Result, I);
|
|
|
|
end;
|
|
|
|
tkString: MakeStr(Result, TokenString);
|
|
|
|
opInc, opDec:
|
|
|
|
begin
|
|
|
|
Op := Token;
|
|
|
|
if DoEval then
|
|
|
|
Result := PrefixIncDec(CheckLValue(Factor(True)), Op = opDec)
|
|
|
|
else
|
|
|
|
Result := Factor(False);
|
|
|
|
end;
|
|
|
|
else
|
|
|
|
begin
|
|
|
|
Op := Token;
|
|
|
|
if DoEval then
|
|
|
|
Result := UnaryOperation(Op, Factor(True))
|
|
|
|
else
|
|
|
|
Factor(False)
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
Op := PeekAtNextToken;
|
|
|
|
while Op in [opInc, opDec] do
|
|
|
|
begin
|
|
|
|
if DoEval then
|
|
|
|
Result := PostfixIncDec(CheckLValue(Result), Op = opDec);
|
|
|
|
NextToken;
|
|
|
|
Op := PeekAtNextToken;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TParser.PerformOperation(Op1, Op2: TIsppVariant; Op: TTokenKind): TIsppVariant;
|
|
|
|
var
|
2020-06-25 17:09:59 +02:00
|
|
|
A, B: Int64;
|
2012-05-09 16:52:22 +02:00
|
|
|
AsBool: Boolean;
|
|
|
|
begin
|
|
|
|
MakeRValue(Op1);
|
|
|
|
MakeRValue(Op2);
|
|
|
|
if Op1.Typ = evNull then
|
|
|
|
case Op2.Typ of
|
|
|
|
evNull:
|
|
|
|
begin
|
|
|
|
MakeInt(Op1, 0);
|
|
|
|
MakeInt(Op2, 0);
|
|
|
|
end;
|
|
|
|
evInt: MakeInt(Op1, 0);
|
|
|
|
evStr: MakeStr(Op1, '');
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if Op2.Typ = evNull then
|
|
|
|
case Op1.Typ of
|
|
|
|
evInt: MakeInt(Op2, 0);
|
|
|
|
evStr: MakeStr(Op2, '');
|
|
|
|
end;
|
|
|
|
if (Op1.Typ <> Op2.Typ) or ((Op in [opSubtract..opShr]) and (Op1.Typ = evStr))
|
|
|
|
then Error(SOperatorNotApplicableToThisOpera);
|
|
|
|
AsBool := False;
|
|
|
|
with Result do
|
|
|
|
try
|
|
|
|
if Op1.Typ = evStr then
|
|
|
|
begin
|
|
|
|
if Op = opAdd then MakeStr(Result, Op1.AsStr + Op2.AsStr)
|
|
|
|
else
|
|
|
|
begin
|
|
|
|
Typ := evInt;
|
|
|
|
A := CompareText(Op1.AsStr, Op2.AsStr);
|
|
|
|
case Op of
|
|
|
|
opGreater: AsBool := A > 0;
|
|
|
|
opLess: AsBool := A < 0;
|
|
|
|
opGreaterEqual: AsBool := A >= 0;
|
|
|
|
opLessEqual: AsBool := A <= 0;
|
|
|
|
opEqual: AsBool := A = 0;
|
|
|
|
opNotEqual: AsBool := A <> 0;
|
|
|
|
end;
|
2020-06-25 17:09:59 +02:00
|
|
|
AsInt := Int64(AsBool)
|
2012-05-09 16:52:22 +02:00
|
|
|
end;
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if Op1.Typ = evInt then
|
|
|
|
begin
|
|
|
|
A := Op1.AsInt;
|
|
|
|
B := Op2.AsInt;
|
|
|
|
Typ := evInt;
|
|
|
|
case Op of
|
|
|
|
opGreater: AsBool := A > B;
|
|
|
|
opLess: AsBool := A < B;
|
|
|
|
opGreaterEqual: AsBool := A >= B;
|
|
|
|
opLessEqual: AsBool := A <= B;
|
|
|
|
opEqual: AsBool := A = B;
|
|
|
|
opNotEqual: AsBool := A <> B;
|
|
|
|
opAdd: AsInt := A + B;
|
|
|
|
opSubtract: AsInt := A - B;
|
|
|
|
opOr: AsBool := (A <> 0) or (B <> 0);
|
|
|
|
opBwOr: AsInt := A or B;
|
|
|
|
opXor: AsInt := A xor B;
|
|
|
|
opMul: AsInt := A * B;
|
|
|
|
opDiv: AsInt := A div B;
|
|
|
|
opAnd: AsBool := (A <> 0) and (B <> 0);
|
|
|
|
opBwAnd: AsInt := A and B;
|
|
|
|
opShl: AsInt := A shl B;
|
|
|
|
opShr: AsInt := A shr B;
|
|
|
|
opMod: AsInt := A mod B;
|
|
|
|
end;
|
2020-06-25 17:09:59 +02:00
|
|
|
if Op in [opGreater..opNotEqual, opOr, opAnd] then AsInt := Int64(AsBool)
|
2012-05-09 16:52:22 +02:00
|
|
|
end
|
|
|
|
except
|
|
|
|
on E: Exception do Error(E.Message);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TParser.UnaryOperation(Op: TTokenKind; Op1: TIsppVariant): TIsppVariant;
|
|
|
|
var
|
2020-06-25 17:09:59 +02:00
|
|
|
A: Int64;
|
2012-05-09 16:52:22 +02:00
|
|
|
begin
|
|
|
|
MakeRValue(Op1);
|
|
|
|
A := 0; // satisfy compiler
|
|
|
|
case Op1.Typ of
|
|
|
|
evNull:;
|
|
|
|
evInt: A := Op1.AsInt
|
|
|
|
else
|
|
|
|
Error(SWrongUnaryOperator);
|
|
|
|
end;
|
|
|
|
case Op of
|
|
|
|
opNot: MakeBool(Result, A = 0);
|
|
|
|
opBwNot: MakeInt(Result, not A);
|
|
|
|
opAdd: MakeInt(Result, A);
|
|
|
|
opSubtract: MakeInt(Result, -A)
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
type
|
|
|
|
TShortCircuitEvalMode = (scemNone, scemStandard, scemOptional);
|
|
|
|
|
|
|
|
const
|
|
|
|
OperatorPrecedence: array[0..9] of record
|
|
|
|
Operators: set of TTokenKind;
|
|
|
|
SCBE: TShortCircuitEvalMode;
|
|
|
|
SCBEValue: Boolean;
|
|
|
|
end =
|
|
|
|
((Operators: [opOr]; SCBE: scemStandard; SCBEValue: True),
|
|
|
|
(Operators: [opAnd]; SCBE: scemStandard; SCBEValue: False),
|
|
|
|
(Operators: [opBwOr]; SCBE: scemNone; SCBEValue: False),
|
|
|
|
(Operators: [opXor]; SCBE: scemNone; SCBEValue: False),
|
|
|
|
(Operators: [opBwAnd]; SCBE: scemNone; SCBEValue: False),
|
|
|
|
(Operators: [opEqual, opNotEqual]; SCBE: scemNone; SCBEValue: False),
|
|
|
|
(Operators: [opLess, opLessEqual,
|
|
|
|
opGreater, opGreaterEqual]; SCBE: scemNone; SCBEValue: False),
|
|
|
|
(Operators: [opShl, opShr]; SCBE: scemOptional; SCBEValue: False),
|
|
|
|
(Operators: [opAdd, opSubtract]; SCBE: scemNone; SCBEValue: False),
|
|
|
|
(Operators: [opMul, opDiv, opMod]; SCBE: scemOptional; SCBEValue: False));
|
|
|
|
|
|
|
|
function TParser.Chain(Level: Byte; DoEval: Boolean): TIsppVariant;
|
|
|
|
|
|
|
|
function CallNext: TIsppVariant;
|
|
|
|
begin
|
|
|
|
if Level = High(OperatorPrecedence) then
|
|
|
|
Result := Factor(DoEval)
|
|
|
|
else
|
|
|
|
Result := Chain(Level + 1, DoEval);
|
|
|
|
end;
|
|
|
|
|
|
|
|
var
|
|
|
|
Operator: TTokenKind;
|
|
|
|
R: Shortint;
|
|
|
|
begin
|
|
|
|
Result := CallNext;
|
|
|
|
while PeekAtNextToken in OperatorPrecedence[Level].Operators do
|
|
|
|
begin
|
|
|
|
if DoEval and (OperatorPrecedence[Level].SCBE <> scemNone) and
|
|
|
|
(GetOption(FOptions.Options, 'B') or // short circuit bool eval
|
|
|
|
GetOption(FOptions.Options, 'M')) then // short circuit mul eval
|
|
|
|
begin
|
|
|
|
with GetRValue(Result) do
|
|
|
|
case Typ of
|
|
|
|
evInt: if AsInt = 0 then R := 0 else R := 1;
|
|
|
|
evStr: R := -1
|
|
|
|
else
|
|
|
|
R := 0;
|
|
|
|
end;
|
|
|
|
if R <> -1 then
|
|
|
|
begin
|
|
|
|
if (OperatorPrecedence[Level].SCBE = scemStandard) and GetOption(FOptions.Options, 'B')
|
|
|
|
or (OperatorPrecedence[Level].SCBE = scemOptional) and GetOption(FOptions.Options, 'M') then
|
|
|
|
DoEval := not (OperatorPrecedence[Level].SCBEValue = Boolean(R))
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
Operator := NextToken;
|
|
|
|
if DoEval then
|
|
|
|
Result := PerformOperation(Result, CallNext, Operator)
|
|
|
|
else
|
|
|
|
CallNext;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2020-06-25 17:09:59 +02:00
|
|
|
function TParser.IntExpr(StopOnComma: Boolean): Int64;
|
2012-05-09 16:52:22 +02:00
|
|
|
var
|
|
|
|
V: TIsppVariant;
|
|
|
|
begin
|
|
|
|
Result := 0;
|
|
|
|
if StopOnComma then
|
|
|
|
V := Assignment(True)
|
|
|
|
else
|
|
|
|
V := Sequentional(True);
|
|
|
|
MakeRValue(V);
|
|
|
|
if V.Typ = evInt then
|
|
|
|
Result := V.AsInt
|
|
|
|
else
|
|
|
|
Error(SIntegerExpressionExpected);
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TParser.StrExpr(StopOnComma: Boolean): string;
|
|
|
|
var
|
|
|
|
V: TIsppVariant;
|
|
|
|
begin
|
|
|
|
if StopOnComma then
|
|
|
|
V := Assignment(True)
|
|
|
|
else
|
|
|
|
V := Sequentional(True);
|
|
|
|
MakeRValue(V);
|
|
|
|
case V.Typ of
|
|
|
|
evNull: Result := '';
|
|
|
|
evStr: Result := V.AsStr;
|
|
|
|
else
|
|
|
|
Error(SStringExpressionExpected);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TParser.Assignment(DoEval: Boolean): TIsppVariant;
|
|
|
|
var
|
|
|
|
Op: TTokenKind;
|
|
|
|
begin
|
|
|
|
Result := Conditional(DoEval);
|
|
|
|
while PeekAtNextToken in [opAssign..opAgnMod] do
|
|
|
|
begin
|
|
|
|
Op := NextToken;
|
|
|
|
if DoEval then
|
|
|
|
Result := AssignOperation(CheckLValue(Result), Assignment(DoEval), Op)
|
|
|
|
else
|
|
|
|
Assignment(DoEval)
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TParser.Conditional(DoEval: Boolean): TIsppVariant;
|
|
|
|
var
|
|
|
|
R: Boolean;
|
|
|
|
T, F: TIsppVariant;
|
|
|
|
begin
|
|
|
|
Result := Chain(0, DoEval);
|
|
|
|
while PeekAtNextToken = tkQuestion do
|
|
|
|
begin
|
|
|
|
NextToken;
|
|
|
|
if DoEval then
|
|
|
|
with GetRValue(Result) do
|
|
|
|
case Typ of
|
|
|
|
evNull: R := False;
|
|
|
|
evInt: R := AsInt <> 0;
|
|
|
|
else
|
|
|
|
R := AsStr <> '';
|
|
|
|
end
|
|
|
|
else
|
|
|
|
R := False;
|
|
|
|
T := Sequentional(DoEval and R);
|
|
|
|
NextTokenExpect([tkColon]);
|
|
|
|
F := Conditional(DoEval and not R);
|
|
|
|
if DoEval then
|
|
|
|
if R then
|
|
|
|
Result := T
|
|
|
|
else
|
|
|
|
Result := F;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TParser.AssignOperation(LValue, RValue: TIsppVariant;
|
|
|
|
Op: TTokenKind): TIsppVariant;
|
|
|
|
begin
|
|
|
|
SimplifyLValue(LValue);
|
|
|
|
if Op = opAssign then
|
|
|
|
begin
|
|
|
|
LValue.AsPtr^ := GetRValue(RValue);
|
|
|
|
Result := LValue;
|
|
|
|
end
|
|
|
|
else
|
|
|
|
begin
|
|
|
|
Result := PerformOperation(LValue, RValue, TTokenKind(Ord(Op) - (Ord(opAgnAdd) - Ord(opAdd))));
|
|
|
|
LValue.AsPtr^ := Result;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TParser.PostfixIncDec(LValue: TIsppVariant; Dec: Boolean): TIsppVariant;
|
|
|
|
var
|
|
|
|
V: TIsppVariant;
|
|
|
|
begin
|
|
|
|
Result := GetRValue(LValue);
|
|
|
|
SimplifyLValue(LValue);
|
|
|
|
if Dec then MakeInt(V, -1) else MakeInt(V, 1);
|
|
|
|
LValue.AsPtr^ := PerformOperation(Result, V, opAdd);
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TParser.PrefixIncDec(LValue: TIsppVariant;
|
|
|
|
Dec: Boolean): TIsppVariant;
|
|
|
|
var
|
|
|
|
V: TIsppVariant;
|
|
|
|
begin
|
|
|
|
SimplifyLValue(LValue);
|
|
|
|
if Dec then MakeInt(V, -1) else MakeInt(V, 1);
|
|
|
|
LValue.AsPtr^ := PerformOperation(GetRValue(LValue), V, opAdd);
|
|
|
|
Result := LValue;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TParser.CheckLValue(const LValue: TIsppVariant): TIsppVariant;
|
|
|
|
begin
|
|
|
|
if LValue.Typ <> evLValue then Error(SLValueRequired);
|
|
|
|
Result := LValue;
|
|
|
|
end;
|
|
|
|
|
|
|
|
end.
|
|
|
|
|
|
|
|
|