Reference
- cmake bison command: https://cmake.org/cmake/help/v3.6/module/FindBISON.html
- cmake flex command: https://cmake.org/cmake/help/v3.6/module/FindFLEX.html
内容
CMake处理lex和yacc文件。即自动将lex&yacc文件转换成为c/c++文件,然后生成库文件或可执行文件。
lex
这里只有一个lex文件(test.ll),然后生成可执行文件ttest。——test是cmake保留字,所以这里用ttest。
目录结构
两个子目录:
- test\src: test.ll,CMakeLists.txt
- test\bin: 工作目录,一开始为空,生成的文件都放在这里。
文件
test.ll
%{ #include <string> #include <iostream> %} %% [\t ]+ /* white space */ [a-zA-Z]+ { std::string word(yytext); std::cout<<"word: "<<word<<std::endl; } [0-9]+ { std::string number(yytext); std::cout<<"number: "<<number<<std::endl; } .|\n {ECHO; /* normal default anyway */ } %% int main() { std::cout<<"Lex and C++"<<std::endl; yylex(); return 0; }
CMakeLists.txt
cmake_minimum_required(VERSION 2.8) project(ttest) # bison and flex find_package(BISON) find_package(FLEX) FLEX_TARGET(ttest_lexer test.ll ${PROJECT_BINARY_DIR}/test.cpp) # main set (MAIN_SRC ${PROJECT_BINARY_DIR}/test.cpp) add_executable(ttest ${MAIN_SRC}) # libraries find_library(LEX_LIB l) target_link_libraries(ttest ${LEX_LIB})
或者
cmake_minimum_required(VERSION 2.8) project(ttest) # bison find_package(FLEX) FLEX_TARGET(ttest_lexer test.ll ${CMAKE_CURRENT_BINARY_DIR}/test.cpp) # main add_executable(ttest ${CMAKE_CURRENT_BINARY_DIR}/test.cpp) # libraries find_library(LEX_LIB l) target_link_libraries(ttest ${LEX_LIB})
Run
$ ./ttest Lex and C++ abd 123 word: abd number: 123 ^C
lexer&parser
Files
两个文件:test.ll,test.yy. 最后生成可执行文件ttest。
test.ll
%{ //#include <string> #include "y.tab.h" %} %% [\t ]+ ; [a-zA-Z]+ {return OBJECT;} [0-9]+ {return PRICE;} .|\n {ECHO;}
test.yy
%{ #include <stdio.h> extern int yylex (void); void yyerror(const char *s,...); %} %token OBJECT PRICE %% description: object PRICE { printf("pass...\n"); } ; object: OBJECT ; %% extern FILE *yyin; int main(int argc,const char* argv[]) { if (argc != 2) { printf("Usage: %s filename\n",argv[0]); return 0; } yyin = fopen(argv[1],"rb"); if (NULL == yyin) { printf("Open file failed: %s\n",argv[1]); return 0; } while(!feof(yyin)) { yyparse(); } fclose(yyin); yyin = NULL; return 0; } void yyerror(const char *s,...) { fprintf(stderr,"%s\n",s); }
不用cmake
执行如下命令:
yacc -d test.yy lex test.ll gcc -o test lex.yy.c y.tab.c -ll
运行示例:
$ ./test Usage: ./test filename $ echo phone 1000 > ok.txt $ echo tom jerry > fail.txt $ ./test ok.txt pass... $ ./test fail.txt syntax error $
用cmake
首先修改test.ll中的头文件名称:
#include "y.tab.h" --> #include "parser.h"
同样创建src/bin/CMakeLists.txt。其中cmake文件内容:
cmake_minimum_required(VERSION 3.5) project(ttest) # bison and flex find_package(BISON) find_package(FLEX) BISON_TARGET(ttest_parser test.yy ${CMAKE_CURRENT_BINARY_DIR}/parser.cpp DEFINES_FILE ${CMAKE_CURRENT_BINARY_DIR}/parser.h ) FLEX_TARGET(ttest_lexer test.ll ${CMAKE_CURRENT_BINARY_DIR}/lexer.cpp) # default header file is parser.hpp ADD_FLEX_BISON_DEPENDENCY(ttest_lexer ttest_parser) # main include_directories(${CMAKE_CURRENT_BINARY_DIR}) set (MAIN_SRC ${CMAKE_CURRENT_BINARY_DIR}/lexer.cpp ${CMAKE_CURRENT_BINARY_DIR}/parser.cpp # or ${BISON_ttest_parser_OUTPUTS} ${FLEX_ttest_lexer_OUTPUTS} ) add_executable(ttest ${MAIN_SRC}) find_library(LEX_LIB l) target_link_libraries(ttest ${LEX_LIB})
注意到对于生成的cpp文件的两种引用方式。
另,根据https://cmake.org/cmake/help/v3.6/release/3.4.html的说法,可能cmake版本要求至少是3.4:
The FindBISON module BISON_TARGET macro learned a new DEFINES_FILE option to specify a custom output header to be generated.
lex&parser打包成库文件
假定要把lexer&parser的代码打包成lib,然后供其他的cpp调用。为此,把test.yy中的main()搬到一个新的main.cpp文件中:
#include <stdio.h> extern FILE *yyin; extern int yyparse(); int main(int argc,argv[1]); return 0; } while(!feof(yyin)) { yyparse(); } fclose(yyin); yyin = NULL; return 0; }
然后cmake文件改为:
cmake_minimum_required(VERSION 3.5) project(ttest) # bison and flex find_package(BISON) find_package(FLEX) BISON_TARGET(ttest_parser test.yy ${CMAKE_CURRENT_BINARY_DIR}/parser.cpp DEFINES_FILE ${CMAKE_CURRENT_BINARY_DIR}/parser.h ) FLEX_TARGET(ttest_lexer test.ll ${CMAKE_CURRENT_BINARY_DIR}/lexer.cpp) # default header file is parser.hpp ADD_FLEX_BISON_DEPENDENCY(ttest_lexer ttest_parser) include_directories(${CMAKE_CURRENT_BINARY_DIR}) add_library(myparser ${BISON_ttest_parser_OUTPUTS} ${FLEX_ttest_lexer_OUTPUTS} ) # main add_executable(ttest main.cpp) target_link_libraries(ttest myparser) find_library(LEX_LIB l) target_link_libraries(ttest ${LEX_LIB})