ポインターの演算はポインターだったらポインターのサイズ分加算などする必要があります。
1 2 3 4 5 | int *p; int list[3]; list[2] = 12; p = list; return *(p + 2); |
上記の場合、pは2を足すのではなく、8足す必要があります。
(pはintのポインターで+2はアドレスで8bit進める必要がある為)
初めのアプローチ
ポインターの加算なので、ポインターだったらグローバルな変数にオフセットを入れておいて
数値が出た時に掛け算する方法です。
初めはこの方法でうまくいっていたのですが、パースしながら行うのは限界がありました。
現在のアプローチ
コード生成の処理の前に、トークナイズした情報をいったん検査して
ポインターの加減算の時に数値の値を調整する様にしました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | #include "9cc.h" int current_pointer_offset_ = 1; int offset_of_variable(Variable *val_info) { if (val_info->type->ty == INT ) { // INTの変数 return 1; } if (val_info->type->ty == PTR && val_info->type->ptrof->ty == INT ) { // INTへのポインター return SIZE_OF_INT; } if (val_info->type->ty == PTR && val_info->type->ptrof->ty == PTR) { // ポインターへのポインター return SIZE_OF_ADDRESS; } if (val_info->type->ty == ARRAY && val_info->type->ptrof->ty == INT ) { // INT 配列へのポインター return SIZE_OF_INT; } // ここに来たら対応不足 error( "不明な変数型です." , "" ); return 1; } void walk(Node *node) { if (node == NULL) return ; switch (node->ty) { case ND_NUM: node->val = node->val * current_pointer_offset_; return ; case '+' : case '-' : // 左のNodeの値が変数の場合、+,-の計算の際にオフセットを設定する // その後数値が出てきた時には、値にオフセットを掛ける if (node->lhs->ty == ND_IDENT) { int before_offset = current_pointer_offset_; Variable *val_info = map_get(variables, node->lhs->name); current_pointer_offset_ = offset_of_variable(val_info); walk(node->rhs); current_pointer_offset_ = before_offset; return ; } } walk(node->lhs); walk(node->rhs); } void sema() { for ( int i = 0; i < functions->len; i++) { Function *function = (Function *)functions->data[i]; // ローカル変数のMapをグローバル領域にコピー (値の定義はcodegen.cにある) variables = function->variables; for ( int i = 0; i < function->code->len; i++) { // オフセットを初期化 current_pointer_offset_ = 1; Node *node = function->code->data[i]; walk(node); } } } |
今の所これでテストはパスしています。
0 件のコメント :
コメントを投稿