View Issue Details

IDProjectCategoryView StatusLast Update
0016931FPCPackagespublic2011-07-23 16:45
ReporterDmitry Boyarintsev Assigned ToMichael Van Canneyt  
PrioritynormalSeverityminorReproducibilityhave not tried
Status closedResolutionfixed 
Fixed in Version2.4.4 
Summary0016931: fcl-passrc: expression parser patch
Description* split TPasExpPart into hierarchy of classes
TPasExpr->
  TBinary
  TUnary .. (as discussed)
* fixed "ranges" parsing
* fixed error for parsing expressions, finishing right after binary operator, i.e. "10+;"
** added SParserExpectedIdentifier error message
* simplified TokenToExprOp usage

TagsNo tags attached.
Fixed in Revision15590
FPCOldBugId0
FPCTarget
Attached Files

Activities

2010-07-15 09:26

 

passrc.patch (13,810 bytes)   
Index: src/pastree.pp
===================================================================
--- src/pastree.pp	(revision 15574)
+++ src/pastree.pp	(working copy)
@@ -67,8 +67,8 @@
   SPasTreeDestructorImpl = 'destructor implementation';
 
 type
-  TPasExprKind = (pekIdent, pekNumber, pekString, pekSet,
-     pekPrefix, pekPostfix, pekBinary, pekFuncParams, pekArrayParams);
+  TPasExprKind = (pekIdent, pekNumber, pekString, pekSet, pekRange,
+     pekUnary, pekBinary, pekFuncParams, pekArrayParams);
 
   TExprOpCode = (eopNone,
                  eopAdd,eopSubtract,eopMultiply,eopDivide, eopDiv,eopMod, eopPower,// arithmetic
@@ -79,25 +79,46 @@
                  eopIn,eopIs,eopAs, eopSymmetricaldifference, // Specials
                  eopAddress);
   
-  { TPasExprPart }
+  { TPasExpr }
 
-  TPasExprPart = class 
+  TPasExpr = class
     Kind      : TPasExprKind;
-    Left      : TPasExprPart;
-    Right     : TPasExprPart;
     OpCode    : TexprOpcode;
-    Value    : AnsiString;
-    Params    : array of TPasExprPart;
+    constructor Create(AKind: TPasExprKind; AOpCode: TexprOpcode);
+  end;
+
+  TUnaryExpr = class(TPasExpr)
+    Operand   : TPasExpr;
+    constructor Create(AOperand: TPasExpr; AOpCode: TExprOpCode);
+    destructor Destroy; override;
+  end;
+
+  { TBinaryExpr }
+
+  TBinaryExpr = class(TPasExpr)
+    left      : TPasExpr;
+    right     : TPasExpr;
+    constructor Create(xleft, xright: TPasExpr; AOpCode: TExprOpCode);
+    constructor CreateRange(xleft, xright: TPasExpr);
+    destructor Destroy; override;
+  end;
+
+  TPrimitiveExpr = class(TPasExpr)
+    Value     : AnsiString;
+    constructor Create(AKind: TPasExprKind; const AValue : Ansistring);
+  end;
+
+  { TParamsExpr }
+
+  TParamsExpr = class(TPasExpr)
+    Value     : TPasExpr;
+    Params    : array of TPasExpr;
+    {pekArray, pekFuncCall, pekSet}
     constructor Create(AKind: TPasExprKind);
-    constructor CreateWithText(AKind: TPasExprKind; const AValue : Ansistring);
-    constructor CreatePrefix(rightExp: TPasExprPart; const AOpCode: TExprOpCode);
-    constructor CreatePostfix(leftExp: TPasExprPart; const AOpCode: TExprOpCode);
-    constructor CreateBinary(xleft, xright: TPasExprPart; const AOpCode: TExprOpCode);
     destructor Destroy; override;
-    procedure AddParam(xp: TPasExprPart);
+    procedure AddParam(xp: TPasExpr);
   end;
 
-
   // Visitor pattern.
   TPassTreeVisitor = class;
 
@@ -467,7 +488,7 @@
     Value: string;
     Modifiers : string;
     AbsoluteLocation : String;
-    Expr: TPasExprPart;
+    Expr: TPasExpr;
   end;
 
   { TPasConst }
@@ -2315,52 +2336,61 @@
   Result:=true;
 end;
 
-{ TPasExprPart }
+{ TPasExpr }
 
-constructor TPasExprPart.Create(AKind:TPasExprKind);
+constructor TPasExpr.Create(AKind: TPasExprKind; AOpCode: TexprOpcode);
 begin
   Kind:=AKind;
+  OpCode:=AOpCode;
 end;
 
-constructor TPasExprPart.CreateWithText(AKind:TPasExprKind;const AValue: AnsiString);
+{ TPrimitiveExpr }
+
+constructor TPrimitiveExpr.Create(AKind: TPasExprKind; const AValue : Ansistring);
 begin
-  Create(AKind);
+  inherited Create(AKind, eopNone);
   Value:=AValue;
 end;
 
-constructor TPasExprPart.CreatePrefix(rightExp: TPasExprPart; const AOpCode: TExprOpCode);
+{ TUnaryExpr }
+
+constructor TUnaryExpr.Create(AOperand: TPasExpr; AOpCode: TExprOpCode);
 begin
-  Create(pekPrefix);
-  right:=rightExp;
-  Opcode:=AOpCode;
+  inherited Create(pekUnary, AOpCode);
+  Operand:=AOperand;
 end;
 
-constructor TPasExprPart.CreatePostfix(leftExp: TPasExprPart; const AOpCode: TExprOpCode);
+destructor TUnaryExpr.Destroy;
 begin
-  Create(pekPostfix);
-  left:=leftExp;
-  Opcode:=AOpCode;
+  Operand.Free;
 end;
 
-constructor TPasExprPart.CreateBinary(xleft, xright: TPasExprPart; const AOpCode: TExprOpcode);
+{ TBinaryExpr }
+
+constructor TBinaryExpr.Create(xleft,xright:TPasExpr; AOpCode:TExprOpCode);
 begin
-  Create(pekBinary);
+  inherited Create(pekBinary, AOpCode);
   left:=xleft;
   right:=xright;
-  Opcode:=AOpCode;
 end;
 
-destructor TPasExprPart.Destroy;
-var
-  i : Integer;
+constructor TBinaryExpr.CreateRange(xleft,xright:TPasExpr);
 begin
+  inherited Create(pekRange, eopNone);
+  left:=xleft;
+  right:=xright;
+end;
+
+destructor TBinaryExpr.Destroy;
+begin
   left.Free;
   right.Free;
-  for i:=0 to length(Params)-1 do Params[i].Free;
   inherited Destroy;
 end;
 
-procedure TPasExprPart.AddParam(xp:TPasExprPart);
+{ TParamsExpr }
+
+procedure TParamsExpr.AddParam(xp:TPasExpr);
 var
   i : Integer;
 begin
@@ -2369,6 +2399,17 @@
   Params[i]:=xp;
 end;
 
+constructor TParamsExpr.Create(AKind: TPasExprKind);
+begin
+  inherited Create(AKind, eopNone)
+end;
 
+destructor TParamsExpr.Destroy;
+var
+  i : Integer;
+begin
+  for i:=0 to length(Params)-1 do Params[i].Free;
+  inherited Destroy;
+end;
 
 end.
Index: src/pparser.pp
===================================================================
--- src/pparser.pp	(revision 15574)
+++ src/pparser.pp	(working copy)
@@ -45,6 +45,7 @@
   SParserInterfaceTokenError = 'Invalid token in interface section of unit';
   SParserImplementationTokenError = 'Invalid token in implementation section of unit';
   SParserInvalidTypeDef = 'Invalid type definition';
+  SParserExpectedIdentifier = 'Identifier expected';
 
 type
   TPasTreeContainer = class
@@ -115,7 +116,7 @@
     procedure ParseExc(const Msg: String);
   protected
     function OpLevel(t: TToken): Integer;
-    Function TokenToExprOp (AToken : TToken; Const AString : String) : TExprOpCode;
+    Function TokenToExprOp (AToken : TToken) : TExprOpCode;
     function CreateElement(AClass: TPTreeElement; const AName: String;
       AParent: TPasElement): TPasElement;overload;
     function CreateElement(AClass: TPTreeElement; const AName: String;
@@ -123,8 +124,8 @@
     Function IsHint(Const S : String; var AHint : TPasMemberHint) : Boolean;
     Function CheckHint(Element : TPasElement; ExpectSemiColon : Boolean) : TPasMemberHints;
 
-    function ParseParams(paramskind: TPasExprKind): TPasExprPart;
-    function ParseExpIdent: TPasExprPart;
+    function ParseParams(paramskind: TPasExprKind): TParamsExpr;
+    function ParseExpIdent: TPasExpr;
   public
     Options : set of TPOptions;
     CurModule: TPasModule;
@@ -142,7 +143,7 @@
     function ParseComplexType(Parent : TPasElement = Nil): TPasType;
     procedure ParseArrayType(Element: TPasArrayType);
     procedure ParseFileType(Element: TPasFileType);
-    function DoParseExpression: TPasExprPart;
+    function DoParseExpression: TPasExpr;
     function ParseExpression: String;
     function ParseCommand: String; // single, not compound command like begin..end
     procedure AddProcOrFunction(Declarations: TPasDeclarations; AProc: TPasProcedure);
@@ -646,21 +647,23 @@
   ];
 
 
-function TPasParser.ParseParams(paramskind: TPasExprKind): TPasExprPart;
+function TPasParser.ParseParams(paramskind: TPasExprKind): TParamsExpr;
 var
-  params  : TPasExprPart;
-  p       : TPasExprPart;
+  params  : TParamsExpr;
+  p       : TPasExpr;
   PClose  : TToken;
 begin
   Result:=nil;
-  if CurToken<>tkBraceOpen then Exit;
 
-  if paramskind in [pekArrayParams, pekSet] then
-    PClose:=tkSquaredBraceClose
-  else
+  if paramskind in [pekArrayParams, pekSet] then begin
+    if CurToken<>tkSquaredBraceOpen then Exit;
+    PClose:=tkSquaredBraceClose;
+  end else begin
+    if CurToken<>tkBraceOpen then Exit;
     PClose:=tkBraceClose;
+  end;
 
-  params:=TPasExprPart.Create(paramskind);
+  params:=TParamsExpr.Create(paramskind);
   try
     NextToken;
     if not (CurToken in EndExprToken) then begin
@@ -689,7 +692,7 @@
   end;
 end;
 
-Function TPasParser.TokenToExprOp (AToken : TToken; Const AString : String) : TExprOpCode;
+Function TPasParser.TokenToExprOp (AToken : TToken) : TExprOpCode;
 
 begin
   Case AToken of
@@ -718,68 +721,65 @@
     tkNot                   : Result:=eopNot;
     tkIn                    : Result:=eopIn;
   else
-    Raise Exception.CreateFmt('Not an operand: (%d : %s)',[AToken,Astring]);   
+    Raise Exception.CreateFmt('Not an operand: (%d : %s)',[AToken,TokenInfos[AToken]]);
   end;
 end;
  
-function TPasParser.ParseExpIdent:TPasExprPart;
+function TPasParser.ParseExpIdent:TPasExpr;
 var
-  x, t    : TPasExprPart;
-  eofid   : Boolean;
+  x       : TPasExpr;
+  prm     : TParamsExpr;
+  u       : TUnaryExpr;
+  b       : TBinaryExpr;
 begin
   Result:=nil;
-  eofid:=True;
   case CurToken of
-    tkString: begin
-      x:=TPasExprPart.CreateWithText(pekString, CurTokenString);
-      NextToken;
-    end;
-    tkNumber:
-    begin
-      x:=TPasExprPart.CreateWithText(pekNumber, CurTokenString);
-      NextToken;
-    end;
-    tkSquaredBraceOpen:
-      x:=ParseParams(pekSet);
-    tkIdentifier: begin
-      x:=TPasExprPart.CreateWithText(pekIdent, CurTokenText);
-      eofid:=False;
-    end;
+    tkString:           x:=TPrimitiveExpr.Create(pekString, CurTokenString);
+    tkNumber:           x:=TPrimitiveExpr.Create(pekNumber, CurTokenString);
+    tkIdentifier:       x:=TPrimitiveExpr.Create(pekIdent, CurTokenText);
+    tkSquaredBraceOpen: x:=ParseParams(pekSet);
+  else
+    ParseExc(SParserExpectedIdentifier);
   end;
 
-  if eofid then begin
-    Result:=x;
-    Exit;
-  end;
+  if x.Kind<>pekSet then NextToken;
 
   try
-    NextToken;
-    while CurToken in [tkBraceOpen, tkSquaredBraceOpen, tkCaret] do
-      case CurToken of
-        tkBraceOpen: begin
-          t:=ParseParams(pekFuncParams);
-          if not Assigned(t) then Exit;
-          t.left:=x;
-          x:=t;
+    if x.Kind=pekIdent then begin
+      while CurToken in [tkBraceOpen, tkSquaredBraceOpen, tkCaret] do
+        case CurToken of
+          tkBraceOpen: begin
+            prm:=ParseParams(pekFuncParams);
+            if not Assigned(prm) then Exit;
+            prm.Value:=x;
+            x:=prm;
+          end;
+          tkSquaredBraceOpen: begin
+            prm:=ParseParams(pekArrayParams);
+            if not Assigned(prm) then Exit;
+            prm.Value:=x;
+            x:=prm;
+          end;
+          tkCaret: begin
+            u:=TUnaryExpr.Create(x, TokenToExprOp(CurToken));
+            x:=u;
+            NextToken;
+          end;
         end;
-        tkSquaredBraceOpen: begin
-          t:=ParseParams(pekArrayParams);
-          if not Assigned(t) then Exit;
-          t.left:=x;
-          x:=t;
-        end;
-        tkCaret: begin
-          t:=TPasExprPart.CreatePostfix(x, TokenToExprOp(CurToken,TokenInfos[CurToken]));
-          NextToken;
-          x:=t;
-        end;
+
+      if CurToken in [tkDot, tkas] then begin
+        NextToken;
+        b:=TBinaryExpr.Create(x, ParseExpIdent, TokenToExprOp(CurToken));
+        if not Assigned(b.right) then Exit; // error
+        x:=b;
       end;
+    end;
 
-    if CurToken in [tkDot, tkas] then begin
+    if CurToken = tkDotDot then begin
       NextToken;
-      x:=TPasExprPart.CreateBinary(x, ParseExpIdent, TokenToExprOp(CurToken,TokenInfos[CurToken]));
-      if not Assigned(x.right) then
-        Exit; // error?
+      b:=TBinaryExpr.CreateRange(x, DoParseExpression);
+      if not Assigned(b.right) then Exit; // error
+      x:=b;
     end;
 
     Result:=x;
@@ -804,22 +804,23 @@
   end;
 end;
 
-function TPasParser.DoParseExpression: TPasExprPart;
+function TPasParser.DoParseExpression: TPasExpr;
 var
   expstack  : TList;
   opstack   : TList;
   pcount    : Integer;
-  x         : TPasExprPart;
+  x         : TPasExpr;
   i         : Integer;
   tempop    : TToken;
+  AllowEnd  : Boolean;
   
 const
   PrefixSym = [tkPlus, tkMinus, tknot, tkAt]; // + - not @
 
-  function PopExp: TPasExprPart; inline;
+  function PopExp: TPasExpr; inline;
   begin
     if expstack.Count>0 then begin
-      Result:=TPasExprPart(expstack[expstack.Count-1]);
+      Result:=TPasExpr(expstack[expstack.Count-1]);
       expstack.Delete(expstack.Count-1);
     end else
       Result:=nil;
@@ -845,13 +846,13 @@
   procedure PopAndPushOperator;
   var
     t       : TToken;
-    xright  : TPasExprPart;
-    xleft   : TPasExprPart;
+    xright  : TPasExpr;
+    xleft   : TPasExpr;
   begin
     t:=PopOper;
     xright:=PopExp;
     xleft:=PopExp;
-    expstack.Add(TPasExprPart.CreateBinary(xleft, xright, TokenToExprOp(t,TokenInfos[t])));
+    expstack.Add(TBinaryExpr.Create(xleft, xright, TokenToExprOp(t)));
   end;
 
 begin
@@ -860,6 +861,7 @@
   opstack := TList.Create;
   try
     repeat
+      AllowEnd:=True;
       pcount:=0;
       while CurToken in PrefixSym do begin
         PushOper(CurToken);
@@ -872,18 +874,20 @@
         x:=DoParseExpression();
         if CurToken<>tkBraceClose then Exit;
         NextToken;
-      end else
+      end else begin
         x:=ParseExpIdent;
+      end;
 
       if not Assigned(x) then Exit;
       expstack.Add(x);
       for i:=1 to pcount do
         begin
         tempop:=PopOper;
-        expstack.Add( TPasExprPart.CreatePrefix( PopExp, TokenToExprOp(tempop,TokenInfos[tempop]) ));
+        expstack.Add( TUnaryExpr.Create( PopExp, TokenToExprOp(tempop) ));
         end;
       if not (CurToken in EndExprToken) then begin
         // Adjusting order of the operations
+        AllowEnd:=False;
         tempop:=PeekOper;
         while (opstack.Count>0) and (OpLevel(tempop)>=OpLevel(CurToken)) do begin
           PopAndPushOperator;
@@ -893,12 +897,12 @@
         NextToken;
       end;
 
-    until CurToken in EndExprToken;
+    until AllowEnd and (CurToken in EndExprToken);
 
     while opstack.Count>0 do PopAndPushOperator;
 
     // only 1 expression should be on the stack, at the end of the correct expression
-    if expstack.Count=1 then Result:=TPasExprPart(expstack[0]);
+    if expstack.Count=1 then Result:=TPasExpr(expstack[0]);
 
   finally
     if not Assigned(Result) then begin
passrc.patch (13,810 bytes)   

Michael Van Canneyt

2010-07-16 21:04

administrator   ~0039395

Thanks for the effort !

Issue History

Date Modified Username Field Change
2010-07-15 09:26 Dmitry Boyarintsev New Issue
2010-07-15 09:26 Dmitry Boyarintsev File Added: passrc.patch
2010-07-16 20:58 Michael Van Canneyt Status new => assigned
2010-07-16 20:58 Michael Van Canneyt Assigned To => Michael Van Canneyt
2010-07-16 21:04 Michael Van Canneyt Fixed in Revision => 15590
2010-07-16 21:04 Michael Van Canneyt Status assigned => resolved
2010-07-16 21:04 Michael Van Canneyt Fixed in Version => 2.5.1
2010-07-16 21:04 Michael Van Canneyt Resolution open => fixed
2010-07-16 21:04 Michael Van Canneyt Target Version => 3.0.0
2010-07-16 21:04 Michael Van Canneyt Note Added: 0039395
2010-07-16 21:10 Dmitry Boyarintsev Status resolved => closed
2011-05-01 16:07 Marco van de Voort FPCOldBugId => 0
2011-05-01 16:07 Marco van de Voort Fixed in Version 2.5.1 => 2.4.4
2011-05-01 16:07 Marco van de Voort Target Version 3.0.0 =>
2011-05-02 17:35 Marco van de Voort Status closed => resolved
2011-07-23 16:45 Dmitry Boyarintsev Status resolved => closed