Mercurial > hg > Members > anatofuz > 9cc
changeset 2:75f25ab4022c
update
author | anatofuz <anatofuz@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Thu, 25 Jul 2019 09:00:25 +0900 |
parents | 59c56be5222e |
children | 3cdf1d015159 |
files | 9cc.c Makefile test.sh |
diffstat | 3 files changed, 124 insertions(+), 15 deletions(-) [+] |
line wrap: on
line diff
--- a/9cc.c Wed Jul 24 14:16:31 2019 +0900 +++ b/9cc.c Thu Jul 25 09:00:25 2019 +0900 @@ -1,5 +1,117 @@ +#include <ctype.h> +#include <stdarg.h> +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> + +// kind of token +typedef enum { + TK_RESERVED, // 記号 + TK_NUM, // 整数トークン + TK_EOF, // 終端トークン +} TokenKind; + +typedef struct Token Token; +struct Token { + TokenKind kind; // トークンの型 + Token *next; // 次の入力トークン + int val; // kindがTK_NUMのときに入る + char *str; // トークン文字列 +}; + + +Token *token; +char *user_input; + +// エラー報告用の関数 +// printfと同じ引数を取る +void error(char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + exit(1); +} + +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, ""); // pos個の空白を出力 + fprintf(stderr, "^ "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + exit(1); +} + +// 次のトークンが予想している記号ならtrue +bool consume(char op) { + if (token->kind != TK_RESERVED || token->str[0] != op) + return false; + token = token->next; + return true; +} + +// 予想している記号じゃないとエラーになる +void expect(char op) { + if (token->kind != TK_RESERVED || token->str[0] != op) + error_at(token->str, "'%c'ではありません",op); + token = token->next; +} + +// 数値なら数値を返す + +int expect_number() { + if (token->kind != TK_NUM) + error_at(token->str, "数ではないです"); + int val = token->val; + token = token->next; + return val; +} + +bool at_eof() { + return token->kind == TK_EOF; +} + +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; +} + +Token *tokenize(char *p) { + Token head; + head.next = NULL; + Token *cur = &head; + + while (*p) { + 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_at(token->str, "トーカナイズできないです"); + } + + new_token(TK_EOF, cur, p); + return head.next; +} int main(int argc, char **argv) { if (argc != 2) { @@ -7,28 +119,24 @@ return 1; } - char *p = argv[1]; + user_input = argv[1]; + token = tokenize(user_input); printf(".intel_syntax noprefix\n"); printf(".global main\n"); printf("main:\n"); - printf(" mov rax, %ld\n",strtol(p,&p,10)); + + // 最初は数をチェックする + printf(" mov rax, %d\n",expect_number()); - while (*p) { - if (*p == '+') { - p++; - printf(" add rax, %ld\n", strtol(p,&p,10)); + while (!at_eof()) { + if (consume('+')) { + printf(" add rax, %d\n", expect_number()); continue; } - if (*p == '-') { - p++; - printf(" sub rax, %ld\n", strtol(p,&p,10)); - continue; - } - - fprintf(stderr, "予期しない文字です: '%c'\n", *p); - return 1; + expect('-'); + printf(" sub rax, %d\n", expect_number()); } printf(" ret\n");