// // a2.c ... 構文解析器の例 // #include #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; }