/*
再帰的下向き構文解析プログラム
（以下の文法に対する構文解析プログラム）
   Expr    -> CON
	    | FunCall
   FunCall -> FID '(' Expr ',' Expr ')'

   -- 以下は終端記号: 字句解析部で処理
   EOL     -> '\n'                    -- End Of Line
   CON     -> '0' | '1' | ... | '9'   --  一桁の数のみ
   FID     -> '+' | '-' | '*' 
 */

#include <stdio.h>
#include <stdlib.h>   /* exit()用 */
#include <ctype.h>    /* isdigit()用 */

/* 大域変数の宣言 */
int token;      /* 入力の先頭のトークンを表す */
int yylval;	/* tokenの属性 */

/* 終端記号に対応するマクロの定義 */
#define CON 256
#define FID 257
#define EOL 258	/* End of Line -- $に相当 */ 

/* 簡易字句解析ルーチン */
int yylex(void) {   
  int c;
  
  do {
    c = getchar ();
  } while (c == ' ' || c == '\t');

  if (isdigit (c)) {
    yylval = c-'0';	/* 数字から数へ変換 */
    return CON;
  }

  if (c == '+' || c== '-' || c == '*' ) {
    yylval = c;
    return FID;
  }

  if (c == '\n') {
    return EOL; /* 行末が $（入力の終わり）に対応する */
  }
  
  if (c == EOF) { /* ファイルの終 */
    exit(0); 
  }
  /* 上のどの条件にも合わなければ、文字をそのまま返す。*/
  return c;   /* '(', ')', ','など */
}

/* token（終端記号）を消費して、次の tokenを読む */
void eat(int t) {	
  if (token == t) {
    token = yylex();
    return;
  } else {
    if (t < 256) {
      printf("%c is expected here.\n", t);
    } else {
      printf("token %d is expected here.\n", t);
    }
    exit (0);
  }
}

/* 関数プロトタイプ宣言 */
void Expr(void);
void FunCall(void);

/* 
   再帰的構文解析関数群
   文法の各非終端記号に対応する関数
 */
void Expr(void) {
  if (token == CON) {
    eat(CON);
  } else if (token == FID) {
    FunCall();
  } else {
    if (token < 256) {
      printf("Unexpected token: \'%c\'", token);
    } else {
      printf("Unexpected token: %d", token);
    }
    printf ("\n");
    exit (0);
  }
}

void FunCall(void) {
  eat(FID); eat('('); Expr(); eat(','); Expr(); eat(')');
}

/* 各行の処理 */
void processLine(void) {
  Expr();
  if (token==EOL) { /* 入力がブロックしないように改行は特別扱い */
    printf("Correct!\n");   /* eat(EOL)の前に出力しておく */
  }
  eat(EOL);
}

/* main関数 */
int main(void) {
  printf("Ctrl-cで終了します。\n");
  token = yylex(); /* 最初のトークンを読む */
  while (1 /* 無限ループ */) {
    processLine();  /* 各行を処理する */
  }
}
