view Gears/Xv6/src/gearsTools/generate_stub.pl.md @ 2:b6c284fd5ae4

backup 2020-12-16
author autobackup
date Wed, 16 Dec 2020 15:11:16 +0900
parents e12992dca4a0
children
line wrap: on
line source

# generate_stub.pl

- 入力した.cbcファイル、Interfaceのヘッダファイルを元に.cのファイルを作成する
    - 別にcbc->cに変換するわけではなく、マクロや `*_stub`CodeGearを生成する


## %var

```perl
if (/^\s*(.*)\s+(\w+);$/ ) {
    my $ttype = $1;
    my $tname = $2;
    if ($ttype =~ /^(union|struct|const)?\s*(\w+)/) {
        if ($1 ne 'const') {
            $ttype = $2;
        } else {
            $ttype = "const $2";
        }
    }
    $var{$name}->{$tname} = $ttype;
```             

- `__code`の引数で使う変数がこの`%var`に登録される
    - Interfaceのフィードにあるかないかで生成されるマクロが異なる
- ここで`%var`には `$name`と`$tname(変数名)`, `$ttype(型名)`が登録される
- `$ttype`は`struct|union`は外された状態で登録される
    - これらは `typedef`で外された型名でも使えるので、そちらで生成している
        - そのため`Gearef`のマクロではstructを外した状態で書かれる
- constの場合は `const char`で1つの型なので、constが来ていたらconstを戻している
- いずれにせよポインタの`*`はここでは落とさなければならない    
    - `if ($ttype =~ /^(union|struct|const)?\s*(\w+)/)`の正規表現でポインタを外している
    

# TODO

## OutPutDataGearが2つ存在するケース

Stackのinterfaceで言うところの`get2`と`pop2`のケース

```c
typedef struct Stack<Type, Impl>{
        union Data* stack;
        union Data* data;
        union Data* data1;
        /* Type* stack; */
        /* Type* data; */
        /* Type* data1; */
        __code whenEmpty(...);
        __code clear(Impl* stack,__code next(...));
        __code push(Impl* stack,Type* data, __code next(...));
        __code pop(Impl* stack, __code next(Type* data, ...));
        __code pop2(Impl* stack, __code next(Type* data, Type* data1, ...));
        __code isEmpty(Impl* stack, __code next(...), __code whenEmpty(...));
        __code get(Impl* stack, __code next(Type* data, ...));
        __code get2(Impl* stack, __code next(Type* data, Type* data1, ...));
        __code next(...);
} Stack;
```

`pop2`と`get2`はそれぞれ`__code next`に2つの出力が存在する
- これを取り出して来るのは`pop2`などの呼び出し元が設定したContinuationによって異なる

例えばRedBlackTreeの例題では、このように呼び出している

```c
__code insertCase3(struct RedBlackTree* tree) {
    struct Stack* nodeStack = tree->nodeStack;
    struct Node* uncle;

    if (tree->grandparent->left == tree->parent) {
        uncle = tree->grandparent->right;
    } else {
        uncle = tree->grandparent->left;
    }

    if (uncle && (uncle->color == Red)) {
        // do insertcase1 on grandparent, stack must be pop by two
        tree->parent->color = Black;
        uncle->color = Black;
        tree->grandparent->color = Red;
        tree->current = tree->grandparent;
        goto nodeStack->pop2(insertCase1);
    }
    goto insertCase4();
}
```
上の例題では `goto nodeStack->pop2(insertCase1);`の部分が相当する
- Stackの実装はnodeStack
- pop2に渡している継続は`insertCase1`

この場合、insertCase1はstubでStackのInterfaceから値を2つ取り出す必要がある
- 現状のgenerate_stubはこの出力に対応していないので、👇のようなstubを静的に書いている

```
__code insertCase1_stub(struct Context* context) {
    goto insertCase1(context,
        &Gearef(context, Tree)->tree->Tree.tree->RedBlackTree,
        &context->data[D_Stack]->Stack.data->Node,
        &context->data[D_Stack]->Stack.data1->Node);
}
```

### やりたいこと
- 呼び出すAPIの出力に応じて、継続先のstubをいい感じに整形する
    - 呼び出した先のInterfaceがなんであるかを判定する必要がありそう