`
xieyj
  • 浏览: 100269 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

yacc介绍

阅读更多

        在mysql源码中,解析sql在sql_yacc.yy中实现,这个文件是一个硕大的文件,用bison来转换为c文件。

        在《编译原理及实践》中有yacc介绍,编译原理是很深奥的科目,学好了对编程技术好很大的帮助,可惜当初没好好学,需要回炉一下。

        这里是从《编译原理及实践》的摘录。

        一个简单的算术表达式的计算器。calc.y,BNF文法如下:


 %{

#include <stdio.h>

#include <ctype.h>

%}

 

%token NUMBER

 

%%

 

command : exp { printf("%d\n", $1);}

                ;

exp : exp '+' term { $$ = $1 + $3 ;}

      | exp '-' term { $$ = $1 - $3 ;}

      | term { $$ = $1 ;}

      ;

term : term '*' factor { $$ = $1 * $3 ;}

        | factor { $$ = $1 ;}

        ;

factor : NUMBER { $$ = $1 ;}

          | '(' exp ')' { $$ = $2 ;} 

          ;

%%

 

main(){

         /*extern int yydebug ;    ------- 此处为debug显示yacc执行调用用

         yydebug = 1 ;*/

        return yyparse();

}

 

int yylex(void){           -------可以通过lex工具来进行词法分析,这里用手工实现

        int c ;

        while( (c = getchar()) == ' ');

        if( isdigit(c) ){

               ungetc(c, stdin);

               scanf("%d", &yylval);

               return (NUMBER);

        }

        if (c == '\n') return 0 ;      ------0表示输入结束,结束词法分析

        return (c) ;

}

 

int yyerror(char* s){

       fprintf(stderr,"%s\n",s);

       return 0 ;

}

       上面的yylex,可以通过lex来实现,这里为手工实现。

       同过main函数可以看出,执行yyparse,这个为yacc这类的工具产生的的方法,就是根据文法执行%%之间的用户定义的操作。

       每个在L A L R ( 1 )分析栈中的符号值都可通过使用以$开始的伪变量来引用。$ $代表刚才被识别出来的非终结符的值,也就是在文法规则左边的符号。伪变量$ 1、$ 2、$ 3等等都代表了文法规则右边的每个连续的符号。

       个人理解就是当文法匹配,执行{}里面的语句。

       执行一下看看效果,bison -y calc.y  gcc y.tab.c -o test ----y.tab.c为自动产生的c文件

       执行./test 


       程序已经可以跑了,当输入12+4回车时,结果已经出来了。

       把main函数的注释去掉,用bison -y -t 产生c文件,再用gcc y.tab.c -o test 编译

       执行./test 

显示如下:

Starting parse

Entering state 0

Reading a token: 12+3   ---此处为手工输入的值

Next token is token NUMBER ()

Shifting token NUMBER ()

Entering state 1

Reducing stack by rule 7 (line 19):   -----19行为factor : NUMBER { $$ = $1 ;}

   $1 = token NUMBER ()

-> $$ = nterm factor ()

Stack now 0

Entering state 6

Reducing stack by rule 6 (line 17):  -----17行为factor { $$ = $1 ;}

   $1 = nterm factor ()

-> $$ = nterm term ()

Stack now 0

Entering state 5

Reading a token: Next token is token '+' ()  ---解析到+号

Reducing stack by rule 4 (line 14):   ----14行为term { $$ = $1 ;}

   $1 = nterm term ()

-> $$ = nterm exp ()

Stack now 0

Entering state 4

Next token is token '+' ()

Shifting token '+' ()

Entering state 9

Reading a token: Next token is token NUMBER ()

Shifting token NUMBER ()

Entering state 1

Reducing stack by rule 7 (line 19):  -----19行为factor : NUMBER { $$ = $1 ;}

   $1 = token NUMBER ()

-> $$ = nterm factor ()

Stack now 0 4 9

Entering state 6

Reducing stack by rule 6 (line 17):  -----17行为factor { $$ = $1 ;}

   $1 = nterm factor ()

-> $$ = nterm term ()

Stack now 0 4 9

Entering state 13

Reading a token: Now at end of input.

Reducing stack by rule 2 (line 12):   ----12行为exp : exp '+' term { $$ = $1 + $3 ;}

   $1 = nterm exp ()

   $2 = token '+' ()

   $3 = nterm term ()

-> $$ = nterm exp ()

Stack now 0

Entering state 4

Now at end of input.

Reducing stack by rule 1 (line 10): ----10行为command : exp { printf("%d\n", $1);}

   $1 = nterm exp ()

15

-> $$ = nterm command ()

Stack now 0

Entering state 3

Now at end of input.

Stack now 0 3

Cleanup: popping nterm command ()

      yacc这东西还挺神奇,java也有个javacc,也能实现同样的功能,amoeba中有用到。

  • 大小: 13.4 KB
  • 大小: 2.7 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics