我們在前幾天試著做出一個簡單的加法計算機。我們今天來試著擴充這個計算機的功能,讓它可以做加減乘除四種運算。
當然,我們可以直接加入另外三種運算方式的規則,像是下面這樣:
expr_add: NUMBER '+' NUMBER { $$ = $1 + $3; }
expr_minus: NUMBER '-' NUMBER { $$ = $1 - $3; }
expr_mul: NUMBER '*' NUMBER { $$ = $1 - $3; }
expr_div: NUMBER '/' NUMBER { $$ = $1 / $3; }
這樣的寫法當然是沒問題,但如果要再擴充幾十個規則,那就要取幾十個規則名稱,實在是太辛苦了。
既然這些規則的架構都一樣,是對兩個數字做運算,我們便可以使用OR語法把這些規則寫在一起。
Yacc中的OR語法規則(也稱為選擇語法規則)用於定義多個可能的選項之間的選擇。當輸入中的一個結構可以匹配多個可能的規則時,OR語法規則允許解析器選擇其中一個選項來匹配輸入。
在Yacc檔案中,OR的寫法跟C++一樣,用 |
符號表示。因此,上述的規則可以改寫成下面的樣子:
expr:
NUMBER '+' NUMBER { $$ = $1 + $3; }
| NUMBER '-' NUMBER { $$ = $1 - $3; }
| NUMBER '*' NUMBER { $$ = $1 * $3; }
| NUMBER '/' NUMBER { $$ = $1 / $3; }
;
這樣一來,就不用每個運算都取一個名字了,而且做後續的修改與維護都變得更加方便!
請實作出一個簡易的計算機,能夠對兩個正整數做運算(加減乘除其中之一),並回傳結果。
由於之前的範例中,我們只有定義+號的token,因此要補上其他三個運算符號。
我們可以利用Regular Expression把四個運算符寫在一起,這樣更加簡潔。
%{
#include "main.h"
#include "yacc.tab.h"
%}
posint ([0-9]+)
blank_chars ([ \f\r\t\v]+)
expressions ([-*+/])
%%
{posint} { yylval = atoi(yytext); return NUMBER; }
{expressions} { return yytext[0]; }
{blank_chars} { ; }
\n { ; }
%%
int yywrap(void) {
return 1;
}
我們只要將Yacc規則改寫一下就可以了,其他部分跟之前一樣。
expr:
NUMBER '+' NUMBER { $$ = $1 + $3; printf("%d\n", $$); }
| NUMBER '-' NUMBER { $$ = $1 - $3; printf("%d\n", $$); }
| NUMBER '*' NUMBER { $$ = $1 * $3; printf("%d\n", $$); }
| NUMBER '/' NUMBER { $$ = $1 / $3; printf("%d\n", $$); }
;
今天我們成功的用OR語法規則將多個相似的結構寫在一起,非常方便。