Here is a “pretty close” implementation. Fiddly and wordy, but simple structures look pretty close. Dot does pretty well on ranks (rows) but not so well on files (columns), so more complex structures like those found in section 3.3 of the book (https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-22.html) might be much more difficult.
digraph lisp {
graph [nodesep=.6 splines=line newrank=true] // nodesep will help & hurt
node [shape=plain ]
edge [tailclip=false ] // tail starts in the center
subgraph clusterA {
node [shape=plain ]
edge [tailclip=false ] // tail starts in the center
graph [label="figure 2.2" labelloc=b]
// begin1 - pointer from the left
begin1 [style=invis]
// pair w/ left & right pointers (filled circle in center)
a [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR>
<TD WIDTH="32" port="l">●</TD>
<TD WIDTH="32" height="32" PORT="r">●</TD>
</TR>
</TABLE>>];
// terminal
1 [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR>
<TD WIDTH="32" HEIGHT="32" port="l">1</TD>
<TD WIDTH="32" HEIGHT="32" border="0"></TD>
</TR>
</TABLE>>];
// terminal
2 [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR>
<TD WIDTH="32" HEIGHT="32" port="l">2</TD>
<TD WIDTH="32" HEIGHT="32" border="0"></TD>
</TR>
</TABLE>>];
{ rank=same begin1 -> a }
a:l:c -> 1:l
{ rank=same a 2 a:r:c -> 2:w}
}
////////////////////////////////////////////////////////////////////
subgraph clusterB {
node [shape=plain ]
edge [tailclip=false ] // tail starts in the center
graph [label="figure 2.3 (part 1)" labelloc=b]
// begin2 - pointer from the left
begin2[style=invis]
// pair w/ left & right pointers (filled circle in center)
b1 [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR>
<TD WIDTH="32" port="l">●</TD>
<TD WIDTH="32" height="32" PORT="r">●</TD>
</TR>
</TABLE>>];
// pair w/ left & right pointers (filled circle in center)
b2 [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR>
<TD WIDTH="32" port="l">●</TD>
<TD WIDTH="32" height="32" PORT="r">●</TD>
</TR>
</TABLE>>];
// pair w/ left & right pointers (filled circle in center)
b3 [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR>
<TD WIDTH="32" port="l">●</TD>
<TD WIDTH="32" height="32" PORT="r">●</TD>
</TR>
</TABLE>>];
{ rank=same begin2 -> b1 }
{rank=same b1 b3}
b1:l:c -> b2
b1:r:c -> b3:w
// two terminals represented by "split" table
bp1 [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"><TR>
<TD WIDTH="32" height="32" port="l">1</TD>
<TD WIDTH="8" height="32" border="0"></TD>
<TD WIDTH="32" height="32" PORT="r">2</TD></TR>
</TABLE>>];
b2:l:c -> bp1:l
b2:r:c -> bp1:r
// two terminals represented by "split" table
bp2 [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"><TR>
<TD WIDTH="32" height="32" port="l">3</TD>
<TD WIDTH="8" height="32" border="0"></TD>
<TD WIDTH="32" height="32" PORT="r">4</TD></TR>
</TABLE>>];
b3:l:c -> bp2:l
b3:r:c -> bp2:r
}
////////////////////////////////////////////////////////////////////
subgraph clusterC {
node [shape=plain ]
edge [tailclip=false ] // tail starts in the center
graph [label="figure 2.3 (part 2)" labelloc=b]
// begin3 - pointer from the left
begin3[style=invis]
// pair w/ left & right pointers (filled circle in center)
c1 [group=CG1 label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR>
<TD WIDTH="32" port="l">●</TD>
<TD WIDTH="32" height="32" PORT="r">●</TD>
</TR>
</TABLE>>];
c2 [group=CG1 label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR>
<TD WIDTH="32" port="l">●</TD>
<TD WIDTH="32" height="32" PORT="r">●</TD>
</TR>
</TABLE>>];
c3 [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR>
<TD WIDTH="32" port="l">●</TD>
<TD WIDTH="32" height="32" PORT="r">●</TD>
</TR>
</TABLE>>];
// terminal - w/ 1 invisible cell
C1 [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR>
<TD WIDTH="32" HEIGHT="32" port="l">1</TD>
<TD WIDTH="32" HEIGHT="32" border="0"></TD>
</TR>
</TABLE>>];
// terminal
C4 [group=CG1 label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR>
<TD WIDTH="32" HEIGHT="32" port="l">4</TD>
<TD WIDTH="32" HEIGHT="32" border="0"></TD>
</TR>
</TABLE>>];
{rank=same c1 C4}
{rank=same c2 c3}
c1:l:c -> c2:l
c1:r:c -> C4:w
c2:l:c -> C1:l
c2:r:c -> c3:w
// two terminals represented by "split" table
cp1 [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"><TR>
<TD WIDTH="32" height="32" port="l">2</TD>
<TD WIDTH="8" height="32" border="0"></TD>
<TD WIDTH="32" height="32" PORT="r">3</TD></TR>
</TABLE>>];
c3:l:c -> cp1:l
c3:r:c -> cp1:r
{ rank=same begin3:e -> c1:l:w }
}
////////////////////////////////////////////////////////////////////
subgraph clusterD {
node [shape=plain ]
edge [tailclip=false ] // tail starts in the center
graph [label="figure 2.4" labelloc=b]
// begin4 - pointer from the left
begin4[style=invis]
// pair w/ left & right pointers (filled circle in center)
d1 [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR>
<TD WIDTH="32" port="l">●</TD>
<TD WIDTH="32" height="32" PORT="r">●</TD>
</TR>
</TABLE>>];
d2 [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR>
<TD WIDTH="32" port="l">●</TD>
<TD WIDTH="32" height="32" PORT="r">●</TD>
</TR>
</TABLE>>];
d3 [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR>
<TD WIDTH="32" port="l">●</TD>
<TD WIDTH="32" height="32" PORT="r">●</TD>
</TR>
</TABLE>>];
// black-out nil cdr
d4 [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR>
<TD WIDTH="32" port="l">●</TD>
<TD WIDTH="32" height="32" PORT="r" BGCOLOR="black"></TD>
</TR>
</TABLE>>];
// terminal
D1 [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR>
<TD WIDTH="32" HEIGHT="32" port="l">1</TD>
<TD WIDTH="32" HEIGHT="32" border="0"></TD>
</TR>
</TABLE>>];
// terminal
D2 [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR>
<TD WIDTH="32" HEIGHT="32" port="l">2</TD>
<TD WIDTH="32" HEIGHT="32" border="0"></TD>
</TR>
</TABLE>>];
// terminal
D3 [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR>
<TD WIDTH="32" HEIGHT="32" port="l">3</TD>
<TD WIDTH="32" HEIGHT="32" border="0"></TD>
</TR>
</TABLE>>];
// terminal
D4 [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR>
<TD WIDTH="32" HEIGHT="32" port="l">4</TD>
<TD WIDTH="32" HEIGHT="32" border="0"></TD>
</TR>
</TABLE>>];
{ rank=same begin4:e -> d1:l:w }
{rank=same d1 d2 d3 d4}
{rank=same D1 D2 D3 D4}
d1:l:c -> D1:l
d1:r:c -> d2:w
d2:l:c -> D2:l
d2:r:c -> d3:w
d3:l:c -> D3:l
d3:r:c -> d4:w
d4:l:c -> D4:l
}
}
