読者です 読者をやめる 読者になる 読者になる

テストステ論

高テス協会会長が, テストステロンに関する情報をお届けします.

(macro-of-inline report) non-void関数のvoid化(大体)終了

今, 10:30PM. くらくらする.

non-void関数もvoidにしてしまえば, マクロ化出来ると思いついたのが昨日で, 今朝には罠を見つけて, 会社にいる時も大体これをやって, 帰り際に難しさに気づいて, 帰ってきたらさらに難しいことに気づいて, もうどうしようもないと思ったが, 難しいところは出来たような気がする. 早く寝たい.

入力として以下のようなコードを考える.

inline int f(void) { return 0; }
inline int g(int a, int b) { return a * b; }

inline int h1(int x) { return x; }
int h2(int x) { return x; }
inline int h3(int x) { return x; }

void r(int x) {}

int foo()
{
        int x = f();
        r(f());
        x += 1;
        int y = g(z, g(y, f()));
        int z = 2;
        int hR = h1(h1(h2(h3(0))));
        int p;
        return g(x, f());
}

void化は, 関数定義の変更と呼び出し側(ここではfoo関数)の変更があるのだが, 後者がとにかく難しい.

前者は3Hくらいの実装で終わった. 例えば関数gは以下のようになる. これは紛れも無くイージー.

inline void g(int a, int b, int *retval)
{
  *retval = a * b;
  return;
}

foo()は以下のようになる.

int foo()
{
  int npvpCjVySKyLexiL;
  int PBhxBcOfZROvhfQX;
  int HaGQYqsguZjgpFFR;
  int qoZwoOBaVsNpQjRJ;
  int kPSYBVGYKuIvCpAd;
  int YUSiuOdFDseYttlb;
  int x;
  int y;
  int z;
  int hR;
  int p;
  x = f();
  YUSiuOdFDseYttlb = f();
  r(YUSiuOdFDseYttlb);
  x += 1;
  qoZwoOBaVsNpQjRJ = f();
  kPSYBVGYKuIvCpAd = g(y, qoZwoOBaVsNpQjRJ);
  y = g(z, kPSYBVGYKuIvCpAd);
  z = 2;
  PBhxBcOfZROvhfQX = h3(0);
  HaGQYqsguZjgpFFR = h1(h2(PBhxBcOfZROvhfQX));
  hR = h1(HaGQYqsguZjgpFFR);
  npvpCjVySKyLexiL = f();
  return g(x, npvpCjVySKyLexiL);
}

FuncCallがネストしている場合が地獄だ. 難しくしている理由は2点:

  1. 外で定義した関数を, 引数や変数がシャドウイングする可能性がある. そのため, スコープを意識してシンボル表を管理し続ける必要がある.

  2. ネストは, inlineのものとそうでないものがネストする可能性がある. その中で, inlineのものだけを切り出す(randvar = expr)必要がある. しかもそれは, ネストの深い位置から計算するという順序を保存する必要がある. もとのhR =の行がどう展開されたかを見ると良い.

後者が難しくなってる理由は, pycparserがNodeVisitorが自身を書換えることを想定して設計されていないためだ. そのため, かなりややこしいコードになってしまう. そもそも, pycparserは, macro-of-inlineのようにASTをむちゃくちゃ書き換える異常者向けではない.


残りは簡単だ. var = fun()の形をfun(&var)に直していけばいい.

return文のところが少し誤ってると思うが, たぶんなんとかなるだろう. たぶん, return(args)とみないといけないんだろう.