yacc的功能:
sql解析中的語法分析工具,和flex配合使用。
yacc不能分析什麼:
1、不能處理歧義語法,在歧義語法中,同樣的輸入符合多個分析樹
2、不能處理需要向前看多於一個標記才能確定它是否已經匹配一條規則的語法。
yacc與lex的通信:
詞法分析程序將標記返回給語法分析程序時,如果標記有相關的值,詞法分析程序在返回之前都必須在yylval中存儲值。
yylval默認爲int型,在更復雜的語法分析程序中,yacc將yylval定義爲一個union類型,放置在y.tab.h中。
yacc語法分析程序結構:
定義段:處理yacc生成的語法分析程序的控制信息,建立語法分析程序的執行環境
規則段:包含語法分析程序的規則;
代碼段:被逐字拷貝到生成的C程序中的C代碼
定義段常見內容:
1、標記的描述
例:/* ordinary key words in alphabetical order */
%token ABORT_P ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER
注意:可以將單個被引起來的字符作爲標記而不用聲明它們,所以不需要聲明“=”、“+”或“-”
2、%type聲明
用%type 聲明非終結符的類型,每個聲明都有如下格式:
%type name,name…
"type"名字必須由“%union"定義,每個name都是一個非終結符的名字
3、%union聲明
%union聲明標識符號值的所有可能C類型,聲明採用這種格式:
%union {
…域聲明…
}
域聲明被逐字拷貝到輸出文件中YYSTYPE類型的C聯合類型聲明中
在沒有%union聲明時,yacc將YYSTYPE定義爲int,所以所有的符號值都是整數
例:
%union
{
core_YYSTYPE core_yystype;
/* these fields must match core_YYSTYPE: */
int ival;
char *str;
const char *keyword;
char chr;
bool boolean;
JoinType jtype;
DropBehavior dbehavior;
OnCommitAction oncommit;
List *list;
Node *node;
......
}
4、結合規則(associativity)聲明:%left 左結合性聲明,%right 右結合性聲明,%nonassoc 聲明沒有結合規則
例:
%left ‘+’ ‘-’
%left ‘*’ ‘/’
yacc與lex程序結構都包括定義段、規則段、代碼段三段,但規則段語法有以下不同:
1、和lex不同,yacc不關心行邊界,你會發現大量的空白會使程序更容量閱讀
2、分析程序增加了一條新規則:語句可以是純表達式,也可以是一個賦值
規則段
起始符號:第一條規則左側的符號通常是起始符號,但可以在定義部分使用%start聲明覆蓋它
%prec: 聲明所用標記的優先級,常與聲明段的%nonassoc配合使用,例:
%left '-' '+'
%left '*' '/'
%nonassoc UMINUS
%%
expression: expression '+' expression {$$=$1+$3;}
| expression '-' expression {$$=$1-$3;}
| expression '*' expression {$$=$1*$3;}
| expression '/' expression
{ if($3==0.0)
yyerror("divide by zero");
else
$$=$1/$3;
}
| '-' expression %prec UMINUS {$$=-$2;} //%prec告訴yacc爲這條規則使用UMINUS的優先級
%%
lex+yacc實現簡單計算器程序:
詞法分析程序ch1-1.l:
%{
#include "y.tab.h"
extern int yylval;
%}
%%
[0-9]+ {yylval=atoi(yytext); return NUMBER;}
[ \t] ;
\n return 0;
. return yytext[0];
%%
int yywrap()
{
return 1;
}
語法分析程序ch1-1.y
%{
#include <stdio.h>
%}
%token NAME NUMBER
%%
statement: NAME '=' expression
| expression {printf("=%d\n",$1);}
;
expression: expression '+' NUMBER {$$=$1+$3;}
| expression '-' NUMBER {$$=$1-$3;}
| NUMBER {$$=$1;}
;
%%
extern FILE *yyin;
int main(){
do{
yyparse();
}while(!feof(yyin));
}
void yyerror(char *s){
fprintf(stderr,"%s\n",s);
}
~
編譯及運行:
lex ch1-1.l //生成lex.yy.c
yacc -d ch1-1.y //生成y.tab.c和y.tab.h
cc -o test y.tab.c lex.yy.c //生成可執行文件
./test //測試