语法分析 Flex + Yacc (BISON)
Difference
flex 文件中第一部分,加上 #include “y.tab.c”
y.tab.h是bison在翻译代码时自动生成的头文件(这也是为什么我们先翻译.y文件),如果不加上这个头文件,则编译会出错。
第二部分的 action, 会变成 return
事实上,这些符号的定义就在t.tab.h头文件中,它们都是一些互不相同的常量,这也是为什么不使用该头文件就会报错。那么这些符号是bison自动定义的吗?其实不是,我们会在编写bison代码时手动定义这些符号。
第三部分直接略掉,搬到了yacc文件中
makefile 中指令也发生变化
eg: test.l, test.y
bison --yacc -dv test.y
flex -o test.yy.c test.l
gcc -o test.out y.tab.c test.yy.c
文件架构
与flex 文件相同,但是具体语法有所差距
语法
%{ %} 中,需要定义 int yylex(void); void yyerror(char* ); 函数 (flex中有的函数)
%token NUM ADD SUB MUL DIV VAR CR
在%token后面,跟着一些字符串,我们就是在这里定义了这些符号,它们会被翻译成C头文件 #define NUM 123
// 不关心数值,数值没用
被flex引用,然后又通过yylex()函数return回来。
称为标记
第二部分语法规则 (关键)
需要懂得BNF(巴克斯范式), 明白什么是移进和归约 rule-> BNF action—
expression: expression '+' expression
| expression '-' expression
| NUM
;
**【注意】:最后需要;
结尾
第三部分代码
void yyerror(char *str){
fprintf(stderr,"error:%s\n",str);
}
int yywrap(){
return 1;
}
int main()
{
yyparse();
}
这里给出了yyerror
具体的报错操作;
yywrap
函数同之前在flex的讲述;
而yyparse
函数就是bison的语法分析函数。
最后就是yywarp函数,这是一个约束函数,当它返回1时,代表扫描结束,此时结束程序。这个函数在读取多个文件时很有用处,关于它的进阶运用也会在未来而不是现在展开
运行
会自动生成.output
文件(好像),里面是语法分析器的具体实现(语法分析表以及语法规则)
保留值
%union{
int i;
double d;
}
首先,我们用
%union
将yylval
变成了一个联合体,类似于全局变量,方便后续使用
此后,我们发现了%token
的另一种用法:将联合体的一个变量名用尖括号括起,后跟终结符(可以为多个),就能表示它们的值使用的是这个变量。
接着,是从未见过的%type
,其实这与上面%token
的用法一样,也是指示类型,但这次指示的是非终结符。
expression: expression SUB term {$$=$1-$3;}
$1表示的是expression的值, 3 表示的是 t e r m 的值; ( ∗ ∗ 产生式的右部 ∗ ∗ ) 而两者相减后将值传给 3表示的是term的值;(**产生式的右部**) 而两者相减后将值传给 3表示的是term的值;(∗∗产生式的右部∗∗)而两者相减后将值传给$,这就是归约后的符号的值(产生式的左部)
yytext
yytext是lex内部已经定义好的指针变量
lex分析过程是将输入字符串按程序员预先设计好的正则表达式进行匹配
yytext总是指向当前获得匹配的字符串
{NUM} sscanf(yytext,"%d",&yylval.asd); return NUM;
表示,当读到NUM时,将NUM的以值的形式传给yylval.asd
,方便后续使用,(可以进行运算并输出结果的原因)
词法分析 Flex
将词法分析程序 生成可执行文件
write a txtfile named ?.l
run the code in cmd
flex ?.l
flex -o asd.yy.c asd.l
gcc lex.yy.c
gcc -o asd asd.yy.c
then you ll get an excutable file named ?.out
运行 cmd :./?.out
over
Flex
make a lexical analyzer into a “.c” file
内置函数
函数名 | 定义 |
---|---|
yyin | FILE*类型,指向LEX输入文件,缺省情况下指向标准输入 |
yyout | FILE*类型,指向LEX输出文件,缺省情况下指向标准输出 |
yytext | char*类型,指向识别规则中的一个正规式匹配的单词的首字符 |
yyleng | int类型,记录与识别规则中正规式匹配的单词的长度 |
yylex() | 从该函数开始分析,可由lex自动生成 |
yywrap() | 文件结束处理函数,如果返回值为1就停止解析。可以用来解析多个文件。 |
echo | 将yytext打印到yyout |
分析文件
yyin=fopen(“testin.c”,“r”);
yyout=fopen(“testout.txt”,“w”);
【注意】:分析是从yylex开始
【注意】:fopen中的引号是双引号,否则编译能过,但是运行会出错
操作 // 第二部分
第二部分用于定义语法规则
一行表示一种匹配,最后附加的语句表示匹配到之后的动作(多条语句用花括号)
宏定义
ALPHA [a-zA-Z]
VAR {ALPHA}+[a-zA-Z0-9_]*
KEY int|double
DIGIT [0-9]
VALUE [1-9]+{DIGIT}*|{DIGIT}+\.{DIGIT}+
匹配时,{KEY}