以下をアセンブラに落としていく
PUSH 2
PUSH 3
PUSH 4
MUL
ADD
スタックへのpushとpop
// 2*3を計算して結果をスタックにプッシュ
push 2
push 3
pop rdi
pop rax
mul rax, rdi
push rax
// 4*5を計算して結果をスタックにプッシュ
push 4
push 5
pop rdi
pop rax
mul rax, rdi
push rax
// スタックトップの2つの値を足す
// つまり2*3+4*5を計算する
pop rdi
pop rax
add rax, rdi
push rax
インタプリターでは構文解析の実行のタイミングで実行するがコンパイラはスタックに値を入れて、opに応じてアッセンブラを実行する
RAXはアキュムレータの「A」
RSIはソースインデックスレジスタ
cqo命令を使うと、RAXに入っている64ビットの値を128ビットに伸ばしてRDXとRAXにセットすることができる
#include <ctype.h> #include <stdarg.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> // token type 構造体 typedef enum { TK_RESERVED, // op TK_NUM, TK_EOF, // end of input } TokenKind; typedef struct Token Token; // token struct Token { TokenKind kind; // token type Token *next; // next token int val; // TK_NUM value char *str; // token char }; // now focus token Token *token; // input program char *user_input; // report error void error_at(char *loc, char *fmt, ...){ va_list ap; va_start(ap, fmt); int pos = loc - user_input; fprintf(stderr, "%s\n", user_input); fprintf(stderr, "%*s", pos, " "); // output pos blank fprintf(stderr, "^ "); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); exit(1); } void error(char *fmt, ...){ va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); exit(1); } // if the next token is expected symbol, read forward one token and // return true. bool consume(char op) { if(token->kind != TK_RESERVED | token->str[0] != op) return false; token = token->next; return true; } // if the next token is expected symbol, read forward one token and // otherwise report an error. void expect(char op) { if(token->kind != TK_RESERVED | token->str[0] != op) error("'%c'ではありません。", op); token = token->next; } // if the next token is expected number, read forward one token and // otherwise report an error. int expect_number() { if(token->kind != TK_NUM) error("数ではありません"); int val = token->val; token = token->next; return val; } bool at_eof() { return token->kind == TK_EOF; } // create a new token and connect it to curl. Token *new_token(TokenKind kind, Token *cur, char *str){ Token *tok = calloc(1, sizeof(token)); tok->kind = kind; tok->str = str; cur->next = tok; return tok; } // Tokenize the input string p and return it Token *tokenize(char *p) { Token head; head.next = NULL; Token *cur = &head; while (*p) { // skip space if(isspace(*p)){ p++; continue; } if(*p == '+' || *p == '-') { cur = new_token(TK_RESERVED, cur, p++); continue; } if(isdigit(*p)) { cur = new_token(TK_NUM, cur, p); cur->val = strtol(p, &p, 10); continue; } error("トークナイズできません"); } new_token(TK_EOF, cur, p); return head.next; } typedef enum { ND_ADD, // + ND_SUB, // - ND_MUL, // * ND_DIV, // / ND_NUM, // num } NodeKind; typedef struct Node Node; struct Node { NodeKind kind; // node type Node *lhs; // left Node *rhs; // right int val; }; 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; } 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(); 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; } } 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; } } Node *primary() { if(consume('(')){ Node *node = expr(); expect(')'); return node; } return new_node_num(expect_number()); } void gen(Node *node) { if(node->kind == ND_NUM) { printf(" push %d\n", node->val); return; } gen(node->lhs); gen(node->rhs); printf(" pop rdi\n"); printf(" pop rax\n"); switch(node->kind) { case ND_ADD: printf(" addd 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) { error("引数の個数が正しくありません\n"); return 1; } user_input = argv[1]; token = tokenize(user_input); Node *node = expr(); printf(".intel_syntax noprefix\n"); printf(".global main\n"); printf("main:\n"); gen(node); printf(" pop rax\n"); printf(" ret\n"); return 0; }