Cコンパイラ作成入門のメモ #2 (Step2,3)

はじめに

こちらをやってみたときのメモを書いていく。

www.sigbus.info

今回はStep3まで commitはこちら tokenizerにより空白文字のスキップが可能になった · lvlnaga/9cc@056147d (github.com)

調べたこと

連結リスト

  • リストは「要素」と「次のデータを指し示すポインタ」の2つからなるデータ数珠のようにつながっているデータ構造
  • リストの場合は要素を探すために先頭からポイントをたどる必要あり
  • 配列と比べていい点
    • データの追加、削除がデータ数に関係なく数ステップでできる
      • nextポインタを書き換えればOK

参考

うさぎでもわかる配列と連結リスト | 工業大学生ももやまのうさぎ塾 (momoyama-usagi.com)

tokenizeのところ詳細

書いたのはこれ

// 新しいトークンを作成してcurに繋げる
Token *new_token(TokenKind kind, Token *cur, char *str){
  Token *tok = calloc(1, sizeof(Token)); //? callocの仕様を知りたい
  tok->kind = kind;
  tok->str = str;
  cur->next = tok;
  return tok;
}

// 入力文字列pをトークナイズしてそれを返す
Token *tokenize(char *p){
  Token head; //dummyのhead要素を作る
  head.next = NULL;
  Token *cur = &head; //現在のtokenへのポインタにdummyのheadを設定

  while (*p)
  {
    // 空白文字をスキップ
    if (isspace(*p))
    {
      p++;
      continue;
    }
    
    if (*p == '+' || *p == '-')
    {
      cur = new_token(TK_RESERVED, cur, p++); //(1)
      continue;
    }
    
    if (isdigit(*p))
    {
      cur = new_token(TK_NUM, cur, p); //(2)
      cur->val = strtol(p, &p, 10); 
      continue;
    }

    error("トークナイズできません");
  }

  new_token(TK_EOF, cur, p);
  return head.next; //先頭のトークンを返す
}

(1)について

p++は後置演算子なので現在のpが指し示す位置でtokenを作成した後、 pが次の位置へと進められる。ということ

(2)について

strtol(p,&p,10); で#2引数でpのポインタが次(数字の次の位置)に進められる。
strtolの#2引数には変換が失敗する文字がある位置(数字じゃない文字がある位置)のポインタが入る。
例えば 12 +トークナイズする場合は、12の次の変換失敗する’ ‘ (スペース)の位置が&pに格納される。
すなわちポインタが次に進められる。

参考

文字列を数値に変換(C言語) - 超初心者向けプログラミング入門 (pc-note.net)`

可変個引数、動的引数 (...)について

// エラーを報告するための関数
// printfと同じ引数をとる
void error(char *fmt, ...){ 
  va_list ap;
  va_start(ap, fmt);
  vfprintf(stderr, fmt, ap);
  fprintf(stderr, "\n");
  exit(1);
}

引数の数を可変に受け取れる関数のこと。

stdarg.hで定義されているマクロとセットで基本的に使用する模様。

詳しくは下記。

可変個引数 | Programming Place Plus C言語編 第52章 (programming-place.net)

vprintfについて、詳しくは下記。自前でエラー関数作ったりするときはよくある常套手段のような雰囲気。

vprintf | Programming Place Plus C言語編 標準ライブラリのリファレンス (programming-place.net)