Search code examples
macrosflex-lexer

Can C macros be expanded in flex?


From what I gather, the following won't work in flex:

...
std::string opt_val = "--help";

%%
opt_val { /* do something */ }
%%

Can I expand a C macro instead? I've tried this:

%{
#define MCR_OPTION "--help"
%}

ALIAS_OPTION MCR_OPTION

%%
{ALIAS_OPTION} { /* do something */ }
%%

Unfortunately, this doesn't seem to work. I want to keep the string literal values someplace else than the rule section of the scanner, so that if they change, I will have one less place to update. Am I missing something obvious?

(EDIT): Here is a more complete sample that I tested:

test.l

%option noyywrap

%{
#include <iostream>
#define MCR_HELP_OPT "--help"
#define MCR_HELP_OPT2 --help
%}

ALIAS_HELP_OPT MCR_HELP_OPT
ALIAS_HELP_OPT2 MCR_HELP_OPT2

%%
"--works" { std::cout << "this works" << std::endl; }
{ALIAS_HELP_OPT} { std::cout << "help" << std::endl; }
{ALIAS_HELP_OPT2} { std::cout << "help2" << std::endl; }
\n { return 0; }
. { /* consume */ }
%%

int main(int, char**) {
    while (yylex()) {}
}

I tested it like so:

> flex test.l && c++ lex.yy.c
> echo "--help" | ./a.out
> echo "--works" | ./a.out
this works

Solution

  • In the end, I decided to use CMake's configure_file functionality; Here is a minimal working example:

    CMakeLists.txt:

    cmake_minimum_required(VERSION 3.25)
    project(test)
    
    find_package(FLEX REQUIRED)
    
    set(SCANNER_FLEX ${CMAKE_BINARY_DIR}/test.l)
    set(SCANNER_SRC ${CMAKE_BINARY_DIR}/test.cpp)
    set(MCR_HELP_OPT "--help")
    
    configure_file(test.l.in ${SCANNER_FLEX} @ONLY)
    
    FLEX_TARGET(scanner ${SCANNER_FLEX} ${SCANNER_SRC})
    add_executable(run ${SCANNER_SRC})
    
    target_include_directories(run PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}
    )
    

    test.l.in

    %option noyywrap
    
    %{
    #include <iostream>
    %}
    
    %%
    @MCR_HELP_OPT@ { std::cout << "help" << std::endl; }
    \n { return 0; }
    . { /* consume */ }
    %%
    
    int main(int, char**) {
        while (yylex()) {}
    }
    

    Then building and running it:

    > cmake -B build
    > make -C build
    > echo "--help" | ./build/run
    help