mirror of https://github.com/red-prig/fpPS4.git
more CFG
This commit is contained in:
parent
5b701a35d1
commit
e8dc073341
|
@ -124,6 +124,7 @@ type
|
||||||
|
|
||||||
TsrSourceGoto=class(TsrSourceNode)
|
TsrSourceGoto=class(TsrSourceNode)
|
||||||
FGoto:record
|
FGoto:record
|
||||||
|
pParent:Pointer;
|
||||||
pPrev,pNext:TsrSourceGoto;
|
pPrev,pNext:TsrSourceGoto;
|
||||||
end;
|
end;
|
||||||
//
|
//
|
||||||
|
@ -144,7 +145,7 @@ type
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
TsrBlockType=(btMain,btSetpc,btCond,btElse,btLoop,btMerg,btExec,btInline,btOther);
|
TsrBlockType=(btMain,btSetpc,btCond,btElse,btLoop,btMerg,btInline,btOther);
|
||||||
|
|
||||||
TsrSourceBlock=class(TsrSourceNode)
|
TsrSourceBlock=class(TsrSourceNode)
|
||||||
FList:TsrSourceNodeList;
|
FList:TsrSourceNodeList;
|
||||||
|
@ -196,6 +197,8 @@ type
|
||||||
pCurr:TsrSourceNode;
|
pCurr:TsrSourceNode;
|
||||||
order:PtrUint;
|
order:PtrUint;
|
||||||
VarId:Ptruint;
|
VarId:Ptruint;
|
||||||
|
mode :Integer;
|
||||||
|
hits :Integer;
|
||||||
//
|
//
|
||||||
FLabelTree:TsrSourceLabelTree;
|
FLabelTree:TsrSourceLabelTree;
|
||||||
FInstructionTree:TsrSourceInstructionTree;
|
FInstructionTree:TsrSourceInstructionTree;
|
||||||
|
@ -207,6 +210,7 @@ type
|
||||||
Function NewGoto (Cond:TsrCondition;Adr:TSrcAdr):TsrSourceGoto;
|
Function NewGoto (Cond:TsrCondition;Adr:TSrcAdr):TsrSourceGoto;
|
||||||
Function NewGoto (pCond:TsrStatement;pLabel:TsrSourceLabel):TsrSourceGoto;
|
Function NewGoto (pCond:TsrStatement;pLabel:TsrSourceLabel):TsrSourceGoto;
|
||||||
procedure FreeGoto (node:TsrSourceGoto);
|
procedure FreeGoto (node:TsrSourceGoto);
|
||||||
|
procedure RestoreGoto (node:TsrSourceGoto);
|
||||||
Function NewBlock (bType:TsrBlockType):TsrSourceBlock;
|
Function NewBlock (bType:TsrBlockType):TsrSourceBlock;
|
||||||
//
|
//
|
||||||
Function NewCond (cond:TsrCondition):TsrStatement;
|
Function NewCond (cond:TsrCondition):TsrStatement;
|
||||||
|
@ -223,12 +227,13 @@ type
|
||||||
procedure EmitLabels;
|
procedure EmitLabels;
|
||||||
procedure GotoPass;
|
procedure GotoPass;
|
||||||
procedure InitMovePass;
|
procedure InitMovePass;
|
||||||
procedure RemoveGoto(goto_stmt:TsrSourceGoto;simple_pass:Boolean);
|
procedure RemoveGoto(goto_stmt:TsrSourceGoto);
|
||||||
procedure EliminateAsConditional(goto_stmt:TsrSourceGoto);
|
procedure EliminateAsConditional(goto_stmt:TsrSourceGoto);
|
||||||
procedure EliminateAsLoop (goto_stmt:TsrSourceGoto);
|
procedure EliminateAsLoop (goto_stmt:TsrSourceGoto);
|
||||||
function MoveOutward (goto_stmt:TsrSourceGoto):TsrSourceGoto;
|
function MoveOutward (goto_stmt:TsrSourceGoto):TsrSourceGoto;
|
||||||
function MoveOutwardIf (goto_stmt:TsrSourceGoto):TsrSourceGoto;
|
function MoveOutwardIf (goto_stmt:TsrSourceGoto):TsrSourceGoto;
|
||||||
function MoveOutwardElse (goto_stmt:TsrSourceGoto):TsrSourceGoto;
|
function MoveOutwardElse (goto_stmt:TsrSourceGoto):TsrSourceGoto;
|
||||||
|
function MoveOutwardElseElse (goto_stmt:TsrSourceGoto):TsrSourceGoto;
|
||||||
function MoveOutwardLoop (goto_stmt:TsrSourceGoto):TsrSourceGoto;
|
function MoveOutwardLoop (goto_stmt:TsrSourceGoto):TsrSourceGoto;
|
||||||
function MoveOutwardSwitch (goto_stmt:TsrSourceGoto):TsrSourceGoto;
|
function MoveOutwardSwitch (goto_stmt:TsrSourceGoto):TsrSourceGoto;
|
||||||
function MoveInward (goto_stmt:TsrSourceGoto):TsrSourceGoto;
|
function MoveInward (goto_stmt:TsrSourceGoto):TsrSourceGoto;
|
||||||
|
@ -301,6 +306,8 @@ end;
|
||||||
|
|
||||||
procedure TsrGotoList.Push_head(Node:TsrSourceGoto);
|
procedure TsrGotoList.Push_head(Node:TsrSourceGoto);
|
||||||
begin
|
begin
|
||||||
|
Assert(Node.FGoto.pParent=nil);
|
||||||
|
//
|
||||||
if (pHead=nil) then
|
if (pHead=nil) then
|
||||||
begin
|
begin
|
||||||
pTail:=node;
|
pTail:=node;
|
||||||
|
@ -312,10 +319,14 @@ begin
|
||||||
end;
|
end;
|
||||||
node.FGoto.pPrev:=nil;
|
node.FGoto.pPrev:=nil;
|
||||||
pHead:=node;
|
pHead:=node;
|
||||||
|
//
|
||||||
|
Node.FGoto.pParent:=@Self;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsrGotoList.Push_tail(Node:TsrSourceGoto);
|
procedure TsrGotoList.Push_tail(Node:TsrSourceGoto);
|
||||||
begin
|
begin
|
||||||
|
Assert(Node.FGoto.pParent=nil);
|
||||||
|
//
|
||||||
if (pTail=nil) then
|
if (pTail=nil) then
|
||||||
begin
|
begin
|
||||||
pHead:=node;
|
pHead:=node;
|
||||||
|
@ -327,10 +338,14 @@ begin
|
||||||
end;
|
end;
|
||||||
node.FGoto.pNext:=nil;
|
node.FGoto.pNext:=nil;
|
||||||
pTail:=node;
|
pTail:=node;
|
||||||
|
//
|
||||||
|
Node.FGoto.pParent:=@Self;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsrGotoList.InsertAfter(node,new:TsrSourceGoto);
|
procedure TsrGotoList.InsertAfter(node,new:TsrSourceGoto);
|
||||||
begin
|
begin
|
||||||
|
Assert(new.FGoto.pParent=nil);
|
||||||
|
//
|
||||||
new.FGoto.pPrev:=node;
|
new.FGoto.pPrev:=node;
|
||||||
if (node.FGoto.pNext=nil) then
|
if (node.FGoto.pNext=nil) then
|
||||||
begin
|
begin
|
||||||
|
@ -343,10 +358,14 @@ begin
|
||||||
node.FGoto.pNext.FGoto.pPrev:=new;
|
node.FGoto.pNext.FGoto.pPrev:=new;
|
||||||
end;
|
end;
|
||||||
node.FGoto.pNext:=new;
|
node.FGoto.pNext:=new;
|
||||||
|
//
|
||||||
|
new.FGoto.pParent:=@Self;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsrGotoList.InsertBefore(node,new:TsrSourceGoto);
|
procedure TsrGotoList.InsertBefore(node,new:TsrSourceGoto);
|
||||||
begin
|
begin
|
||||||
|
Assert(new.FGoto.pParent=nil);
|
||||||
|
//
|
||||||
new.FGoto.pNext:=node;
|
new.FGoto.pNext:=node;
|
||||||
if (node.FGoto.pPrev=nil) then
|
if (node.FGoto.pPrev=nil) then
|
||||||
begin
|
begin
|
||||||
|
@ -359,6 +378,8 @@ begin
|
||||||
node.FGoto.pPrev.FGoto.pNext:=new;
|
node.FGoto.pPrev.FGoto.pNext:=new;
|
||||||
end;
|
end;
|
||||||
node.FGoto.pPrev:=new;
|
node.FGoto.pPrev:=new;
|
||||||
|
//
|
||||||
|
new.FGoto.pParent:=@Self;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TsrGotoList.Pop_tail:TsrSourceGoto;
|
function TsrGotoList.Pop_tail:TsrSourceGoto;
|
||||||
|
@ -379,11 +400,15 @@ begin
|
||||||
end;
|
end;
|
||||||
Result.FGoto.pPrev:=nil;
|
Result.FGoto.pPrev:=nil;
|
||||||
Result.FGoto.pNext:=nil;
|
Result.FGoto.pNext:=nil;
|
||||||
|
//
|
||||||
|
Result.FGoto.pParent:=nil;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsrGotoList.Remove(node:TsrSourceGoto);
|
procedure TsrGotoList.Remove(node:TsrSourceGoto);
|
||||||
begin
|
begin
|
||||||
|
Assert(node.FGoto.pParent=@Self);
|
||||||
|
//
|
||||||
if (node.FGoto.pPrev=nil) then
|
if (node.FGoto.pPrev=nil) then
|
||||||
begin
|
begin
|
||||||
if (pHead=node) then
|
if (pHead=node) then
|
||||||
|
@ -408,6 +433,8 @@ begin
|
||||||
end;
|
end;
|
||||||
node.FGoto.pPrev:=nil;
|
node.FGoto.pPrev:=nil;
|
||||||
node.FGoto.pNext:=nil;
|
node.FGoto.pNext:=nil;
|
||||||
|
//
|
||||||
|
node.FGoto.pParent:=nil;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -578,7 +605,10 @@ end;
|
||||||
|
|
||||||
procedure TsrCFGParser2.FreeGoto(node:TsrSourceGoto);
|
procedure TsrCFGParser2.FreeGoto(node:TsrSourceGoto);
|
||||||
begin
|
begin
|
||||||
FGotoList.Remove(node);
|
if (node.FGoto.pParent<>nil) then
|
||||||
|
begin
|
||||||
|
FGotoList.Remove(node);
|
||||||
|
end;
|
||||||
if (node.pParent<>nil) then
|
if (node.pParent<>nil) then
|
||||||
begin
|
begin
|
||||||
node.pParent.Remove(node);
|
node.pParent.Remove(node);
|
||||||
|
@ -586,6 +616,14 @@ begin
|
||||||
FGotoFree.Push_tail(node);
|
FGotoFree.Push_tail(node);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TsrCFGParser2.RestoreGoto(node:TsrSourceGoto);
|
||||||
|
begin
|
||||||
|
if (node.FGoto.pParent=nil) then
|
||||||
|
begin
|
||||||
|
FGotoList.Push_tail(node);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
Function TsrCFGParser2.NewBlock(bType:TsrBlockType):TsrSourceBlock;
|
Function TsrCFGParser2.NewBlock(bType:TsrBlockType):TsrSourceBlock;
|
||||||
begin
|
begin
|
||||||
Result:=FEmit.specialize New<TsrSourceBlock>;
|
Result:=FEmit.specialize New<TsrSourceBlock>;
|
||||||
|
@ -865,24 +903,6 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function flow_next_up(node:TsrSourceNode):TsrSourceNode;
|
|
||||||
begin
|
|
||||||
repeat //up
|
|
||||||
Result:=node.pNext;
|
|
||||||
node:=node.pParent;
|
|
||||||
until (node=nil) or (Result<>nil);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function flow_down_next(node:TsrSourceNode):TsrSourceNode;
|
|
||||||
begin
|
|
||||||
Result:=node.First; //down
|
|
||||||
if (Result=nil) then
|
|
||||||
begin
|
|
||||||
//next
|
|
||||||
Result:=node.pNext;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TsrCFGParser2.EmitLabels;
|
procedure TsrCFGParser2.EmitLabels;
|
||||||
var
|
var
|
||||||
node:TsrSourceGoto;
|
node:TsrSourceGoto;
|
||||||
|
@ -1018,16 +1038,8 @@ procedure TsrCFGParser2.GotoPass;
|
||||||
var
|
var
|
||||||
node,next:TsrSourceGoto;
|
node,next:TsrSourceGoto;
|
||||||
begin
|
begin
|
||||||
node:=FGotoList.pHead;
|
mode:=0;
|
||||||
//
|
hits:=0;
|
||||||
while (node<>nil) do
|
|
||||||
begin
|
|
||||||
next:=node.FGoto.pNext;
|
|
||||||
//
|
|
||||||
RemoveGoto(node,True);
|
|
||||||
//
|
|
||||||
node:=next;
|
|
||||||
end;
|
|
||||||
//
|
//
|
||||||
node:=FGotoList.pHead;
|
node:=FGotoList.pHead;
|
||||||
//
|
//
|
||||||
|
@ -1035,14 +1047,43 @@ begin
|
||||||
begin
|
begin
|
||||||
next:=node.FGoto.pNext;
|
next:=node.FGoto.pNext;
|
||||||
//
|
//
|
||||||
RemoveGoto(node,False);
|
RemoveGoto(node);
|
||||||
//
|
//
|
||||||
node:=next;
|
node:=next;
|
||||||
end;
|
end;
|
||||||
//
|
//
|
||||||
|
repeat
|
||||||
|
mode:=1;
|
||||||
|
hits:=0;
|
||||||
|
//
|
||||||
|
node:=FGotoList.pHead;
|
||||||
|
//
|
||||||
|
while (node<>nil) do
|
||||||
|
begin
|
||||||
|
next:=node.FGoto.pNext;
|
||||||
|
//
|
||||||
|
RemoveGoto(node);
|
||||||
|
//
|
||||||
|
node:=next;
|
||||||
|
end;
|
||||||
|
//
|
||||||
|
until (hits=0);
|
||||||
|
//
|
||||||
|
mode:=2;
|
||||||
|
//
|
||||||
|
node:=FGotoList.pHead;
|
||||||
|
//
|
||||||
|
while (node<>nil) do
|
||||||
|
begin
|
||||||
|
next:=node.FGoto.pNext;
|
||||||
|
//
|
||||||
|
RemoveGoto(node);
|
||||||
|
//
|
||||||
|
node:=next;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure MoveListBefore(List:TsrSourceNodeList;before:TsrSourceNode);
|
procedure MoveListBefore(var List:TsrSourceNodeList;before:TsrSourceNode);
|
||||||
var
|
var
|
||||||
node:TsrSourceNode;
|
node:TsrSourceNode;
|
||||||
begin
|
begin
|
||||||
|
@ -1090,6 +1131,24 @@ begin
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Function NextUsedFlowUp(node:TsrSourceNode):TsrSourceNode;
|
Function NextUsedFlowUp(node:TsrSourceNode):TsrSourceNode;
|
||||||
|
|
||||||
|
function flow_next_up(node:TsrSourceNode):TsrSourceNode;
|
||||||
|
begin
|
||||||
|
repeat //up
|
||||||
|
Result:=node.pNext;
|
||||||
|
node:=node.pParent;
|
||||||
|
//exclude "else"
|
||||||
|
if (Result<>nil) then
|
||||||
|
if (node<>nil) then
|
||||||
|
if (node.ntype=TsrSourceBlock) then
|
||||||
|
if (TsrSourceBlock(node).bType=btMerg) then
|
||||||
|
begin
|
||||||
|
Result:=nil;
|
||||||
|
end;
|
||||||
|
//
|
||||||
|
until (node=nil) or (Result<>nil);
|
||||||
|
end;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Result:=flow_next_up(node);
|
Result:=flow_next_up(node);
|
||||||
while (Result<>nil) do
|
while (Result<>nil) do
|
||||||
|
@ -1107,6 +1166,17 @@ begin
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Function NextUsedFlowDown(node:TsrSourceNode):TsrSourceNode;
|
Function NextUsedFlowDown(node:TsrSourceNode):TsrSourceNode;
|
||||||
|
|
||||||
|
function flow_down_next(node:TsrSourceNode):TsrSourceNode;
|
||||||
|
begin
|
||||||
|
Result:=node.First; //down
|
||||||
|
if (Result=nil) then
|
||||||
|
begin
|
||||||
|
//next
|
||||||
|
Result:=node.pNext;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Result:=flow_down_next(node);
|
Result:=flow_down_next(node);
|
||||||
while (Result<>nil) do
|
while (Result<>nil) do
|
||||||
|
@ -1123,7 +1193,7 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsrCFGParser2.RemoveGoto(goto_stmt:TsrSourceGoto;simple_pass:Boolean);
|
procedure TsrCFGParser2.RemoveGoto(goto_stmt:TsrSourceGoto);
|
||||||
var
|
var
|
||||||
label_stmt:TsrSourceLabel;
|
label_stmt:TsrSourceLabel;
|
||||||
label_level,goto_level:DWORD;
|
label_level,goto_level:DWORD;
|
||||||
|
@ -1132,7 +1202,7 @@ begin
|
||||||
label_stmt:=goto_stmt.pLabel;
|
label_stmt:=goto_stmt.pLabel;
|
||||||
if (IsIndirectlyRelated(goto_stmt, label_stmt)) then
|
if (IsIndirectlyRelated(goto_stmt, label_stmt)) then
|
||||||
begin
|
begin
|
||||||
if simple_pass then Exit;
|
if (mode=0) then Exit;
|
||||||
// Move goto_stmt out using outward-movement transformation until it becomes
|
// Move goto_stmt out using outward-movement transformation until it becomes
|
||||||
// directly related to label_stmt
|
// directly related to label_stmt
|
||||||
while (not IsDirectlyRelated(goto_stmt, label_stmt)) do
|
while (not IsDirectlyRelated(goto_stmt, label_stmt)) do
|
||||||
|
@ -1147,18 +1217,20 @@ begin
|
||||||
goto_level :=Level(goto_stmt);
|
goto_level :=Level(goto_stmt);
|
||||||
if (goto_level > label_level) then
|
if (goto_level > label_level) then
|
||||||
begin
|
begin
|
||||||
if simple_pass then Exit;
|
if (mode=0) then Exit;
|
||||||
// Move goto_stmt out of its level using outward-movement transformations
|
// Move goto_stmt out of its level using outward-movement transformations
|
||||||
while (goto_level > label_level) do
|
while (goto_level > label_level) do
|
||||||
begin
|
begin
|
||||||
goto_stmt:=MoveOutward(goto_stmt);
|
goto_stmt:=MoveOutward(goto_stmt);
|
||||||
|
//deffered
|
||||||
|
if (goto_stmt=nil) then Exit;
|
||||||
//Dec(goto_level);
|
//Dec(goto_level);
|
||||||
goto_level:=Level(goto_stmt);
|
goto_level:=Level(goto_stmt);
|
||||||
end;
|
end;
|
||||||
end else
|
end else
|
||||||
if (goto_level < label_level) then
|
if (goto_level < label_level) then
|
||||||
begin
|
begin
|
||||||
if simple_pass then Exit;
|
if (mode<2) then Exit;
|
||||||
//
|
//
|
||||||
if (NeedsLift(goto_stmt, label_stmt)) then
|
if (NeedsLift(goto_stmt, label_stmt)) then
|
||||||
begin
|
begin
|
||||||
|
@ -1247,10 +1319,50 @@ begin
|
||||||
|
|
||||||
if_stmt.pCond:=neg_cond;
|
if_stmt.pCond:=neg_cond;
|
||||||
|
|
||||||
|
Inc(hits);
|
||||||
|
|
||||||
//
|
//
|
||||||
FreeGoto(goto_stmt);
|
FreeGoto(goto_stmt);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function SanitizeNoBreaks(node_first,node_last:TsrSourceNode):Boolean;
|
||||||
|
var
|
||||||
|
node,next:TsrSourceNode;
|
||||||
|
begin
|
||||||
|
Result:=True;
|
||||||
|
node:=node_first;
|
||||||
|
|
||||||
|
while (node<>nil) and (node<>node_last) do
|
||||||
|
begin
|
||||||
|
|
||||||
|
if (node.ntype=TsrStatement) then
|
||||||
|
begin
|
||||||
|
if (TsrStatement(node).sType=sBreak) then
|
||||||
|
begin
|
||||||
|
Exit(False);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
next:=node.First; //down
|
||||||
|
|
||||||
|
if (next<>nil) then
|
||||||
|
if (TsrSourceBlock(node).bType=btLoop) then
|
||||||
|
begin
|
||||||
|
next:=nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if (next=nil) then
|
||||||
|
begin
|
||||||
|
repeat //up
|
||||||
|
next:=node.pNext;
|
||||||
|
node:=node.pParent;
|
||||||
|
until (node=nil) or (next<>nil) or (node=node_last);
|
||||||
|
end;
|
||||||
|
|
||||||
|
node:=next;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TsrCFGParser2.EliminateAsLoop(goto_stmt:TsrSourceGoto);
|
procedure TsrCFGParser2.EliminateAsLoop(goto_stmt:TsrSourceGoto);
|
||||||
var
|
var
|
||||||
label_stmt:TsrSourceLabel;
|
label_stmt:TsrSourceLabel;
|
||||||
|
@ -1259,6 +1371,11 @@ var
|
||||||
begin
|
begin
|
||||||
label_stmt:=goto_stmt.pLabel;
|
label_stmt:=goto_stmt.pLabel;
|
||||||
|
|
||||||
|
if not SanitizeNoBreaks(label_stmt, goto_stmt) then
|
||||||
|
begin
|
||||||
|
Assert(false,'SanitizeNoBreaks:EliminateAsLoop');
|
||||||
|
end;
|
||||||
|
|
||||||
loop_stmt:=NewBlock(btLoop);
|
loop_stmt:=NewBlock(btLoop);
|
||||||
loop_stmt.splice(label_stmt,goto_stmt);
|
loop_stmt.splice(label_stmt,goto_stmt);
|
||||||
|
|
||||||
|
@ -1268,6 +1385,8 @@ begin
|
||||||
|
|
||||||
loop_stmt.pCond:=cond;
|
loop_stmt.pCond:=cond;
|
||||||
|
|
||||||
|
Inc(hits);
|
||||||
|
|
||||||
//
|
//
|
||||||
FreeGoto(goto_stmt);
|
FreeGoto(goto_stmt);
|
||||||
end;
|
end;
|
||||||
|
@ -1321,18 +1440,19 @@ var
|
||||||
parent:TsrSourceBlock;
|
parent:TsrSourceBlock;
|
||||||
begin
|
begin
|
||||||
Result:=False;
|
Result:=False;
|
||||||
|
|
||||||
|
parent:=goto_stmt.pParent;
|
||||||
|
if (parent=nil) then Exit;
|
||||||
|
|
||||||
|
if (parent.bType=btCond) then
|
||||||
if IsUnconditional(goto_stmt.pCond) then
|
if IsUnconditional(goto_stmt.pCond) then
|
||||||
if (NextUsed(goto_stmt)=nil) then
|
if (NextUsed(goto_stmt)=nil) then
|
||||||
if (goto_stmt.pParent<>nil) then
|
|
||||||
if (goto_stmt.pParent.bType=btCond) then
|
|
||||||
begin
|
begin
|
||||||
parent:=goto_stmt.pParent;
|
|
||||||
parent:=parent.pParent;
|
parent:=parent.pParent;
|
||||||
if (parent<>nil) then
|
if (parent<>nil) then
|
||||||
if (parent.bType=btMerg) then
|
if (parent.bType=btMerg) then
|
||||||
if (NextUsed(parent)<>goto_stmt.pLabel) then
|
|
||||||
begin
|
begin
|
||||||
Result:=AreOrdered(parent,goto_stmt.pLabel);
|
Result:=True;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
@ -1365,7 +1485,25 @@ begin
|
||||||
end else
|
end else
|
||||||
if AreSiblings(parent,label_stmt) then
|
if AreSiblings(parent,label_stmt) then
|
||||||
begin
|
begin
|
||||||
Exit(True);
|
|
||||||
|
if (parent.pParent<>nil) then
|
||||||
|
if (parent.pParent.bType=btMerg) then
|
||||||
|
begin
|
||||||
|
parent:=parent.pParent;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if (NextUsedFlowUp(parent)=label_stmt) then
|
||||||
|
begin
|
||||||
|
Exit(False);
|
||||||
|
end else
|
||||||
|
if SanitizeNoBreaks(parent,label_stmt) then
|
||||||
|
begin
|
||||||
|
Exit(True);
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
Exit(False);
|
||||||
|
end;
|
||||||
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
parent:=parent.pParent;
|
parent:=parent.pParent;
|
||||||
|
@ -1388,11 +1526,13 @@ begin
|
||||||
Exit(MoveOutwardElse(goto_stmt));
|
Exit(MoveOutwardElse(goto_stmt));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
if (mode=2) then
|
||||||
if IsBreakSwitch(goto_stmt) then
|
if IsBreakSwitch(goto_stmt) then
|
||||||
begin
|
begin
|
||||||
Exit(MoveOutwardSwitch(goto_stmt));
|
Exit(MoveOutwardSwitch(goto_stmt));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
if IsBreakLoop(goto_stmt) then
|
if IsBreakLoop(goto_stmt) then
|
||||||
begin
|
begin
|
||||||
Exit(MoveOutwardLoop(goto_stmt));
|
Exit(MoveOutwardLoop(goto_stmt));
|
||||||
|
@ -1427,7 +1567,7 @@ end;
|
||||||
L1:
|
L1:
|
||||||
stmt_n;
|
stmt_n;
|
||||||
}
|
}
|
||||||
//-->
|
//--> normal
|
||||||
{
|
{
|
||||||
....
|
....
|
||||||
goto_L1 = false;
|
goto_L1 = false;
|
||||||
|
@ -1448,7 +1588,7 @@ end;
|
||||||
L1:
|
L1:
|
||||||
stmt_n;
|
stmt_n;
|
||||||
}
|
}
|
||||||
//-->
|
//--> no body
|
||||||
{
|
{
|
||||||
....
|
....
|
||||||
goto_L1 = false;
|
goto_L1 = false;
|
||||||
|
@ -1463,6 +1603,20 @@ end;
|
||||||
L1:
|
L1:
|
||||||
stmt_n;
|
stmt_n;
|
||||||
}
|
}
|
||||||
|
//--> no body, no cond, "if" body -> "else"
|
||||||
|
{
|
||||||
|
....
|
||||||
|
if (expr)
|
||||||
|
{
|
||||||
|
stmt_1;
|
||||||
|
....
|
||||||
|
----
|
||||||
|
}
|
||||||
|
if (expr) goto L1;
|
||||||
|
....
|
||||||
|
L1:
|
||||||
|
stmt_n;
|
||||||
|
}
|
||||||
|
|
||||||
function TsrCFGParser2.MoveOutwardIf(goto_stmt:TsrSourceGoto):TsrSourceGoto;
|
function TsrCFGParser2.MoveOutwardIf(goto_stmt:TsrSourceGoto):TsrSourceGoto;
|
||||||
var
|
var
|
||||||
|
@ -1488,9 +1642,36 @@ begin
|
||||||
|
|
||||||
if (NextUsedFlowUp(pmerge)<>label_stmt) then
|
if (NextUsedFlowUp(pmerge)<>label_stmt) then
|
||||||
begin
|
begin
|
||||||
|
|
||||||
|
if (mode<>2) then
|
||||||
|
begin
|
||||||
|
RestoreGoto(goto_stmt);
|
||||||
|
Exit(nil);
|
||||||
|
end;
|
||||||
|
|
||||||
|
//backup action
|
||||||
|
if (parent.bType=btCond) and
|
||||||
|
(IsUnconditional(goto_stmt.pCond)) and
|
||||||
|
(NextUsed(goto_stmt)=nil) then
|
||||||
|
begin
|
||||||
|
//else is detect
|
||||||
|
Exit(MoveOutwardElse(goto_stmt));
|
||||||
|
end;
|
||||||
|
|
||||||
|
//else goto up
|
||||||
|
if (parent.bType=btElse) and
|
||||||
|
(IsUnconditional(goto_stmt.pCond)) and
|
||||||
|
(NextUsed(goto_stmt)=nil) then
|
||||||
|
begin
|
||||||
|
//else in else
|
||||||
|
Exit(MoveOutwardElseElse(goto_stmt));
|
||||||
|
end;
|
||||||
|
|
||||||
new_var:=NewVar;
|
new_var:=NewVar;
|
||||||
end else
|
end else
|
||||||
begin
|
begin
|
||||||
|
Inc(hits);
|
||||||
|
|
||||||
//simplification
|
//simplification
|
||||||
new_var:=nil;
|
new_var:=nil;
|
||||||
end;
|
end;
|
||||||
|
@ -1582,11 +1763,11 @@ end;
|
||||||
{
|
{
|
||||||
stmt_1;
|
stmt_1;
|
||||||
....
|
....
|
||||||
|
----
|
||||||
} else {
|
} else {
|
||||||
stmt_2;
|
stmt_2;
|
||||||
goto L1;
|
|
||||||
}
|
}
|
||||||
|
if (expr) goto L1;
|
||||||
{
|
{
|
||||||
....
|
....
|
||||||
L1:
|
L1:
|
||||||
|
@ -1607,6 +1788,8 @@ begin
|
||||||
label_stmt:=goto_stmt.pLabel;
|
label_stmt:=goto_stmt.pLabel;
|
||||||
|
|
||||||
if_stmt:=goto_stmt.pParent;
|
if_stmt:=goto_stmt.pParent;
|
||||||
|
Assert(if_stmt<>nil);
|
||||||
|
|
||||||
pmerge:=if_stmt.pParent;
|
pmerge:=if_stmt.pParent;
|
||||||
Assert(pmerge<>nil);
|
Assert(pmerge<>nil);
|
||||||
Assert(pmerge.bType=btMerg);
|
Assert(pmerge.bType=btMerg);
|
||||||
|
@ -1614,28 +1797,142 @@ begin
|
||||||
cond:=goto_stmt.pCond;
|
cond:=goto_stmt.pCond;
|
||||||
Assert(IsUnconditional(cond));
|
Assert(IsUnconditional(cond));
|
||||||
|
|
||||||
if_else:=NewBlock(btElse);
|
if (mode<>2) then
|
||||||
if_else.pIf :=if_stmt;
|
begin
|
||||||
if_stmt.pElse:=if_else;
|
if not AreOrdered(pmerge,label_stmt) then
|
||||||
pmerge.InsertAfter(if_stmt,if_else);
|
begin
|
||||||
|
if (NextUsedFlowUp(pmerge.pParent.Last)<>label_stmt) then
|
||||||
|
begin
|
||||||
|
RestoreGoto(goto_stmt);
|
||||||
|
Exit(nil);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
Inc(hits);
|
||||||
|
end;
|
||||||
|
|
||||||
if_else.splice(pmerge.pNext,label_stmt);
|
if (NextUsed(pmerge)=nil) or
|
||||||
|
(NextUsedFlowUp(pmerge)=label_stmt) then
|
||||||
|
begin
|
||||||
|
//no else body
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
|
||||||
|
if_else:=NewBlock(btElse);
|
||||||
|
if_else.pIf :=if_stmt;
|
||||||
|
if_stmt.pElse:=if_else;
|
||||||
|
pmerge.InsertAfter(if_stmt,if_else);
|
||||||
|
|
||||||
|
if AreOrdered(pmerge,label_stmt) then
|
||||||
|
begin
|
||||||
|
if_else.splice(pmerge.pNext,label_stmt);
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
if_else.splice(pmerge.pNext,nil);
|
||||||
|
end;
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
//
|
//
|
||||||
FreeGoto(goto_stmt);
|
FreeGoto(goto_stmt);
|
||||||
//
|
//
|
||||||
|
|
||||||
goto_stmt:=TsrSourceGoto(if_else.Last);
|
//if (expr)
|
||||||
|
cond:=if_stmt.pCond;
|
||||||
|
|
||||||
if (goto_stmt<>nil) then
|
if (NextUsedFlowUp(pmerge)<>label_stmt) then
|
||||||
if (goto_stmt.ntype=TsrSourceGoto) then
|
|
||||||
if IsUnconditional(goto_stmt.pCond) then
|
|
||||||
begin
|
begin
|
||||||
Exit(goto_stmt);
|
cond:=NewCopy(cond);
|
||||||
|
pmerge.FInit.Push_tail(cond);
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
//simplification
|
||||||
|
Exit(nil);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
new_goto:=NewGoto(cond,label_stmt);
|
new_goto:=NewGoto(cond,label_stmt);
|
||||||
if_else.Push_tail(new_goto);
|
InsertAfter(pmerge,new_goto);
|
||||||
|
|
||||||
|
Result:=new_goto;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
//--> no body, no cond, "else" body
|
||||||
|
{
|
||||||
|
....
|
||||||
|
goto_L1 = false;
|
||||||
|
if (expr)
|
||||||
|
{
|
||||||
|
stmt_1;
|
||||||
|
....
|
||||||
|
} else {
|
||||||
|
....
|
||||||
|
----
|
||||||
|
}
|
||||||
|
if (!expr) goto L1;
|
||||||
|
....
|
||||||
|
L1:
|
||||||
|
stmt_n;
|
||||||
|
}
|
||||||
|
|
||||||
|
function TsrCFGParser2.MoveOutwardElseElse(goto_stmt:TsrSourceGoto):TsrSourceGoto;
|
||||||
|
var
|
||||||
|
label_stmt:TsrSourceLabel;
|
||||||
|
pmerge :TsrSourceBlock;
|
||||||
|
cond :TsrStatement;
|
||||||
|
new_goto :TsrSourceGoto;
|
||||||
|
if_else :TsrSourceBlock;
|
||||||
|
if_stmt :TsrSourceBlock;
|
||||||
|
begin
|
||||||
|
label_stmt:=goto_stmt.pLabel;
|
||||||
|
|
||||||
|
if_else:=goto_stmt.pParent;
|
||||||
|
Assert(if_else<>nil);
|
||||||
|
|
||||||
|
pmerge:=if_else.pParent;
|
||||||
|
Assert(pmerge<>nil);
|
||||||
|
Assert(pmerge.bType=btMerg);
|
||||||
|
|
||||||
|
if_stmt:=if_else.pIf;
|
||||||
|
Assert(if_stmt<>nil);
|
||||||
|
|
||||||
|
cond:=goto_stmt.pCond;
|
||||||
|
Assert(IsUnconditional(cond));
|
||||||
|
|
||||||
|
if (mode<>2) then
|
||||||
|
begin
|
||||||
|
if (NextUsedFlowUp(pmerge)<>label_stmt) then
|
||||||
|
begin
|
||||||
|
RestoreGoto(goto_stmt);
|
||||||
|
Exit(nil);
|
||||||
|
end;
|
||||||
|
Inc(hits);
|
||||||
|
end;
|
||||||
|
|
||||||
|
//
|
||||||
|
FreeGoto(goto_stmt);
|
||||||
|
//
|
||||||
|
|
||||||
|
//if (expr) else {}
|
||||||
|
cond:=if_stmt.pCond;
|
||||||
|
|
||||||
|
Assert(cond<>nil);
|
||||||
|
|
||||||
|
if (NextUsedFlowUp(pmerge)<>label_stmt) then
|
||||||
|
begin
|
||||||
|
//(!expr)
|
||||||
|
cond:=NewNot(cond);
|
||||||
|
pmerge.FInit.Push_tail(cond);
|
||||||
|
|
||||||
|
cond:=NewCopy(cond);
|
||||||
|
pmerge.FInit.Push_tail(cond);
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
//simplification
|
||||||
|
Exit(nil);
|
||||||
|
end;
|
||||||
|
|
||||||
|
new_goto:=NewGoto(cond,label_stmt);
|
||||||
|
InsertAfter(pmerge,new_goto);
|
||||||
|
|
||||||
Result:=new_goto;
|
Result:=new_goto;
|
||||||
end;
|
end;
|
||||||
|
@ -1696,6 +1993,13 @@ begin
|
||||||
|
|
||||||
if (NextUsedFlowUp(loop_parent)<>label_stmt) then
|
if (NextUsedFlowUp(loop_parent)<>label_stmt) then
|
||||||
begin
|
begin
|
||||||
|
|
||||||
|
if (mode<>2) then
|
||||||
|
begin
|
||||||
|
RestoreGoto(goto_stmt);
|
||||||
|
Exit(nil);
|
||||||
|
end;
|
||||||
|
|
||||||
new_var:=NewVar;
|
new_var:=NewVar;
|
||||||
|
|
||||||
//goto_L1 = false;
|
//goto_L1 = false;
|
||||||
|
@ -1703,6 +2007,8 @@ begin
|
||||||
loop_parent.FInit.Push_tail(set_var);
|
loop_parent.FInit.Push_tail(set_var);
|
||||||
end else
|
end else
|
||||||
begin
|
begin
|
||||||
|
Inc(hits);
|
||||||
|
|
||||||
//simplification
|
//simplification
|
||||||
new_var:=nil;
|
new_var:=nil;
|
||||||
end;
|
end;
|
||||||
|
@ -1761,44 +2067,6 @@ begin
|
||||||
Result:=new_goto;
|
Result:=new_goto;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function SanitizeNoBreaks(node_first,node_last:TsrSourceNode):Boolean;
|
|
||||||
var
|
|
||||||
node,next:TsrSourceNode;
|
|
||||||
begin
|
|
||||||
Result:=True;
|
|
||||||
node:=node_first;
|
|
||||||
|
|
||||||
while (node<>nil) and (node<>node_last) do
|
|
||||||
begin
|
|
||||||
|
|
||||||
if (node.ntype=TsrStatement) then
|
|
||||||
begin
|
|
||||||
if (TsrStatement(node).sType=sBreak) then
|
|
||||||
begin
|
|
||||||
Exit(False);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
next:=node.First; //down
|
|
||||||
|
|
||||||
if (next<>nil) then
|
|
||||||
if (TsrSourceBlock(node).bType=btLoop) then
|
|
||||||
begin
|
|
||||||
next:=nil;
|
|
||||||
end;
|
|
||||||
|
|
||||||
if (next=nil) then
|
|
||||||
begin
|
|
||||||
repeat //up
|
|
||||||
next:=node.pNext;
|
|
||||||
node:=node.pParent;
|
|
||||||
until (node=nil) or (next<>nil) or (node=node_last);
|
|
||||||
end;
|
|
||||||
|
|
||||||
node:=next;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
if (expr) {
|
if (expr) {
|
||||||
if (cond) goto L1;
|
if (cond) goto L1;
|
||||||
|
@ -2369,10 +2637,10 @@ begin
|
||||||
Result:='';
|
Result:='';
|
||||||
case node.sType of
|
case node.sType of
|
||||||
//sCond :'
|
//sCond :'
|
||||||
sCopy :Result:=GetCondStr(node.pDst)+' = '+GetCondStr(node.pSrc)+';';
|
sCopy :Result:=GetCondStr(node.pDst)+' = '+GetCondStr(node.pSrc)+'; //#'+IntToStr(node.order);
|
||||||
//sVar :'
|
//sVar :'
|
||||||
sStore:Result:=GetCondStr(node.pDst)+' = '+GetCondStr(node.pSrc)+';';
|
sStore:Result:=GetCondStr(node.pDst)+' = '+GetCondStr(node.pSrc)+'; //#'+IntToStr(node.order);
|
||||||
sBreak:Result:='break;';
|
sBreak:Result:='break; //#'+IntToStr(node.order);
|
||||||
//sNot :;
|
//sNot :;
|
||||||
//sOr :;
|
//sOr :;
|
||||||
//sAnd :;
|
//sAnd :;
|
||||||
|
@ -2418,6 +2686,7 @@ begin
|
||||||
case node.bType of
|
case node.bType of
|
||||||
btCond:Result:='if ('+GetCondStr(node.pCond)+') { //#'+IntToStr(node.order);
|
btCond:Result:='if ('+GetCondStr(node.pCond)+') { //#'+IntToStr(node.order);
|
||||||
btLoop:Result:='do { //#'+IntToStr(node.order);
|
btLoop:Result:='do { //#'+IntToStr(node.order);
|
||||||
|
//btMerg:Result:='merge { //#'+IntToStr(node.order);
|
||||||
else;
|
else;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
@ -2432,13 +2701,12 @@ begin
|
||||||
Result:='}; //if #'+IntToStr(node.order);;
|
Result:='}; //if #'+IntToStr(node.order);;
|
||||||
end else
|
end else
|
||||||
begin
|
begin
|
||||||
Result:='} else { //#'+IntToStr(node.order);
|
Result:='} else { //#'+IntToStr(node.order)+'-#'+IntToStr(node.pElse.order);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
btElse:Result:='}; //else #'+IntToStr(node.order);
|
btElse:Result:='}; //else #'+IntToStr(node.order);
|
||||||
btLoop:begin
|
btLoop:Result:='} while ('+GetCondStr(node.pCond)+'); //#'+IntToStr(node.order);
|
||||||
Result:='} while ('+GetCondStr(node.pCond)+'); //#'+IntToStr(node.order);
|
//btMerg:Result:='} //merge #'+IntToStr(node.order);
|
||||||
end;
|
|
||||||
else;
|
else;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
|
@ -253,6 +253,11 @@ var
|
||||||
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
Function IsUnconditional(cond:TsrStatement):Boolean; inline;
|
||||||
|
begin
|
||||||
|
Result:=(cond.sType=sCond) and (cond.u.cond=cTrue)
|
||||||
|
end;
|
||||||
|
|
||||||
Function IsUnreachable(cond:TsrStatement):Boolean; inline;
|
Function IsUnreachable(cond:TsrStatement):Boolean; inline;
|
||||||
begin
|
begin
|
||||||
Result:=(cond.sType=sCond) and (cond.u.cond=cFalse)
|
Result:=(cond.sType=sCond) and (cond.u.cond=cFalse)
|
||||||
|
@ -268,14 +273,27 @@ var
|
||||||
PrivateList.build_volatile_reset(pOpBlock.Regs.next);
|
PrivateList.build_volatile_reset(pOpBlock.Regs.next);
|
||||||
end else
|
end else
|
||||||
begin
|
begin
|
||||||
//calc break volatile state
|
|
||||||
PrivateList.build_volatile_break(pOpBlock.vctx,pOpBlock.Regs.orig,pOpBlock.Regs.prev,pOpBlock.Regs.next);
|
|
||||||
|
|
||||||
parent:=pOpBlock.FCursor.AsBlock;
|
parent:=pOpBlock.FCursor.AsBlock;
|
||||||
if (parent.pCond<>nil) then
|
|
||||||
if not IsUnreachable(parent.pCond) then
|
if (parent.pCond=nil) then
|
||||||
begin
|
begin
|
||||||
//have post conditions
|
//continue
|
||||||
|
PrivateList.build_volatile_conti(pOpBlock.vctx,pOpBlock.Regs.orig,pOpBlock.Regs.prev,pOpBlock.Regs.next);
|
||||||
|
end else
|
||||||
|
if IsUnconditional(parent.pCond) then
|
||||||
|
begin
|
||||||
|
//continue
|
||||||
|
PrivateList.build_volatile_conti(pOpBlock.vctx,pOpBlock.Regs.orig,pOpBlock.Regs.prev,pOpBlock.Regs.next);
|
||||||
|
end else
|
||||||
|
if IsUnreachable(parent.pCond) then
|
||||||
|
begin
|
||||||
|
//break
|
||||||
|
PrivateList.build_volatile_break(pOpBlock.vctx,pOpBlock.Regs.orig,pOpBlock.Regs.prev,pOpBlock.Regs.next);
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
//break
|
||||||
|
PrivateList.build_volatile_break(pOpBlock.vctx,pOpBlock.Regs.orig,pOpBlock.Regs.prev,pOpBlock.Regs.next);
|
||||||
|
//continue
|
||||||
PrivateList.build_volatile_conti(pOpBlock.vctx,pOpBlock.Regs.orig,pOpBlock.Regs.prev,pOpBlock.Regs.next);
|
PrivateList.build_volatile_conti(pOpBlock.vctx,pOpBlock.Regs.orig,pOpBlock.Regs.prev,pOpBlock.Regs.next);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -1065,8 +1083,7 @@ end;
|
||||||
|
|
||||||
function TEmitFlow.ParseStage(base:Pointer):Integer;
|
function TEmitFlow.ParseStage(base:Pointer):Integer;
|
||||||
label
|
label
|
||||||
_skip,
|
_skip;
|
||||||
_up;
|
|
||||||
var
|
var
|
||||||
next:TsrSourceNode;
|
next:TsrSourceNode;
|
||||||
FLevel:DWORD;
|
FLevel:DWORD;
|
||||||
|
@ -1087,13 +1104,15 @@ begin
|
||||||
//down
|
//down
|
||||||
while (Cursor.pNode.ntype=TsrSourceBlock) do
|
while (Cursor.pNode.ntype=TsrSourceBlock) do
|
||||||
begin
|
begin
|
||||||
BlockBeg;
|
|
||||||
next:=Cursor.pNode.First;
|
next:=Cursor.pNode.First;
|
||||||
if (next=nil) then
|
if (next=nil) then
|
||||||
begin
|
begin
|
||||||
//up
|
//up
|
||||||
goto _up;
|
goto _skip;
|
||||||
end;
|
end;
|
||||||
|
//
|
||||||
|
BlockBeg;
|
||||||
|
//
|
||||||
Cursor.pNode:=next;
|
Cursor.pNode:=next;
|
||||||
Cursor.UpdateAdr;
|
Cursor.UpdateAdr;
|
||||||
end;
|
end;
|
||||||
|
@ -1152,7 +1171,6 @@ begin
|
||||||
(Cursor.pNode.pParent<>nil) and
|
(Cursor.pNode.pParent<>nil) and
|
||||||
(Cursor.pNode.pParent<>Cursor.pCode.FTop) do
|
(Cursor.pNode.pParent<>Cursor.pCode.FTop) do
|
||||||
begin
|
begin
|
||||||
_up:
|
|
||||||
//up
|
//up
|
||||||
BlockEnd; //"Cursor.pNode:=Cursor.pNode.pParent" in "PopBlockOp"
|
BlockEnd; //"Cursor.pNode:=Cursor.pNode.pParent" in "PopBlockOp"
|
||||||
//
|
//
|
||||||
|
|
Loading…
Reference in New Issue