http://www.ibm.com/developerworks/cn/linux/l-lexyac.html
http://www.ibm.com/developerworks/cn/linux/sdk/lex/index.html
http://wenku.baidu.com/view/188c4493daef5ef7ba0d3c7a.html
http://wenku.baidu.com/view/a4434174f46527d3240ce0b4.html
从下列地方可以等到lex 和yacc 工具:
● Mortice Kern System (MKS),在 www.mks.com,
● GNU flex 和 bison,在 www.gnu.org ,
● Ming,在 www.mingw.org,
● Cygwin,在 www.cygwin.org
“lex”和“yacc”这两个名字所代表的也包括这些工具的 GNU 版本 flex 和 bison
终端和非终端符号, 在BNF中使用
C语言的例子:
http://www.quut.com/c/ANSI-C-grammar-y-1998.html#external-declaration
http://www.quut.com/c/ANSI-C-grammar-l-1998.html
一、词法分析器生成工具 Lex
Lex 为词法分析器或扫描器生成C程序代码。
第一段只有C的全局声明;没有token匹配定义;没有include yacc生成的头文件,此文件可能包含命名标记token的定义;
第二段没有return token 终结符给yacc使用;
第三段必须手动添加yywrap定义;如果和yacc联合使用,则main函数转移到yacc中。main在lex中调用yylex,而在yacc中则调用yyparse,其间接调用yylex。
注意:lex程序的默认输入为stdin。
%{
int nchar, nword, nline;
%}
%%
\n { nline++; nchar++; }
[^ \t\n]+ { nword++, nchar += yyleng; }
. { nchar++; }
%%
int main(void) {
yylex();
printf("%d\t%d\t%d\n", nchar, nword, nline);
return 0;
}
int yywrap()
{
return 1;
}
Lex 变量
个人使用心得:
lex文件:
filtercomp = and / or --> filtercomp {and} | {or}
filterlist = 1*filter --> filterlist {filter}+
EXCLAMATION = %x21 ; exclamation mark ("!") --> EXCLAMATION \x21
UTF2 = %xC2-DF UTF0 --> UTF2 [\xC2-\xDF]{UTF0}
二、yacc(Yet Another Compiler Compiler),是一个经典的生成语法分析器的工具
%{
#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发现一个解析错误,默认动作是调用yyerror
定义三个token,在lex中被return。
%{
typedef char* string;
#define YYSTYPE string
%}
%token NAME EQ AGE
%%
file : record file
| record
;
record : NAME EQ AGE {
printf("%s is %s years old!!!\n", $1, $3); }
%%
int main()
{
yyparse();
return 0;
}
int yyerror(char *msg)
{
printf("Error encountered: %s \n", msg);}
执行cat y.tab.h
#ifndef YYERRCODE
#define YYERRCODE 256
#endif
#define NAME 257
#define EQ 258
#define AGE 259
yacc -d file.y
lex file.l
cc lex.yy.c y.tab.c -o file.exe
执行结果:
a=5
a is 5 years old!!!
afds = 32
afds is 32 years old!!!
a=32
a is 32 years old!!!
tt=
fd
Error encountered: syntax error
yacc文件
%union会生成为yylval的定义
#define NUMBER 257
#define NAME 258
#define EQ 259
#define AGE 260
typedef union {
long value;
char *p;
} YYSTYPE;
extern YYSTYPE yylval;
%union { long value; char *p; }
%token <value> NUMBER
%token <p> NAME EQ AGE
%%
file : record file
| record
record : NAME EQ NUMBER {
printf("%s is %d years old!!!\n", $1, $3); }
%%
int main()
{
yyparse();
return 0;
}
int yyerror(char *msg)
{
printf("Error encountered: %s \n", msg);}
lex文件
删除了yylval声明
%{
#include "y.tab.h"
#include <stdio.h>
#include <string.h>
%}
char [A-Za-z]
num [0-9]
eq [=]
name {char}+
age {num}+
%%
{name} { yylval.p = strdup(yytext);
return NAME; }
{eq} { return EQ; yylval.p = strdup(yytext);}
{age} {
yylval.value = strtol(yytext, 0, 10);
return NUMBER;
}
%%
int yywrap(){
return 1;
}
%{
#include "y.tab.h"
#include <stdio.h>
#include <string.h>
%}
char [A-Za-z]
num [0-9]
eq [=]
name {char}+
age {num}+
%%
{name} { yylval.p = strdup(yytext);
return NAME; }
{eq} { return EQ; yylval.p = strdup(yytext);}
{age} {
yylval.value = strtol(yytext, 0, 10);
return NUMBER;
}
%%
int yywrap(){
return 1;}
在lex和yacc文件中声明、定义函数;
在lex文件中一般需要执行yylval = strdup(yytext); 这个yylval需要在yacc中delete。
在yacc文件中一般需要执行字符串串联,如$1和$2需要串起来,采用strdup存储到$$中,否则无法向上反馈。
调试方法,lex文件编译时lex -d file.l;而yacc文件的main中定义yy_flex_debug = 1;这样cc编译才能通过!
lex文件过滤掉空格等,否则有时有莫名其妙的空格打印。[ \t\v\n\f] {}
为了检测出不应该出现的字符,lex文件最后加:. {return ERROR;}匹配检查,但同时要过滤掉“\0" {}匹配动作,否则总是失败。
- 顶
- 0
- 踩
- 0