Recent

Author Topic: [SOLVED] Linked list inside a class.  (Read 635 times)

seany

  • Full Member
  • ***
  • Posts: 120
[SOLVED] Linked list inside a class.
« on: February 03, 2023, 03:26:37 pm »
my adventure on making a markdown renderer with slightly more function continues  :-[ :-[.. I have this linked list and class definition :

Code: Pascal  [Select][+][-]
  1. unit TDocument;
  2.  
  3. {$mode ObjFPC}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, TRenderObjects, TBlockIdentifierEngine;
  9.  
  10. type
  11.     SectionNodePTR = ^NodeStruct;
  12.     NodeStruct  = packed record
  13.       rendObj   : Variant;
  14.       ID        : Integer;
  15.       Parent    : SectionNodePTR;
  16.       Children  : Array of SectionNodePTR;
  17.       objType   : TBlockIdentifierEngine.classificationEnum;
  18.       end;
  19.     TNodeArray = Array of NodeStruct;
  20.  
  21.  
  22.   { markedDocument }
  23.  
  24.   markedDocument = class
  25.     // Sections : Array of TRenderObjects.Section;
  26.   public
  27.       nodeTree                   : NodeStruct;
  28.       constructor Create();
  29.       procedure AppendNode(var ChildObj : NodeStruct);
  30.       procedure AppendObject_asNode(var insertionObject : variant; var ID : integer; var objType : TBlockIdentifierEngine.classificationEnum);
  31.  
  32.  
  33.   end;    
  34.  

The classificationEnum is defined as :

Code: Pascal  [Select][+][-]
  1. classificationEnum = (localCommand, globalCommand, renderTarget, unknown, highLightCommand);  


- this definition is in a different file: tblockidentifierengine.pas . This works.

I want to add every block of renderable text (starting and ending with a newline) as well as every command block (starting with a . or period and ending with a ; or semicolon) as document nodes. The nodes will be marked either as renderTarget or as various commands. So The function is defined as:

Code: Pascal  [Select][+][-]
  1. procedure markedDocument.AppendObject_asNode(var insertionObject: variant;
  2.   var ID: integer; var objType: TBlockIdentifierEngine.classificationEnum);
  3. var
  4.    newNode                       : NodeStruct;
  5.    currNode                      : NodeStruct;
  6. begin
  7.  
  8.    newNode.rendObj      := insertionObject;
  9.    newNode.ID           := ID;
  10.    newNode.objType      := objType;
  11.  
  12.    if nodeTree = nil then
  13.    begin
  14.      nodeTree    := newNode;
  15.    end
  16.    else
  17.    begin
  18.      currNode    := nodeTree;
  19.      while length(currNode.Children) <> 0 do
  20.      begin
  21.        currNode  := currNode.Children[0];
  22.      end;
  23.      SetLength(currNode.Children, length(currNode.Children) + 1);
  24.      currNode.Children[length(currNode.Children) -1] := newNode;
  25.    end;
  26.  
  27. end;      
  28.    


This is called as:

classInstance.AppendObject_asNode("some text",0,a tesst enum value);


But this does not compile. It tells me:

In the line:
Code: Pascal  [Select][+][-]
  1.  if nodeTree = nil then  

Error: Operator is not overloaded: "NodeStruct" = "Pointer"

I was hoping that, I can find out if the root NodeStruct in the class instance is populated or not via comparing it with nil. My plan is to add every block (text or command as described above) as a node in a linked list. In this list, each element is a Nodestruct. The first element of the linked list is denoted as nodeTree in the class. So if I see that the nodeTree is not set in an instance of the class, it will mean that that first element of the linked list is not set. So we can set the newly created NodeStruct with the incoming block directly as the nodeTree.

Moreover, I also tried with:
Code: Pascal  [Select][+][-]
  1.  if markedDocument.nodeTree = nil then  
In that case, It tells me, that in the same line: Only class methods, class properties and class variables can be referred with class references




Also, in this line:

Code: Pascal  [Select][+][-]
  1. currNode  := currNode.Children[0];

I get an error: Error: Incompatible types: got "SectionNodePTR" expected "NodeStruct".

I read that objects are already pointers, so there is no need to dereference them. But seems that is not the case?

I have a similar error in this line.
Code: Pascal  [Select][+][-]
  1. currNode.Children[length(currNode.Children) -1] := newNode;

But I will be able to address that as soon as I have addressed the #2 error.


Please help. Thank you.





« Last Edit: February 04, 2023, 05:38:15 pm by seany »
My projects, among others:

https://linktr.ee/siderealNight

Blaazen

  • Hero Member
  • *****
  • Posts: 3237
  • POKE 54296,15
    • Eye-Candy Controls
Re: Linked list inside a class.
« Reply #1 on: February 03, 2023, 04:54:22 pm »
This is pretty complex question. Anyway, record cannot be nil. Pointer to record can.

Declare
Code: Pascal  [Select][+][-]
  1.  nodeTree: SectionNodePTR;

and try
Code: Pascal  [Select][+][-]
  1. if nodeTree = nil then
  2.    begin
  3.      new(nodeTree);
  4.      nodeTree^    := newNode;
  5.    end
  6.    else
  7.    begin

Also here: correct is
Code: Pascal  [Select][+][-]
  1. currNode  := currNode.Children[0]^;

("Correct" means that both sides are of the same type; if it will do what you want is another story)
Lazarus 2.3.0 (rev main-2_3-2863...) FPC 3.3.1 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

seany

  • Full Member
  • ***
  • Posts: 120
Re: Linked list inside a class.
« Reply #2 on: February 04, 2023, 03:35:19 pm »
That needed a little bit of work.

So this is how I did it.

The class:
Code: Pascal  [Select][+][-]
  1. uses
  2.   Classes, SysUtils, TRenderObjects, Dialogs, TBlockIdentifierEngine;
  3.  
  4. type
  5.     genNodePtr = ^NodeStruct;
  6.     NodeStruct  = packed record
  7.       rendObj   : Variant;
  8.       ID        : Integer;
  9.       Parent    : genNodePtr;
  10.       Children  : Array of genNodePtr;
  11.       objType   : TBlockIdentifierEngine.classificationEnum;
  12.       end;
  13.     TNodeArray = Array of NodeStruct;
  14.      
  15.   markedDocument = class
  16.   public
  17.       nodeTree                   : genNodePtr;
  18.       constructor Create();
  19.       procedure AppendNode(var ChildObj : NodeStruct);
  20.       procedure AppendObject_asNode(var insertionObject : variant; var ID : integer; var objType : TBlockIdentifierEngine.classificationEnum);
  21.  
  22.  
  23.   end;  

Then the Insertion Program
Code: Pascal  [Select][+][-]
  1. procedure markedDocument.AppendObject_asNode(var insertionObject: variant;
  2.   var ID: integer; var objType: TBlockIdentifierEngine.classificationEnum);
  3. var
  4.    newNode                       : ^NodeStruct;
  5.    currNode                      : ^NodeStruct;      // I made them pointers
  6.  
  7.    argStr                        : String;
  8. begin
  9.  
  10.    newNode               := New(genNodePtr);
  11.  
  12.    newNode^.rendObj      := insertionObject;
  13.    newNode^.ID           := ID;
  14.    newNode^.objType      := objType;
  15.  
  16.    // pointer is dereferenced with the caret after it's name, and then filled up
  17.  
  18.    if nodeTree = nil then
  19.    begin
  20.      new(nodeTree);
  21.      nodeTree     := newNode;
  22.    end
  23.    else
  24.    begin
  25.  
  26.      currNode    := nodeTree;
  27.  
  28.      while length(currNode^.Children) <> 0 do                       // the last item in the list has no children, so children.length is 0
  29.      begin
  30.        
  31.        currNode  := currNode^.Children[0];                          // Dereference and pick the first child, because at this stage the size of children is exactly ONE
  32.        
  33.      end;
  34.      
  35.      SetLength(currNode^.Children, length(currNode^.Children) + 1);      // increase arraysize from zero to one
  36.  
  37.      currNode^.Children[length(currNode^.Children) -1] := newNode;       // Fill up first child. If i instead had currnode and newnode as records themselves, then
  38.                                                                          //  currNode.Children[length(currNode.Children) -1]^ := newNode compiles,
  39.                                                                          //  but throws a sigsev error in runtime
  40.    end;
  41.  
  42. end;

This works, I can look in the list, and it contains the stuff as i want them to...

QUESTION

Why the sigsev error (as shown in the code by a comment)?
« Last Edit: February 04, 2023, 06:08:53 pm by seany »
My projects, among others:

https://linktr.ee/siderealNight

Blaazen

  • Hero Member
  • *****
  • Posts: 3237
  • POKE 54296,15
    • Eye-Candy Controls
Re: Linked list inside a class.
« Reply #3 on: February 04, 2023, 05:38:15 pm »
I'm surprised that this even compile:
Code: Pascal  [Select][+][-]
  1.  newNode := New(genNodePtr);
It's not even documented: https://www.freepascal.org/docs-html/rtl/system/new.html

I always used:
Code: Pascal  [Select][+][-]
  1. new(newNode);

BTW what is genNodePtr?
Lazarus 2.3.0 (rev main-2_3-2863...) FPC 3.3.1 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

seany

  • Full Member
  • ***
  • Posts: 120
Re: [SOLVED] Linked list inside a class.
« Reply #4 on: February 04, 2023, 06:08:14 pm »
My bad.

Code: Pascal  [Select][+][-]
  1. genNodePtr = ^NodeStruct;

Also adjusted my previous post in this thread
My projects, among others:

https://linktr.ee/siderealNight

seany

  • Full Member
  • ***
  • Posts: 120
Re: Linked list inside a class.
« Reply #5 on: February 04, 2023, 06:11:59 pm »

It's not even documented: https://www.freepascal.org/docs-html/rtl/system/new.html


About documentation: I followed it here:

https://forum.lazarus.freepascal.org/index.php?topic=9521.0

The example code there looks like:

Code: Pascal  [Select][+][-]
  1. type
  2.   TMailingListRecord = record
  3.     FirstName: string;
  4.     // [...]
  5.   end;
  6.   PMailingListRecord = ^TMailingListRecord;
  7. var
  8.   ptr: PMailingListRecord;
  9. begin
  10.   ptr := New(PMailingListRecord);                       // MY COMMENT: ptr is of type pointer to record, and is initialized as a new pointer to the same type of record
  11.   ptr^.FirstName := 'Per';
  12.   // [...]
  13.   Dispose(ptr);
  14. end;
  15.  
My projects, among others:

https://linktr.ee/siderealNight

 

TinyPortal © 2005-2018