Как создать правильную синтаксическую диаграмму с помощью Graphviz? - PullRequest
2 голосов
/ 10 апреля 2020

Я пытаюсь воссоздать следующую синтаксическую диаграмму, используя Graphviz (который в конечном итоге будет встроен в Sphinx):

enter image description here

Использование DOT язык, я определил следующую диаграмму:

digraph numexpr {

    bgcolor="transparent"

    {rank = same;
    p_0[shape=point];
    n_1[shape=block, label="constant", group=g1];
    p_1[shape=point]}

    n_2[shape=block, label="enumerated-list", group=g1]
    n_3[shape=block, label="reference", group=g1]
    n_4[shape=block, label="function-call", group=g1]
    n_5[shape=block, label="operator-expression", group=g1]
    n_6[shape=block, label="iterative-expression", group=g1]
    n_7[shape=block, label="conditional-expression", group=g1]
    n_8[shape=block, label="logical-expression", group=g1]

    {rank = same;
    c_1[shape=circle, label="("];
    n_9[shape=block, label="numerical-expression", group=g1];
    c_2[shape=circle, label=")"]}

    p_0 -> n_1 [arrowsize=.5]
    p_0 -> n_2 [arrowsize=.5]
    p_0 -> n_3 [arrowsize=.5]
    p_0 -> n_4 [arrowsize=.5]
    p_0 -> n_5 [arrowsize=.5]
    p_0 -> n_6 [arrowsize=.5]
    p_0 -> n_7 [arrowsize=.5]
    p_0 -> n_8 [arrowsize=.5]
    p_0 -> c_1 [arrowsize=.5]
    c_1 -> n_9 [arrowsize=.5]
    n_1 -> p_1 [arrowsize=.5]
    n_2 -> p_1 [arrowsize=.5]
    n_3 -> p_1 [arrowsize=.5]
    n_4 -> p_1 [arrowsize=.5]
    n_5 -> p_1 [arrowsize=.5]
    n_6 -> p_1 [arrowsize=.5]
    n_7 -> p_1 [arrowsize=.5]
    n_8 -> p_1 [arrowsize=.5]
    n_9 -> c_2 [arrowsize=.5]
    c_2 -> p_1 [arrowsize=.5]

    edge[style=invis];
    n_1 -> n_2
    n_2 -> n_3
    n_3 -> n_4
    n_4 -> n_5
    n_5 -> n_6
    n_6 -> n_7
    n_7 -> n_8
    n_8 -> n_9

}

Рендеринг выглядит следующим образом:

enter image description here

Закрыть, но без сигары. Как можно манипулировать краями так, чтобы рендер выглядел более похожим на исходную синтаксическую диаграмму?

1 Ответ

2 голосов
/ 14 апреля 2020

Вот приблизительное. Выполнено с ~ 225 строками точка кода и требует трехэтапного процесса:

  1. точка -Tdot ...> somefile
  2. ручное редактирование некоторого файла для добавления 18 горизонтальных ребер и добавление макета = neato
  3. точка -Tpng somefile> somefile.png

enter image description here

Если бы мне пришлось сделать это снова, я бы сгенерировал pos значения для узлов и ребер.

digraph numexpr {
  nodesep=.7
  ranksep=.22
  bgcolor="transparent"
  node[pin=true]

  subgraph clusterLeftSide {
    peripheries=0
    margin=30

    node [shape=point width=.01 qlabel="" style=solid ordering=out]
    nls1; nls2; nls3; nls4; nls5; nls6; nls7; nls8; nls9 
    ls1; ls2; ls3; ls4; ls5; ls6; ls7; ls8;
    ls9 [style=invis]

    node [shape=point width=.01 qlabel="" style=invis ordering=out]
    fls1; fls2; fls3; fls4; fls5; fls6; fls7; fls8; fls9 

    edge [tailclip=false headclip=false dir=none]
    {
      rank=same
      fls1->ls1 [style=solid]
      ls1->nls1 [style=solid]
    }
    {
      rank=same
      fls2->ls2 [style=invis]
      ls2->nls2 [style=invis]
    }
    {
      rank=same
      fls3->ls3 [style=invis]
      ls3->nls3 [style=invis]
    }
    {
      rank=same
      fls4->ls4 [style=invis]
      ls4->nls4 [style=invis]
    }
    {
      rank=same
      fls5->ls5 [style=invis]
      ls5->nls5 [style=invis]
    }
    {
      rank=same
      fls6->ls6 [style=invis]
      ls6->nls6 [style=invis]
    }
    {
      rank=same
      fls7->ls7 [style=invis]
      ls7->nls7 [style=invis]
    }
    {
      rank=same
      fls8->ls8 [style=invis]
      ls8->nls8 [style=invis]
    }
    {
      rank=same
      fls9->ls9 [style=invis]
      ls9->nls9 [style=invis]
    }

    fls1->fls2->fls3->fls4->fls5->fls6->fls7->fls8->fls9 [style=invis]

    node [shape=point width=.01 label="" style=zinvis]
    edge [dir=none style=solid tailclip=false headclip=false]
    ls1->ls2->ls3->ls4->ls5->ls6->ls7->ls8 [style=solid]
    ls8->ls9 [style=invis]
  }


  subgraph clusterMain {
    peripheries=0
    margin=30
    n1[shape=box  label="constant",xleft=1 xright=1 ];
    n2[shape=box  label="enumerated-list",xleft=1 xright=1 ]
    n3[shape=box  label="reference",xleft=1 xright=1 ]
    n4[shape=box  label="function-call",xleft=1 xright=1 ]
    n5[shape=box  label="operator-expression",xleft=1 xright=1 ]
    n6[shape=box  label="iterative-expression",xleft=1 xright=1 ]
    n7[shape=box  label="conditional-expression",xleft=1 xright=1 ]
    n8[shape=box  label="logical-expression",xleft=1 xright=1 ]

    {
      rank = same;
      c9a[shape=circle, label="(" xleft=1 ];
      n9[shape=box width=2.7  label="numerical-expression" ];
      c9b[shape=circle, label=")"  xright=1 ] 
      c9a -> n9 -> c9b
    }

    edge[style=invis];
    n1 -> n2
    n2 -> n3
    n3 -> n4
    n4 -> n5
    n5 -> n6
    n6 -> n7
    n7 -> n8
    n8 -> n9
  }

  subgraph clusterRightSide {
    peripheries=0
    margin=30 

    node [shape=point width=.01 qlabel="" style=solid ordering=out]
    nrs1; nrs2; nrs3; nrs4; nrs5; nrs6; nrs7; nrs8; nrs9 
    rs1; rs2; rs3; rs4; rs5; rs6; rs7; rs8; 
    rs9 [style=invis]

    node [shape=point width=.01 qlabel="" style=invis ordering=out]
    frs1; frs2; frs3; frs4; frs5; frs6; frs7; frs8; frs9 

    edge [tailclip=false headclip=false zdir=none]
    {
      rank=same
      nrs1->rs1 [style=solid dir=none]
      rs1->frs1 [style=solid]
    }
    {
      rank=same
      nrs2->rs2 [style=invis]
      rs2->frs2 [style=invis]
    }
    {
      rank=same
      nrs3->rs3 [style=invis]
      rs3->frs3 [style=invis]
    }
    {
      rank=same
      nrs4->rs4 [style=invis]
      rs4->frs4 [style=invis]
    }
    {
      rank=same
      nrs5->rs5 [style=invis]
      rs5->frs5 [style=invis]
    }
    {
      rank=same
      nrs6->rs6 [style=invis]
      rs6->frs6 [style=invis]
    }
    {
      rank=same
      nrs7->rs7 [style=invis]
      rs7->frs7 [style=invis]
    }
    {
      rank=same
      nrs8->rs8 [style=invis]
      rs8->frs8 [style=invis]
    }
    {
      rank=same
      nrs9->rs9 [style=invis]
      rs9->frs9 [style=invis]
    }

    nrs1->nrs2->nrs3->nrs4->nrs5->nrs6->nrs7->nrs8 [style=invis]
    nrs8->nrs9 [style=invis]

    node [shape=point width=.01 label="" style=zinvis]
    edge [dir=none style=solid tailclip=false headclip=false]
    rs1->rs2 [dir=back]
    rs2->rs3->rs4->rs5->rs6->rs7->rs8 [style=solid]
    rs8->rs9 [style=invis]
    frs1->frs2->frs3->frs4->frs5->frs6->frs7->frs8->frs9 [style=invis]
  }


  edge [dir=none]
  ls1:s->nls2:w
  ls2:s->nls3:w
  ls3:s->nls4:w
  ls4:s->nls5:w
  ls5:s->nls6:w
  ls6:s->nls7:w
  ls7:s->nls8:w
  ls8:s->nls9:w

  nrs2:e->rs1:s
  nrs3:e->rs2:s
  nrs4:e->rs3:s
  nrs5:e->rs4:s
  nrs6:e->rs5:s
  nrs7:e->rs6:s
  nrs8:e->rs7:s
  nrs9:e->rs8:s


/*  add these lines to the output of:  dot -Tdot

 edge [dir=forward]
 nls1->n1
 nls2->n2
 nls3->n3
 nls4->n4
 nls5->n5
 nls6->n6
 nls7->n7
 nls8->n8
 nls9->c9a
 edge [dir=none]
 n1->nrs1
 n2->nrs2
 n3->nrs3
 n4->nrs4
 n5->nrs5
 n6->nrs6
 n7->nrs7
 n8->nrs8
 c9b->nrs9

*/

}
...