// 
// a2.c ... 構文解析器の例
// 

#include <stdio.h>
#include "base.h"
#include "tokenizer.h"

char *tok = NULL;    // 先読み字句

//【課題a2】
//・文法(生成規則の集まり)により正しい字句の並びを定めることを理解する
//・文法に沿った構文解析手続きの書き方を理解する
//・関数 parse_op() と parse_exp() と parse_seq() の開始時と終了時の表示を
// 有効にして,解析木の走査と構文解析の動作を対応させる

// 演算子の構文解析
void parse_op(void) {
  // op -> "+" | "-"
  //printf("[op");
  if (equal_token(tok, "+")) {    // 選択肢には条件文
    printf("+");
    tok = next_token();    // 字句を処理したら次の字句を先読み
  } else if (equal_token(tok, "-")) {
    printf("-");
    tok = next_token();
  } else {
    error_exit("syntax error");    // 照合に失敗したら誤り処理
  }
  //printf("op]");
}

// 字句の検査と表示
void process_token(int test) {
  if (! test) error_exit("syntax error");   // 照合に失敗したら誤り処理
  printf("%s", tok);
}

// 式の構文解析
void parse_exp(void) {
  // exp -> "(" NAME op NUMBER ")"
  //printf("[exp");
  process_token(equal_token(tok, "("));
  tok = next_token();    // 字句を処理したら次の字句を先読み
  process_token(is_name_token(tok));
  tok = next_token();
  parse_op();    // 左辺の記号には解析処理の呼び出し
  process_token(is_number_token(tok));
  tok = next_token();
  process_token(equal_token(tok, ")"));
  tok = next_token();
  //printf("exp]");
}

// 式の列の構文解析
void parse_seq(void) {
  // seq -> exp*
  //printf("[seq\n");
  while (tok != NULL) {    // 繰り返しには反復文
    parse_exp();
    printf("\n");
  }
  //printf("seq]\n");
}

int main(void) {

  // ソースコードの文字列
  char *source[] = {
    "   ",
    " ( x + 0 ) ",
    "(ab + 12) (cde - 345)",
    // 正しい例や誤った例を追加
    NULL
  };

  // 各文字列の構文解析
  char **p;
  for (p = source; *p != NULL; p++) {
    printf("source: \"%s\"\n", *p);
    tokenize(*p);
    tok = next_token();    // 1字句先読みして解析手続きを呼ぶ
    parse_seq();
  }

  return 0;
}