Pascalの三角形 #3

man 1 gvprやPDF化された文書などに書かれていないように思うが、
gvprではユーザ定義関数を定義することができる。
pascal2.gでノードを作成する部分がまとめられそうなので関数化してみる。

pascal3.g
BEGIN {
  if (ARGC != 1) {
    print("usage: gvpr -fpascal2.g -a <step>");
    exit(0);
  }
  int step = ARGV[0];
  graph_t g = graph("pascal_triangle", "U");
  node_t p[], q[];
  int i, j;

# user-defined function for creating new node
  node_t create(int k) {
    node_t n = node(g, sprintf("%d_%d", i, k));
    n.label = i == k || k == 0 ? 1 : 0 + p[k - 1].label + p[k].label;
    return n;
  }

  for (i = 0; i <= step; i++) {
# create nodes in i-th step
    q[0] = create(0);
    for (j = 1; j < i; j++) q[j] = create(j);
    q[i] = create(i);
# create edges from (i-1)-th step to i-th step
    for (j = 0; j < i; j++) {
      edge_sg(g, p[j], q[j], "");
      edge_sg(g, p[j], q[j + 1], "");
    }
# prepare for next step
    for (j = 0; j <= i; j++) p[j] = q[j];
  }
  write(g);
}

関数外の変数は関数内でも利用できる。
それを利用してあまり行儀が良くないが面倒なのでg, i, pは引数として与えていない。
ただしjに関しては同じようにするとi=0や1の時でもfor文でループ本体は実行されないが強制的にj=1となるため、
次のq[i]を生成する段階において存在しないノードを参照してしまいエラーとなる。
そこで引数として処理すべき正しいものを与えてやるようにしている。