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");
--- a/Makefile	Wed Jul 24 14:16:31 2019 +0900
+++ b/Makefile	Thu Jul 25 09:00:25 2019 +0900
@@ -1,4 +1,4 @@
-CFLAGS=-std=c11 -g -static
+CFLAGS=-std=c11 -g -static -Wall
 
 9cc: 9cc.c
 
--- a/test.sh	Wed Jul 24 14:16:31 2019 +0900
+++ b/test.sh	Thu Jul 25 09:00:25 2019 +0900
@@ -19,5 +19,6 @@
 try 0 0
 try 42 42
 try 21 "5+20-4"
+try 41 " 12 + 34 - 5 "
 
 echo OK