CMake&yacc&lex

Reference

内容

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})

相关文章

一:display:flex布局display:flex是一种布局方式。它即可以...
1. flex设置元素垂直居中对齐在之前的一篇文章中记载过如何...
移动端开发知识点pc端软件和移动端apppc端软件是什么,有哪些...
最近挺忙的,准备考试,还有其他的事,没时间研究东西,快周...
display:flex;把容器设置为弹性盒模型(设置为弹性盒模型之后...
我在网页上运行了一个Flex应用程序,我想使用Command←组合键...