由 bison 创建的解析器代码的 g++ 编译失败,因为“yytokentype”枚举值不可见

Compilation by g++ of parser code created by bison fails because `yytokentype` enum values are not visible

我正在尝试使用

在 Linux 上编译 chuffed

这是 CMAKE 管理的安装。

the README 中所述,从发行版的顶层目录开始,我 运行:

mkdir build
cd build
cmake ..
cmake --build . --verbose

此时出现错误。解析器代码的创建似乎有效。然后使用选项 -std=gnu++11 调用 /usr/bin/c++。它终止于:

parser.tab.cpp: In function ‘int yyparse(void*)’:
parser.tab.cpp:1963:12: error: ‘YYEMPTY’ was not declared in this scope
 1963 |   yychar = YYEMPTY; /* Cause a token to be read.  */
      |            ^~~~~~~
parser.tab.cpp:2077:17: error: ‘YYEOF’ was not declared in this scope
 2077 |   if (yychar <= YYEOF)
      |                 ^~~~~
parser.tab.cpp:2083:22: error: ‘YYerror’ was not declared in this scope; did you mean ‘yyerror’?
 2083 |   else if (yychar == YYerror)
      |                      ^~~~~~~
      |                      yyerror
parser.tab.cpp:2089:16: error: ‘YYUNDEF’ was not declared in this scope; did you mean ‘YYUSE’?
 2089 |       yychar = YYUNDEF;
      |                ^~~~~~~
      |                YYUSE
parser.tab.cpp:3650:21: error: ‘YYEOF’ was not declared in this scope
 3650 |       if (yychar <= YYEOF)
      |                     ^~~~~

在源代码中,编译器正在查找的常量在枚举中定义:

/* Token kinds.  */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
  enum yytokentype
  {
    YYEMPTY = -2,
    YYEOF = 0,                     /* "end of file"  */
    YYerror = 256,                 /* error  */
    YYUNDEF = 257,                 /* "invalid token"  */
    INT_LIT = 258,                 /* INT_LIT  */
    BOOL_LIT = 259,                /* BOOL_LIT  */
    FLOAT_LIT = 260,               /* FLOAT_LIT  */
    ID = 261,                      /* ID  */
    STRING_LIT = 262,              /* STRING_LIT  */
...
    WHERE = 301                    /* WHERE  */
  };
  typedef enum yytokentype yytoken_kind_t;
#endif

并在 yyparse(void *parm) 中使用这样的例子:

  YYDPRINTF ((stderr, "Starting parse\n"));

  yychar = YYEMPTY; /* Cause a token to be read.  */
  goto yysetstate;

乍一看,编译器似乎没有理由抱怨。但是,可能有一些特定于 C++ 版本或此处使用的语法。我的 C++ 很生疏,这可能是直截了当的事情。

我尝试将行更改为

  yychar = yytokentype::YYEMPTY; /* Cause a token to be read.  */

但后来我得到:

parser.tab.cpp:1963:25: error: ‘YYEMPTY’ is not a member of ‘yytokentype’
 1963 |   yychar = yytokentype::YYEMPTY; /* Cause a token to be read.  */

那就更令人费解了。

n-1-8e9-wheres-my-share-m的建议下,

假设

CHUFFED_TOPDIR=... # toplevel of the distribution

我们发现有一个现有的 parser.tab.h 使用旧式 GNU Bison 3.0.4 创建:

"$CHUFFED_TOPDIR"/chuffed/flatzinc/parser.tab.h

这个文件在编译的时候确实被包含了,这样编译的时候就可以确定,导致打印出包含树:

cd "$CHUFFED_TOPDIR"
rm -rf build/
mkdir build
cd build/
cmake -E env CXXFLAGS="-H" cmake .. # using cmake to run cmake
cmake --build . --verbose

Note

The usual command line for running cmake would be:

cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR ..

Definitely consider switching on debug mode for a first try. This is important for running the examples, which do not check their commandline arguments and segfault if these are missing . With debugging on, you at least get assertion error messages:

cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR \
      -DCMAKE_BUILD_TYPE=Debug ..

So, altogether

cmake -E env CXXFLAGS="-H" \
   cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR
         -DCMAKE_BUILD_TYPE=Debug ..

因此,请尝试删除 parser.tab.h 并确保随附的 parser.tab.cpp:

mv "$CHUFFED_TOPDIR"/chuffed/flatzinc/parser.tab.h \
   "$CHUFFED_TOPDIR"/chuffed/flatzinc/parser.tab.h.bak

mv "$CHUFFED_TOPDIR"/chuffed/flatzinc/parser.tab.cpp \
   "$CHUFFED_TOPDIR"/chuffed/flatzinc/parser.tab.cpp.bak

lexer.yy.cpp 可能存在类似的问题,因此:

mv "$CHUFFED_TOPDIR"/chuffed/flatzinc/lexer.yy.cpp \
   "$CHUFFED_TOPDIR"/chuffed/flatzinc/lexer.yy.cpp.bak

Note It is always good to take a look at

"$CHUFFED_TOPDIR"/build/CMakeFiles/CMakeError.log

but in my case it just says that looking for the pthread library failed, at least initially.

编译成功。可以发现 Bison 输出为:

"$CHUFFED_TOPDIR"/build/parser.tab.cpp

以及:

"$CHUFFED_TOPDIR"/build/chuffed/flatzinc/parser.tab.h

请注意,在 CMakeLists.txt 文件中,我们找到以下代码:

find_package(BISON)
if(BISON_FOUND)
  file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/chuffed/flatzinc)
  bison_target(FZNParser
    ${PROJECT_SOURCE_DIR}/chuffed/flatzinc/parser.yxx
    ${PROJECT_BINARY_DIR}/parser.tab.cpp
    DEFINES_FILE ${PROJECT_BINARY_DIR}/chuffed/flatzinc/parser.tab.h
    COMPILE_FLAGS "-l"
  )
else()
  message(WARNING "Bison cannot be run. Using cached file, which may be out of date.")
  set(BISON_FZNParser_OUTPUTS
    ${PROJECT_SOURCE_DIR}/chuffed/flatzinc/parser.tab.cpp
    ${PROJECT_SOURCE_DIR}/chuffed/flatzinc/parser.tab.h
  )
endif()

find_package(FLEX)
if(FLEX_FOUND)
  flex_target(FZNLexer
    ${PROJECT_SOURCE_DIR}/chuffed/flatzinc/lexer.lxx
    ${PROJECT_BINARY_DIR}/lexer.yy.cpp
    COMPILE_FLAGS "-L"
  )
  add_flex_bison_dependency(FZNLexer FZNParser)
else()
  message(WARNING "Flex cannot be run. Using cached file, which may be out of date.")
  set(FLEX_FZNLexer_OUTPUTS ${PROJECT_SOURCE_DIR}/chuffed/flatzinc/lexer.yy.cpp)
endif()

我想如果在编译系统上可以找到 bison,应该自动跳过提供的 parser.tab.h。我不确定这里出了什么问题。