yacc学习笔记(一)基础语法

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 //测试

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: C语言中使用lex和yacc来写语法解析器需要分成两步:第一步使用lex工具来生成词法分析器,第二步使用yacc工具来生成语法分析器。 下面是一个简单的语法解析器的例子,它可以识别简单的算术表达式,支持加减乘除运算: 1. lex文件: ``` %{ #include <stdio.h> #include "y.tab.h" %} digit [0-9] %% {digit}+ { yylval = atoi(yytext); return NUMBER; } "+" { return ADD; } "-" { return SUB; } "*" { return MUL; } "/" { return DIV; } [ \t\n] /* ignore whitespace */ . /* anything else is an error */ %% ``` 2. yacc文件: ``` %{ #include <stdio.h> int yylex(); %} %token NUMBER ADD SUB MUL DIV %left ADD SUB %left MUL DIV %% expr: expr ADD expr { printf("%d\n", $1 + $3); } | expr SUB expr { printf("%d\n", $1 - $3); } | expr MUL expr { printf("%d\n", $1 * $3); } | expr DIV expr { printf("%d\n", $1 / $3); } | NUMBER { printf("%d\n", $1); } ; %% ``` 最后使用命令行工具将这两个文件分别编译成C代码 ``` lex lex.l yacc -d yacc.y gcc lex.yy.c y.tab.c -o calculator ``` 编译成功后,就可以使用./calculator来运行该语法解析器了。 注意:这只是一个简单的例子,没有考虑错误处理等问题,实际应用中需要进行更多的处理。 ### 回答2: C语言通过使用Lex和Yacc工具来编写语法解析器,可以实现对输入文本的分析和解析。 首先,我们需要编写一个Lex文件,这个文件定义了词法分析器的规则。在这个文件中,我们需要指定一些正则表达式模式和对应的操作。 一个简单的词法分析器文件(例如sample.l)可能如下所示: ``` %{ #include "y.tab.h" %} %% [0-9]+ { yylval = atoi(yytext); return NUMBER; } [a-zA-Z]+ { yylval = strdup(yytext); return IDENTIFIER; } [ \t\n] /* skip whitespace characters */ . { return yytext[0]; } %% ``` 然后,我们还需编写一个Yacc文件,它定义了语法分析器的规则。在这个文件中,我们需要指定一些语法规则和对应的动作。 一个简单的语法分析器文件(例如sample.y)可能如下所示: ``` %{ #include <stdio.h> #include <stdlib.h> %} %token NUMBER IDENTIFIER %left '+' '-' %% expression : NUMBER { printf("%d\n", $1); } | IDENTIFIER { printf("%s\n", $1); } | expression '+' expression { printf("%d\n", $1 + $3); } | expression '-' expression { printf("%d\n", $1 - $3); } ; %% int main() { yyparse(); return 0; } ``` 完成以上文件编写后,我们需要在终端中执行如下命令进行编译: ```bash flex sample.l yacc -d sample.y gcc -o sample lex.yy.c y.tab.c -ll ``` 接着,我们可以通过执行生成的可执行文件来测试输入的文本: ```bash ./sample ``` 输入相关的文本后,语法解析器将根据我们在Yacc文件中定义的语法规则对输入进行解析,并输出结果。 以上是一个简单的利用C、Lex和Yacc编写的语法解析器的示例。在实际应用中,我们可以依照自己的需求编写更复杂、丰富的语法规则和操作,从而实现更强大的语法解析功能。 ### 回答3: C语言中,可以使用lex和yacc工具生成一个简单的语法解析器。 1. 首先,使用lex工具创建一个词法分析器。词法分析器负责将输入的字符序列转化为标记序列。 例如,我们创建一个名为lex.l的文件,其中包含词法规则: ``` %{ #include <stdio.h> %} %% [0-9]+ { printf("NUMBER: %s\n", yytext); } [a-zA-Z]+ { printf("IDENTIFIER: %s\n", yytext); } .|\n {} %% int main() { yylex(); return 0; } ``` 2. 接下来,使用yacc工具创建一个语法解析器。语法解析器根据词法分析器生成的标记序列进行语法分析,并执行相应的操作。 创建一个名为yacc.y的文件,其中包含语法规则和对应的操作。 ``` %{ #include <stdio.h> %} %token NUMBER IDENTIFIER %% statement : NUMBER { printf("Number: %s\n", $1); } | IDENTIFIER { printf("Identifier: %s\n", $1); } ; %% int main() { yyparse(); return 0; } ``` 3. 在命令行中使用以下命令编译并生成可执行文件: ``` lex lex.l yacc -d yacc.y gcc lex.yy.c y.tab.c -o parser ``` 4. 执行生成的可执行文件。 ``` ./parser ``` 输入一些表达式或标识符之后,词法分析器将会生成对应的标记,然后语法解析器将会对这些标记进行语法分析,并执行相应的操作。 以上是使用c、lex和yacc工具编写一个简单的语法解析器的基本步骤。根据具体的语法和需求,对lex和yacc文件中的规则和操作进行修改,即可实现更加复杂和完整的语法解析器。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值