/* 中綴符號計算機 */
%{
#define YYSTYPE double /*定義語義值的C資料類型*/
#include <math.h>
#include <stdio.h>
#include <ctype.h>
int yylex (void);
void yyerror (char const *);
%}
%token NUM /*記號類型,僅有NUM一種*/
%left '-' '+' /*定義+,-運算為左結合*/
/* 所謂左結合是指1+2+3這個運算式
是這樣計算的: (1+2)+3
而最明顯的右結合x=y=z則這麼算:x=(y=z)
*/
%left '*' '/' /*越靠後優先順序越高*/
%left NEG /*由於負號與減號相同,這裡用另一個符號註明,後面有說明*/
%right '^' /*冪運算為右結合*/
%%
input: /*輸入可以是空串,這使當程式一開始就接收到EOF不致於發生錯誤*/
| input line /*也可以是一行*/
;
line: '/n' /*一行可以簡單的一個斷行符號,這時忽略處理*/
| exp '/n' { printf ("/t%.10g/n", $1); }
/*如果是運算式,則列印exp的語義值,而本句的語義值將被廢棄*/
;
exp: NUM { $$ = $1; }
/*運算式可以僅為一個數字,這時賦值本句的語義值為此數字*/
| exp '+' exp { $$ = $1 + $3; }
/*運算式可以為一個運算式加上另一個,相應的語義值也相加,下同*/
| exp '-' exp { $$ = $1 - $3; }
| exp '*' exp { $$ = $1 * $3; }
| exp '/' exp { $$ = $1 / $3; }
| '-' exp %prec NEG { $$ = -$2; }
/*出現這種文法結構則它的優先順序與NEG相同*/
| exp '^' exp { $$ = pow ($1, $3); }
| '(' exp ')' { $$ = $2; }
;
%%
/*主函數直接調用yyparse進行分析*/
int main (void)
{
return yyparse ();
}
/*詞法分析函數
這本來是lex該做的東西,這裡換手寫了
這個函數簡單地把流中的數字挑出來,其它的以字元形式返回
返回小於或等於0則yyparse會認為輸入結束
*/
int yylex (void)
{
int c;
while ((c = getchar ()) == ' ' || c == '/t');
if (c == '.' || isdigit (c)) {
ungetc (c, stdin);
scanf ("%lf", &yylval);
return NUM;
}
if (c == EOF) return 0;
return c;
}
/*錯誤處理,簡單地列印出來*/
void yyerror (char const *s)
{
fprintf (stderr, "%s/n", s);
}
======================
編譯:$ yacc calc.y
$ gcc -o calc y.tab.c