fcl-passrc: parser: use operator position for TBinaryExpr

git-svn-id: trunk@37245 -
This commit is contained in:
Mattias Gaertner 2017-09-18 08:29:48 +00:00
parent e709afc543
commit b2796c13b6
6 changed files with 112 additions and 58 deletions

View File

@ -299,7 +299,8 @@ type
function CreateElement(AClass: TPTreeElement; const AName: String; AParent: TPasElement; AVisibility: TPasMemberVisibility; const ASrcPos: TPasSourcePos): TPasElement;overload; function CreateElement(AClass: TPTreeElement; const AName: String; AParent: TPasElement; AVisibility: TPasMemberVisibility; const ASrcPos: TPasSourcePos): TPasElement;overload;
function CreatePrimitiveExpr(AParent: TPasElement; AKind: TPasExprKind; const AValue: String): TPrimitiveExpr; function CreatePrimitiveExpr(AParent: TPasElement; AKind: TPasExprKind; const AValue: String): TPrimitiveExpr;
function CreateBoolConstExpr(AParent: TPasElement; AKind: TPasExprKind; const ABoolValue : Boolean): TBoolConstExpr; function CreateBoolConstExpr(AParent: TPasElement; AKind: TPasExprKind; const ABoolValue : Boolean): TBoolConstExpr;
function CreateBinaryExpr(AParent : TPasElement; xleft, xright: TPasExpr; AOpCode: TExprOpCode): TBinaryExpr; function CreateBinaryExpr(AParent : TPasElement; xleft, xright: TPasExpr; AOpCode: TExprOpCode): TBinaryExpr; overload;
function CreateBinaryExpr(AParent : TPasElement; xleft, xright: TPasExpr; AOpCode: TExprOpCode; const ASrcPos: TPasSourcePos): TBinaryExpr; overload;
procedure AddToBinaryExprChain(var ChainFirst: TPasExpr; procedure AddToBinaryExprChain(var ChainFirst: TPasExpr;
Element: TPasExpr; AOpCode: TExprOpCode); Element: TPasExpr; AOpCode: TExprOpCode);
procedure AddParamsToBinaryExprChain(var ChainFirst: TPasExpr; procedure AddParamsToBinaryExprChain(var ChainFirst: TPasExpr;
@ -307,7 +308,8 @@ type
{$IFDEF VerbosePasParser} {$IFDEF VerbosePasParser}
procedure WriteBinaryExprChain(Prefix: string; First, Last: TPasExpr); procedure WriteBinaryExprChain(Prefix: string; First, Last: TPasExpr);
{$ENDIF} {$ENDIF}
function CreateUnaryExpr(AParent : TPasElement; AOperand: TPasExpr; AOpCode: TExprOpCode): TUnaryExpr; function CreateUnaryExpr(AParent : TPasElement; AOperand: TPasExpr; AOpCode: TExprOpCode): TUnaryExpr; overload;
function CreateUnaryExpr(AParent : TPasElement; AOperand: TPasExpr; AOpCode: TExprOpCode; const ASrcPos: TPasSourcePos): TUnaryExpr; overload;
function CreateArrayValues(AParent : TPasElement): TArrayValues; function CreateArrayValues(AParent : TPasElement): TArrayValues;
function CreateFunctionType(const AName, AResultName: String; AParent: TPasElement; function CreateFunctionType(const AName, AResultName: String; AParent: TPasElement;
UseParentAsResultParent: Boolean; const NamePos: TPasSourcePos): TPasFunctionType; UseParentAsResultParent: Boolean; const NamePos: TPasSourcePos): TPasFunctionType;
@ -2190,14 +2192,20 @@ begin
end; end;
function TPasParser.DoParseExpression(AParent : TPaselement;InitExpr: TPasExpr; AllowEqual : Boolean = True): TPasExpr; function TPasParser.DoParseExpression(AParent : TPaselement;InitExpr: TPasExpr; AllowEqual : Boolean = True): TPasExpr;
type
TOpStackItem = record
Token: TToken;
SrcPos: TPasSourcePos;
end;
var var
expstack : TFPList; ExpStack : TFPList;
opstack : array of TToken; OpStack : array of TOpStackItem;
opstackTop: integer; OpStackTop: integer;
pcount : Integer; PrefixCnt : Integer;
x : TPasExpr; x : TPasExpr;
i : Integer; i : Integer;
tempop : TToken; TempOp : TToken;
NotBinary : Boolean; NotBinary : Boolean;
const const
@ -2210,31 +2218,38 @@ const
function PopExp: TPasExpr; inline; function PopExp: TPasExpr; inline;
begin begin
if expstack.Count>0 then begin if ExpStack.Count>0 then begin
Result:=TPasExpr(expstack[expstack.Count-1]); Result:=TPasExpr(ExpStack[ExpStack.Count-1]);
expstack.Delete(expstack.Count-1); ExpStack.Delete(ExpStack.Count-1);
end else end else
Result:=nil; Result:=nil;
end; end;
procedure PushOper(token: TToken); inline; procedure PushOper(Token: TToken);
begin begin
inc(opstackTop); inc(OpStackTop);
if opstackTop=length(opstack) then if OpStackTop=length(OpStack) then
SetLength(opstack,length(opstack)*2+4); SetLength(OpStack,length(OpStack)*2+4);
opstack[opstackTop]:=token; OpStack[OpStackTop].Token:=Token;
OpStack[OpStackTop].SrcPos:=CurTokenPos;
end; end;
function PeekOper: TToken; inline; function PeekOper: TToken; inline;
begin begin
if opstackTop>=0 then Result:=opstack[opstackTop] if OpStackTop>=0 then Result:=OpStack[OpStackTop].Token
else Result:=tkEOF; else Result:=tkEOF;
end; end;
function PopOper: TToken; inline; function PopOper(out SrcPos: TPasSourcePos): TToken;
begin begin
Result:=PeekOper; Result:=PeekOper;
if Result<>tkEOF then dec(opstackTop); if Result=tkEOF then
SrcPos:=DefPasSourcePos
else
begin
SrcPos:=OpStack[OpStackTop].SrcPos;
dec(OpStackTop);
end;
end; end;
procedure PopAndPushOperator; procedure PopAndPushOperator;
@ -2243,22 +2258,24 @@ const
xright : TPasExpr; xright : TPasExpr;
xleft : TPasExpr; xleft : TPasExpr;
bin : TBinaryExpr; bin : TBinaryExpr;
SrcPos: TPasSourcePos;
begin begin
t:=PopOper; t:=PopOper(SrcPos);
xright:=PopExp; xright:=PopExp;
xleft:=PopExp; xleft:=PopExp;
if t=tkDotDot then if t=tkDotDot then
begin begin
bin:=CreateBinaryExpr(AParent,xleft,xright,eopNone); bin:=CreateBinaryExpr(AParent,xleft,xright,eopNone,SrcPos);
bin.Kind:=pekRange; bin.Kind:=pekRange;
end end
else else
bin:=CreateBinaryExpr(AParent,xleft,xright,TokenToExprOp(t)); bin:=CreateBinaryExpr(AParent,xleft,xright,TokenToExprOp(t),SrcPos);
expstack.Add(bin); ExpStack.Add(bin);
end; end;
Var Var
AllowedBinaryOps : Set of TToken; AllowedBinaryOps : Set of TToken;
SrcPos: TPasSourcePos;
begin begin
AllowedBinaryOps:=BinaryOP; AllowedBinaryOps:=BinaryOP;
@ -2266,13 +2283,13 @@ begin
Exclude(AllowedBinaryOps,tkEqual); Exclude(AllowedBinaryOps,tkEqual);
//DumpCurToken('Entry',iaIndent); //DumpCurToken('Entry',iaIndent);
Result:=nil; Result:=nil;
expstack := TFPList.Create; ExpStack := TFPList.Create;
SetLength(opstack,4); SetLength(OpStack,4);
opstackTop:=-1; OpStackTop:=-1;
try try
repeat repeat
NotBinary:=True; NotBinary:=True;
pcount:=0; PrefixCnt:=0;
if not Assigned(InitExpr) then if not Assigned(InitExpr) then
begin begin
// the first part of the expression has been parsed externally. // the first part of the expression has been parsed externally.
@ -2291,7 +2308,7 @@ begin
while CurToken in PrefixSym do while CurToken in PrefixSym do
begin begin
PushOper(CurToken); PushOper(CurToken);
inc(pcount); inc(PrefixCnt);
NextToken; NextToken;
end; end;
@ -2311,6 +2328,7 @@ begin
x:=CreateUnaryExpr(AParent,x, TokenToExprOp(tkCaret)); x:=CreateUnaryExpr(AParent,x, TokenToExprOp(tkCaret));
NextToken; NextToken;
end; end;
// ToDo: move dot below []
// for expressions like (TObject(m)).Free; // for expressions like (TObject(m)).Free;
if (x<>Nil) and (CurToken=tkDot) then if (x<>Nil) and (CurToken=tkDot) then
begin begin
@ -2329,34 +2347,35 @@ begin
end; end;
if not Assigned(x) then if not Assigned(x) then
ParseExcSyntaxError; ParseExcSyntaxError;
expstack.Add(x); ExpStack.Add(x);
for i:=1 to pcount do for i:=1 to PrefixCnt do
begin begin
tempop:=PopOper; TempOp:=PopOper(SrcPos);
x:=popexp; x:=PopExp;
if (tempop=tkMinus) and (x.Kind=pekRange) then if (TempOp=tkMinus) and (x.Kind=pekRange) then
begin begin
TBinaryExpr(x).Left:=CreateUnaryExpr(x, TBinaryExpr(x).left, eopSubtract); TBinaryExpr(x).Left:=CreateUnaryExpr(x, TBinaryExpr(x).left,
expstack.Add(x); eopSubtract, SrcPos);
ExpStack.Add(x);
end end
else else
expstack.Add(CreateUnaryExpr(AParent, x, TokenToExprOp(tempop) )); ExpStack.Add(CreateUnaryExpr(AParent, x, TokenToExprOp(TempOp), SrcPos));
end; end;
end end
else else
begin begin
expstack.Add(InitExpr); ExpStack.Add(InitExpr);
InitExpr:=nil; InitExpr:=nil;
end; end;
if (CurToken in AllowedBinaryOPs) then if (CurToken in AllowedBinaryOPs) then
begin begin
// Adjusting order of the operations // Adjusting order of the operations
NotBinary:=False; NotBinary:=False;
tempop:=PeekOper; TempOp:=PeekOper;
while (opstackTop>=0) and (OpLevel(tempop)>=OpLevel(CurToken)) do begin while (OpStackTop>=0) and (OpLevel(TempOp)>=OpLevel(CurToken)) do begin
PopAndPushOperator; PopAndPushOperator;
tempop:=PeekOper; TempOp:=PeekOper;
end; end;
PushOper(CurToken); PushOper(CurToken);
NextToken; NextToken;
@ -2366,14 +2385,14 @@ begin
if not NotBinary then ParseExcExpectedIdentifier; if not NotBinary then ParseExcExpectedIdentifier;
while opstackTop>=0 do PopAndPushOperator; while OpStackTop>=0 do PopAndPushOperator;
// only 1 expression should be on the stack, at the end of the correct expression // only 1 expression should be on the OpStack, at the end of the correct expression
if expstack.Count<>1 then if ExpStack.Count<>1 then
ParseExcSyntaxError; ParseExcSyntaxError;
if expstack.Count=1 then if ExpStack.Count=1 then
begin begin
Result:=TPasExpr(expstack[0]); Result:=TPasExpr(ExpStack[0]);
Result.Parent:=AParent; Result.Parent:=AParent;
end; end;
@ -2384,11 +2403,11 @@ begin
DumpCurtoken('Exiting (Result: "'+Result.GetDeclaration(true)+'") ',iaUndent);} DumpCurtoken('Exiting (Result: "'+Result.GetDeclaration(true)+'") ',iaUndent);}
if not Assigned(Result) then begin if not Assigned(Result) then begin
// expression error! // expression error!
for i:=0 to expstack.Count-1 do for i:=0 to ExpStack.Count-1 do
TPasExpr(expstack[i]).Release; TPasExpr(ExpStack[i]).Release;
end; end;
SetLength(opstack,0); SetLength(OpStack,0);
expstack.Free; ExpStack.Free;
end; end;
end; end;
@ -6037,7 +6056,10 @@ function TPasParser.CreateElement(AClass: TPTreeElement; const AName: String;
AParent: TPasElement; AVisibility: TPasMemberVisibility; AParent: TPasElement; AVisibility: TPasMemberVisibility;
const ASrcPos: TPasSourcePos): TPasElement; const ASrcPos: TPasSourcePos): TPasElement;
begin begin
Result := Engine.CreateElement(AClass, AName, AParent, AVisibility, ASrcPos); if (ASrcPos.Row=0) and (ASrcPos.FileName='') then
Result := Engine.CreateElement(AClass, AName, AParent, AVisibility, CurSourcePos)
else
Result := Engine.CreateElement(AClass, AName, AParent, AVisibility, ASrcPos);
end; end;
function TPasParser.CreatePrimitiveExpr(AParent: TPasElement; function TPasParser.CreatePrimitiveExpr(AParent: TPasElement;
@ -6059,7 +6081,14 @@ end;
function TPasParser.CreateBinaryExpr(AParent: TPasElement; xleft, function TPasParser.CreateBinaryExpr(AParent: TPasElement; xleft,
xright: TPasExpr; AOpCode: TExprOpCode): TBinaryExpr; xright: TPasExpr; AOpCode: TExprOpCode): TBinaryExpr;
begin begin
Result:=TBinaryExpr(CreateElement(TBinaryExpr,'',AParent)); Result:=CreateBinaryExpr(AParent,xleft,xright,AOpCode,CurSourcePos);
end;
function TPasParser.CreateBinaryExpr(AParent: TPasElement; xleft,
xright: TPasExpr; AOpCode: TExprOpCode; const ASrcPos: TPasSourcePos
): TBinaryExpr;
begin
Result:=TBinaryExpr(CreateElement(TBinaryExpr,'',AParent,ASrcPos));
Result.OpCode:=AOpCode; Result.OpCode:=AOpCode;
Result.Kind:=pekBinary; Result.Kind:=pekBinary;
if xleft<>nil then if xleft<>nil then
@ -6187,7 +6216,13 @@ end;
function TPasParser.CreateUnaryExpr(AParent: TPasElement; AOperand: TPasExpr; function TPasParser.CreateUnaryExpr(AParent: TPasElement; AOperand: TPasExpr;
AOpCode: TExprOpCode): TUnaryExpr; AOpCode: TExprOpCode): TUnaryExpr;
begin begin
Result:=TUnaryExpr(CreateElement(TUnaryExpr,'',AParent,CurTokenPos)); Result:=CreateUnaryExpr(AParent,AOperand,AOpCode,CurTokenPos);
end;
function TPasParser.CreateUnaryExpr(AParent: TPasElement; AOperand: TPasExpr;
AOpCode: TExprOpCode; const ASrcPos: TPasSourcePos): TUnaryExpr;
begin
Result:=TUnaryExpr(CreateElement(TUnaryExpr,'',AParent,ASrcPos));
Result.Kind:=pekUnary; Result.Kind:=pekUnary;
Result.Operand:=AOperand; Result.Operand:=AOperand;
Result.Operand.Parent:=Result; Result.Operand.Parent:=Result;

View File

@ -493,6 +493,8 @@ type
FileName: String; FileName: String;
Row, Column: Cardinal; Row, Column: Cardinal;
end; end;
const
DefPasSourcePos: TPasSourcePos = (Filename:''; Row:0; Column:0);
type type
{ TPascalScanner } { TPascalScanner }

View File

@ -6954,7 +6954,7 @@ begin
Add(' Some: longint;'); Add(' Some: longint;');
Add(' end;'); Add(' end;');
Add('begin'); Add('begin');
CheckResolverException('Duplicate identifier "Some" at afile.pp(5,9)',nDuplicateIdentifier); CheckResolverException('Duplicate identifier "Some" at afile.pp(5,5)',nDuplicateIdentifier);
end; end;
procedure TTestResolver.TestClass_ReintroducePrivateVar; procedure TTestResolver.TestClass_ReintroducePrivateVar;

View File

@ -1119,8 +1119,8 @@ type
ForLoop: TPasImplForLoop; ForLoop: TPasImplForLoop;
LoopVar: TPasElement; LoopVar: TPasElement;
FoundLoop: boolean; FoundLoop: boolean;
LoopVarWrite: boolean; // true if first acces of LoopVar after loop is a write LoopVarWrite: boolean; // true if first access of LoopVar after loop is a write
LoopVarRead: boolean; // true if first acces of LoopVar after loop is a read LoopVarRead: boolean; // true if first access of LoopVar after loop is a read
end; end;
PForLoopFindData = ^TForLoopFindData; PForLoopFindData = ^TForLoopFindData;
procedure ForLoop_OnProcBodyElement(El: TPasElement; arg: pointer); procedure ForLoop_OnProcBodyElement(El: TPasElement; arg: pointer);

View File

@ -9289,7 +9289,7 @@ begin
Add(' Id: longint;'); Add(' Id: longint;');
Add(' end;'); Add(' end;');
Add('begin'); Add('begin');
SetExpectedPasResolverError('Duplicate identifier "Id" at test1.pp(6,7)',nDuplicateIdentifier); SetExpectedPasResolverError('Duplicate identifier "Id" at test1.pp(6,5)',nDuplicateIdentifier);
ConvertProgram; ConvertProgram;
end; end;

View File

@ -56,6 +56,7 @@ type
procedure TestEmptyProgram; procedure TestEmptyProgram;
procedure TestEmptyUnit; procedure TestEmptyUnit;
procedure TestIf; procedure TestIf;
procedure TestFor;
end; end;
implementation implementation
@ -91,13 +92,14 @@ begin
end; end;
procedure TCustomTestSrcMap.CheckSrcMap(const aTitle: string); procedure TCustomTestSrcMap.CheckSrcMap(const aTitle: string);
{$IFDEF VerbosePas2JS}
var var
i: Integer; i: Integer;
{$ENDIF}
begin begin
{$IFDEF VerbosePas2JS} {$IFDEF VerbosePas2JS}
writeln('TCustomTestSrcMap.CheckSrcMap ',aTitle); writeln('TCustomTestSrcMap.CheckSrcMap ',aTitle);
{$ENDIF} {for i:=0 to SrcMap.Count-1 do
for i:=0 to SrcMap.Count-1 do
begin begin
write('TCustomTestSrcMap.CheckSrcMap i=',i,' Gen=', write('TCustomTestSrcMap.CheckSrcMap i=',i,' Gen=',
SrcMap[i].GeneratedLine,',',SrcMap[i].GeneratedColumn); SrcMap[i].GeneratedLine,',',SrcMap[i].GeneratedColumn);
@ -105,10 +107,12 @@ begin
if SrcMap[i].SrcFileIndex>0 then if SrcMap[i].SrcFileIndex>0 then
write(SrcMap.SourceFiles[SrcMap[i].SrcFileIndex],','); write(SrcMap.SourceFiles[SrcMap[i].SrcFileIndex],',');
writeln(SrcMap[i].SrcLine,',',SrcMap[i].SrcColumn); writeln(SrcMap[i].SrcLine,',',SrcMap[i].SrcColumn);
end; end;}
for i:=1 to JSSource.Count do for i:=1 to JSSource.Count do
WriteSrcMapLine(i); WriteSrcMapLine(i);
writeln('......012345678901234567890123456789012345678901234567890123456789');
WriteSources(Filename,1,1); WriteSources(Filename,1,1);
{$ENDIF}
end; end;
procedure TCustomTestSrcMap.WriteSrcMapLine(GeneratedLine: integer); procedure TCustomTestSrcMap.WriteSrcMapLine(GeneratedLine: integer);
@ -234,6 +238,19 @@ begin
CheckSrcMap('TestEmptyProgram'); CheckSrcMap('TestEmptyProgram');
end; end;
procedure TTestSrcMap.TestFor;
begin
StartProgram(false);
Add([
'var Runner, i: longint;',
'begin',
' for Runner := 1000 + 2000 to 3000 do',
' inc(i);',
'']);
ConvertProgram;
CheckSrcMap('TestEmptyProgram');
end;
Initialization Initialization
RegisterTests([TTestSrcMap]); RegisterTests([TTestSrcMap]);