Lex和Yacc的分工
Lex用于词法分析,Yacc用于语法分析,二者可以单独使用,亦可配合工作。Yacc和Lex都是基于C语言的,语法极其相似,功能上Yacc和Lex有部分重叠,但是二者有一点区别:Yacc不能表达数字[0-9]+,也不能获得相应的数值;Yacc还不能忽略空白和注释。而这两点恰恰Lex可以办到。通常,Lex用于数字、空格和注释的解析,Yacc用于表达式解析。
Lex模板
/* C 和 Lex 的全局声明 */
%%
/* 模式(C 代码) */
%%
/* C 函数 */
Yacc模板
%{
/* C声明 */
#include <stdio.h>
%}
/* yacc 定义 */
%%
/* 输入及其对应的动作的C描述 */
%%
/* C 代码 */
int main(void)
{
return yyparse();
}
int yylex(void)
{
return getchar();
}
void yyerror(char *s)
{
fprintf(stderr, "%s\n", s);
}
%%
示例程序
Lex name.lex
%{
#include "y.tab.h"
#include <stdio.h>
#include <string.h>
extern char* yylval;
%}
char [A-Za-z]
num [0-9]
eq [=]
name {char}+
age {num}+
%%
{name} { yylval = strdup(yytext); return NAME; }
{eq} { return EQ; }
{age} { yylval = strdup(yytext); return AGE; }
%%
int yywrap()
{
return 1;
}
Yacc name.y
%{
#include <stdio.h>
#define YYSTYPE char* /*a Yacc variable which has the value of returned token */
%}
%token NAME EQ AGE
%%
file: record file | record;
record: NAME EQ AGE
{
printf("%s is now %s years old!!1", $1, $3);
};
%%
int main()
{
yyparse();
return 0;
}
int yyerror(char* msg)
{
printf("Error: %s encountered \n", msg);
}
如何编译与运行
lex : .lex -> lex.yy.c
yacc : .y -> y.tab.c + y.tab.h
gcc : lex.yy.c + y.tab.h + lex.yy.cc -> a.out
a.out : input -> result
# cat /etc/redhat-release
Red Hat Enterprise Linux Server release 7.2 (Maipo)
# lex name.lex
# yacc -d name.y
# cc lex.yy.c y.tab.h y.tab.c
# ./a.out
hello=3
hello is now 3 years old!!1
参考
[1] Yacc 与 Lex 快速入门
[2] Example of Formalising a Grammar for use with Lex & Yacc
网友评论