Skip to content

Commit

Permalink
Add *, / and ()
Browse files Browse the repository at this point in the history
  • Loading branch information
lvlnaga committed Jan 3, 2023
1 parent 2eb68f1 commit f1b1a96
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 22 deletions.
17 changes: 17 additions & 0 deletions .vscode/c_cpp_properties.json
@@ -0,0 +1,17 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [],
"compilerPath": "/usr/bin/gcc-9",
"cStandard": "c11",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}
Binary file added 9cc-memo.xmind
Binary file not shown.
168 changes: 146 additions & 22 deletions 9cc.c
Expand Up @@ -7,7 +7,7 @@

// トークンの種類
typedef enum
{ //? enumの書き方ってこうだっけ?
{
TK_RESERVED, // 記号
TK_NUM, // 整数トークン
TK_EOF, // 入力の終わりを表すトークン
Expand All @@ -33,7 +33,7 @@ Token *token;
// エラーを報告するための関数
// printfと同じ引数をとる
void error(char *fmt, ...)
{ // これって省略ってこと? こんな書き方ある?
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
Expand Down Expand Up @@ -118,7 +118,8 @@ Token *tokenize()
continue;
}

if (*p == '+' || *p == '-')
// if (*p == '+' || *p == '-' || *p == '*' || *p == '/' || *p == '(' || *p == ')' )
if (strchr("+-*/()",*p)) //strchrってどういう関数?
{
cur = new_token(TK_RESERVED, cur, p++);
continue;
Expand All @@ -138,41 +139,164 @@ Token *tokenize()
return head.next; // 先頭のトークンを返す
}

//
// パーサ
//

// 抽象構文木のノードの種類
typedef enum
{
ND_ADD, // +
ND_SUB, // -
ND_MUL, // *
ND_DIV, // /
ND_NUM // 整数
} NodeKind;

// 抽象構文木のノードの型
typedef struct Node Node;
struct Node
{
NodeKind kind; // ノードの型
Node *lhs; // 左辺
Node *rhs; // 右辺
int val; // kindがND_NUMの場合のみ使う
};

// ノード作成関数for2項演算子
Node *new_node(NodeKind kind, Node *lhs, Node *rhs)
{
Node *node = calloc(1, sizeof(Node));
node->kind = kind;
node->lhs = lhs;
node->rhs = rhs;
return node;
}

// ノード作成関数for数値
// 左辺, 右辺は設定不要
Node *new_node_num(int val)
{
Node *node = calloc(1, sizeof(Node));
node->kind = ND_NUM;
node->val = val;
return node;
}

Node *expr();
Node *mul();
Node *primary();

// expr = mul ("+" mul | "-" mul)*
// +,- : 左結合演算子
Node *expr()
{
Node *node = mul();
for (;;)
{
if (consume('+'))
node = new_node(ND_ADD, node, mul());
else if (consume('-'))
node = new_node(ND_SUB, node, mul());
else
return node;
}
}

// mul = primary ("*" primary | "/" primary)*
// *,/ : 左結合演算子
Node *mul()
{
Node *node = primary();
for (;;)
{
if (consume('*'))
node = new_node(ND_MUL, node, primary());
else if (consume('/'))
node = new_node(ND_DIV, node, primary());
else
return node;
}
}

// primary = num | "(" expr ")"
Node *primary()
{
// 次のトークンが"("なら、"(" expr ")"のはず
if (consume('('))
{
Node *node = expr();
expect(')');
return node;
}

// そうでなければ数値のはず
return new_node_num(expect_number());
}

//
// Code generator
//

void gen(Node *node);
// こういう定義の仕方ってプロトタイプ関数っていうんだっけ?

void gen(Node *node)
{
if (node->kind == ND_NUM )
{
printf(" push %d\n", node->val);
return; //空returnはどう解釈される?
}

gen(node->lhs);
gen(node->rhs);

printf(" pop rdi\n");
printf(" pop rax\n");

switch (node->kind)
{
case ND_ADD:
printf(" add rax, rdi\n");
break;
case ND_SUB:
printf(" sub rax, rdi\n");
break;
case ND_MUL:
printf(" imul rax, rdi\n");
break;
case ND_DIV:
printf(" cqo\n");
printf(" idiv rdi\n");
break;
}

printf(" push rax\n");
}

int main(int argc, char **argv)
{
if (argc != 2)
{
fprintf(stderr, "引数の個数が正しくありません\n");
error("%s: 引数の個数が正しくありません", argv[0]);
return 1;
}

// トークナイズしてパースする
user_input = argv[1];
// トークナイズする
token = tokenize();
Node *node = expr();

// アセンブリ前半部分を出力
printf(".intel_syntax noprefix\n");
printf(".globl main\n");
printf("main:\n");

// 式の最初は数でなければならないので、それをチェックして
// 最初のmov命令を出力
printf(" mov rax, %d\n", expect_number());

// `+ <数>`あるいは`- <数>`というトークンの並びを消費しつつ
// アセンブリを出力
while (!at_eof())
{
if (consume('+'))
{
printf(" add rax, %d\n", expect_number());
continue;
}

expect('-');
printf(" sub rax, %d\n", expect_number());
}
// 抽象構文木を下りながらコード生成
gen(node);

printf(" pop rax\n");
printf(" ret\n");
return 0;
}
3 changes: 3 additions & 0 deletions test.sh
Expand Up @@ -20,5 +20,8 @@ assert 0 0
assert 42 42
assert 21 "5+20-4"
assert 41 " 12 + 34 - 5 "
assert 47 '5+6*7'
assert 15 '5*(9-6)'
assert 4 '(3+5)/2'

echo OK

0 comments on commit f1b1a96

Please sign in to comment.