/********************************************************
* 再帰的下降型構文解析の例
* E: expressionを加減算の結果とする
* T: term を乗除算の結果
* F: factor 項(被演算子)とする
* i: identifier 識別子(簡単のためアルファベット1文字)
*
* 構文規則(BNF)
* <L>::= <E> '\n'
* <E>::= <T> { {+|-} T}
* <T>::= <F> { {*|/} <F> }
* <F>::= i | ( <E> )
*
応用練習問題
1)Pーマシン言語に翻訳する
2)一桁の数字からなる式の計算する電卓プログラムに改造する。
(2+8)/(7-4) * 5
15
********************************************************/
#include <stdio.h>
void scan();
void error();
void E(); /* 非終端記号Eを解析する関数 */
void T(); /* 非終端記号Fを解析する関数 */
void F(); /* 非終端記号Tを解析する関数 */
char next; /*次のトークン*/
/*******************************************
* <L>::= <E> 改行文字
* lineは開始記号なので
* プログラムを短くするためmainにしてしまう
******************************************/
int main (int argc, char* argv[])
{
scan();
printf("L--->E\n");
E();
if (next != '\n') error();
printf("\n");
exit(0);
}
/*****************************************************
* トークン(非終端記号)を読みこむ関数
* 空白(タブはないものとして)を読み飛ばす
* 字句解析はしばしばスキャナーと呼ばれるので、ここではscan()とする。
****************************************************/
void scan()
{
while ( (next = getchar()) == ' ');
}
/******************************************************
* 簡単のためエラー回復なし、で構文解析終了とする
*****************************************************/
void error()
{
printf("*********error**********\n");
exit(1);
}
/*****************************************
* <E>::= <T> { {+|-} T }
*
* 解析プログラム E( ):
* 最初のトークンは既に読まれている
* T();
* while(トークン == 加算演算子) {
* 次のトークンを読む();
* T();
* }
* 戻るときは次のトークンまで読んでいる
*****************************************/
void E() {
printf("E--->T <E-rest> \n");
T();
if (next !='+' && next !='-')
printf("<E-rest>--->empty\n");
while ( next=='+' || next == '-') {
printf("<E-rest> --->%c T\n", next);
scan();
T();
printf("ADDまたはSUB命令を生成\n");
}
}
/***************************
* <T>::=<F> { {*|/} <F> }
*
*解析プログラムT():
* 最初のトークンは既に読まれている
* F();
* while(トークン == 乗除演算子) {
* 次のトークンを読む();
* F();
* }
* 戻るときは次のトークンまで読んでいる
****************************/
void T() {
printf("T--->F <F-rest>\n");
F();
if (next !='*' && next !='/')
printf("<F-rest>--->empty\n");
while (next=='*' || next=='/') {
printf("<F-rest>---> %c F\n", next);
scan();
F();
printf("MULまたはDIV命令を生成\n");
}
}
/********************************************
* <F>::= <a-zのアルファベット>
* | ( <E> )
*
*解析プログラムF()
* if (トークン == 識別子) {
* 次のトークンを読む();
* }
* else if (トークン == 括弧開き) {
* 次のトークンを読む();
* T();
* 括弧閉じを確定
* 次のトークンを読む();
* }
* 戻るときは次のトークンまで読んでいる
********************************************/
void F() {
if ( next >='a' && next <= 'z' ) {
printf("F--->id(%c)\n", next);
printf("LOAD命令を生成\n");
scan();
}
else if (next == '('){
printf("F --->( E )\n");
scan();
E();
if (next == ')') {
scan();
}
else
error();
}
}