1. 例子1
功能:从标准输入读取一行,分析出其中包含的数字个数和字母个数。
/* filename: input.lex */%{ int digitCount = 0; int letterCount = 0;%}digit [0-9]letter [a-zA-Z]newline \n%%{digit} digitCount++;{letter} letterCount++;{newline} return 0;%%int yywrap() { return 1;} /* main */int main() { yylex(); printf("Numbers: %d, Letters: %d\n", digitCount, letterCount); return 0;}
测试运行:
#flex input.lex #gcc lex.yy.c #./a.out 123abc456defghNumbers: 6, Letters: 8#
说明:理解yylex()函数的作用,其用于进行扫描,每次调用yylex()都是从上一次扫描结束的地方开始。对于这里,只调用了一次,所以就是从标准输入的第一个字符开始扫描。那么,其何时返回呢?遇到return或者文件结束才会返回,所以这里需要newline时候return 0,否则,程序没法结束。
2. 例子2
实际的编译器工作的流程,一般来说扫描器扫描到匹配的token都需要返回,经过一些处理,然后继续扫描,而且一般的编译器的输入都是文件。下面实现一个类似的例子,以文件作为输入,当然,这里不修改输出,一般输出都会结合其他接口去使用,比如yacc。
/* filename: input.lex */%{ int digitCount = 0; int letterCount = 0; #define TOKENDIGIT 1 #define TOKENLETTER 2%}digit [0-9]letter [a-zA-Z]newline \n%%{digit} digitCount++;return TOKENDIGIT;{letter} letterCount++;return TOKENLETTER; /*{newline} return 0;*/%%int yywrap() { return 1;}void setInputfile(const char* filename) { FILE* fp = fopen(filename, "r"); if (filename == NULL || fp == NULL) { printf("Cannot open source file\n"); exit(0); } yyin = fp;} /* main */int main(int argc, char* argv[]) { if (argc != 2) { printf("Only and must accept 1 auguments\n"); exit(0); } setInputfile(argv[1]); int token = yylex(); while(token != 0) { printf("Token type: %d, token: %s, token length: %d\n", token, yytext, yyleng); token = yylex(); // get next token } printf("Numbers: %d, Letters: %d\n", digitCount, letterCount); return 0;}
测试运行:
#flex input.lex #gcc lex.yy.c #cat test.txt 1ab2d3f#./a.out test.txt Token type: 1, token: 1, token length: 1Token type: 2, token: a, token length: 1Token type: 2, token: b, token length: 1Token type: 1, token: 2, token length: 1Token type: 2, token: d, token length: 1Token type: 1, token: 3, token length: 1Token type: 2, token: f, token length: 1Numbers: 3, Letters: 4#
PS:如果读到文件尾,那么yylex()返回值为0,所以这里是while(token != 0)