写这篇文章的目的,一方面是解决在句法分析器中的的版本不同,另外一方面可以扩展到其它软件的兼容性是否也可以采用类似方法解决。此文中最好需要有automake的基础来阅读这篇文章。
我们假设有一个工程,采用autoconf来进行编译。对于不同版本的bison,弄清楚其差异化点,对于bison2.3和bison3.0.4来说,主要在于code段引用的方式不一样,bison2.3版本的句法文件MySampleParser.yy如下:
%{
#include <stdio.h>
#include <string>
#include <limits.h>
#include <ot/common.h>
BEGIN_OT_NAMESPACE(dsp);
class MySampleScanner;
END_OT_NAMESPACE(dsp);
...
%}
在Makefile.am里面,需要添加:
AM_YFLAGS = -d
AM_LFLAGS = -olex.yy.c
noinst_LTLIBRARIES = libmysample_scanner.la
libmysample_scanner_la_SOURCES = MySampleParser.yy MySampleScanner.ll
CLEANFILES = MySampleParser.hh \
MySampleParser.cc \
stack.hh \
position.hh \
location.hh
值得注意的是,在MySampleParser.yy文件中,BEGIN_OT_NAMESPACE不会被C++编译器编译执行,所以使用automake解析的时候会出现找不到 namespace ot 的情况,这个时候需要在MySampleScanner.ll文件的code段中添加namespace,如:
%{
namespace ot
{
}
#include <string>
...
%}
当然MySampleScanner.h头文件一般不是自动生成,需要构造类MySampleScanner,且继承yyFlexLexer,但由于符号冲突的问题,需要在定义类MySampleScanner之前,对yyFlexLexer重新定义,像这样:
#ifndef __FLEX_LEXER_H
#define yyFlexLexer QueryFlexLexer
#include <FlexLexer.h>
#undef yyFlexLexer
#endif
但对于bison3.0.4版本来说,code段的表达方式发生了变化,需要采用如下描述:
% code requires{
#include <stdio.h>
#include <string>
#include <limits.h>
#include <ot/common.h>
BEGIN_OT_NAMESPACE(dsp);
class MySampleScanner;
END_OT_NAMESPACE(dsp);
...
}
了解到区别之后,如果需要兼容,应该怎么办呢?首先要获取到bison版本才能做下一步策略:
在configure.ac里面(如果有m4的宏文件,也可以放置在m4文件中)添加:
dnl -------------------------------------------------------------------------
dnl Checks for bison version
dnl -------------------------------------------------------------------------
BISON_VERSION=$(bison --version | head -1 | awk '{print $ 4}')
AC_SUBST(BISON_VERSION)
AC_SUBST(BISON_VERSION_3_FLAG)
AC_SUBST(BISON_VERSION_2_FLAG)
AC_MSG_CHECKING([bison version])
AS_IF([test "$(echo "$BISON_VERSION 3.0.4" | tr " " "\n" | sort -rn | head -n 1)" == "$BISON_VERSION"], [
BISON_VERSION_3_FLAG="define HAVE_BISON_VERSION_3"
BISON_VERSION_2_FLAG="undef HAVE_BISON_VERSION_2"
], [
BISON_VERSION_3_FLAG="undef HAVE_BISON_VERSION_3"
BISON_VERSION_2_FLAG="define HAVE_BISON_VERSION_2"
])
AM_CONDITIONAL(ENABLE_BISON_VERSION_3, test "$(echo "$BISON_VERSION 3.0.4" | tr " " "\n" | sort -rn | head -n 1)" == "$BISON_VERSION" )
AC_MSG_RESULT([$BISON_VERSION])
这里面定义了四个重要的变量:
- BISON_VERSION是用来记录bison的版本号;
- BISON_VERSION_3_FLAG和 BISON_VERSION_2_FLAG是方便在C/C++的一些头文件中定义是版本3还是版本2,好做对应的处理;
- ENABLE_BISON_VERSION_3是用来在Makefile.am里面用于条件判定
那么Makefile.am里面的条件判断可以写成如下所示:
AUTOMAKE_OPTIONS = foreign
dist_headers = $(wildcard *.h *.hh)
AM_CPPFLAGS = -I$(top_srcdir)/src \
$(NULL)
AM_LDFLAGS = $(NULL)
AM_YFLAGS = -d
AM_LFLAGS = -olex.yy.c
if ENABLE_BISON_VERSION_3
noinst_LTLIBRARIES = libmysample_scanner.la libmysample.la
libmysample_scanner_la_SOURCES = MySampleParser.yy MySampleScanner.ll
libmysample_scanner_la_DEPENDENCIES = MySampleParser.yy
MySampleParser.yy :
sed 's#%{#%code requires {#' MySampleParser.yy.in > MySampleParser.yy
else
noinst_LTLIBRARIES = libmysample.la
cc_files = MySampleParser.cc MySampleScanner.cc
endif
libmysample_la_SOURCES = XX.cpp $(cc_files) $(dist_headers)
if ENABLE_BISON_VERSION_3
libmysample_la_LIBADD = libmysample_scanner.la
else
libmysample_la_DEPENDENCIES = MySampleParser.hh
MySampleParser.hh : MySampleParser.yy libmysample_scanner.la
bison -o MySampleParser.cc MySampleParser.yy
endif
CLEANFILES = MySampleParser.hh \
MySampleParser.cc \
stack.hh \
position.hh \
location.hh
其中MySampleParser.yy.in写成和bison2.3版本的MySampleParser.yy一样即可。
通过此次调整,完美的解决了bison2.3和bison3.0.4在autoconf编译的冲突问题,类似的冲突也可以采用此方式解决。