比較演算子の実装
https://www.sigbus.info/compilerbook#ステップ7-比較演算子
この節では、<、<=、>、>=、==、!=を実装します。これらの比較演算子は特殊な意味を持っているように見えますが、実際には+や-などと同じように、2つの整数を受け取って1つの整数を返す普通の2項演算子です。+が両辺を足した結果を返すように、例えば==は両辺が同じ場合は1を、違う場合は0を返します。
複数文字のパース対応
code:c
struct Token {
TokenKind kind; // トークンの型
Token *next; // 次の入力トークン
int val; // kindがTK_NUMの場合、その数値
char *str; // トークン文字列
};
これを変更する
code:c
struct Token {
TokenKind kind; // トークンの型
Token *next; // 次の入力トークン
int val; // kindがTK_NUMの場合、その数値
char *str; // トークン文字列
int len; // トークンの長さ ←←←←
};
あわせてconsumeやexpect等の関数も変更する
consume('+')をconsume("+")という引数にしてconsume("==")などができるようにする
code:c
bool consume(char op) {
if (token->kind != TK_RESERVED || token->str0 != op)
return false;
token = token->next;
return true;
}
これを以下に変更
code:c
bool consume(char *op) {
if (token->kind != TK_RESERVED ||
strlen(op) != token->len ||
memcmp(token->str, op, token->len))
return false;
token = token->next;
return true;
}
memcmpで2つのポインタから指定長さの範囲で一致するか比較する
一致するとき0が返る
よってifの部分は以下のときにtrueに到達する
tokenがreservedされていて、
opの長さとtokenの長さが一致していて、
token->strとopが長さの範囲で同じのとき
複数の文字からなる記号をトークナイズする場合、長いトークンから先にトークナイズする必要があります。
たとえば残りの文字列が>から始まっている場合、
まずstrncmp(p, ">=", 2)のように>=である可能性から先にチェックしないで、
>から始まっている可能性をチェックしてしまうと、
>=が>と=という2つのトークンとして誤ってトークナイズされてしまいます。
code:txt
expr = mul ("+" mul | "-" mul)*
mul = unary ("*" unary | "/" unary)*
unary = ("+" | "-")? primary
primary = num | "(" expr ")"
↓
code:txt
expr = equality
equality = relational ("==" relational | "!=" relational)*
relational = add ("<" add | "<=" add | ">" add | ">=" add)*
add = mul ("+" mul | "-" mul)*
mul = unary ("*" unary | "/" unary)*
unary = ("+" | "-")? primary
primary = num | "(" expr ")"
equality, relationalを追加
アセンブラでの比較演算
code:c
case ND_EQ:
printf(" cmp rax, rdi\n");
printf(" sete al\n");
printf(" movzb rax, al\n");
break;
case ND_NE:
printf(" cmp rax, rdi\n");
printf(" setne al\n");
printf(" movzb rax, al\n");
break;
case ND_LT:
printf(" cmp rax, rdi\n");
printf(" setl al\n");
printf(" movzb rax, al\n");
break;
case ND_LE:
printf(" cmp rax, rdi\n");
printf(" setle al\n");
printf(" movzb rax, al\n");
break;