在 c 中的 GNU automake 中使用解析器
Using parsers in GNU automake in c
我是 GNU autotools 的新手,在我的项目中,lex 和 yacc 解析器是 used.Including 它们作为源 makefile.am 产生以下错误:
configure.in :
...
AC_CHECK_PROGS(YACC,bison yacc,none)
if test "x$YACC" = "xbison"; then
YACC="$YACC -y"
fi
AC_CHECK_PROGS(LEX,flex,none)
...
makefile.am :
## $Id
AUTOMAKE_OPTIONS=foreign no-dependencies
include $(srcdir)/Makefile_defs
dynamicpreprocessordir = ${libdir}/snort_dynamicpreprocessor
dynamicpreprocessor_LTLIBRARIES = libsf_appid_preproc.la
libsf_appid_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@
if SO_WITH_STATIC_LIB
libsf_appid_preproc_la_LIBADD = ../libsf_dynamic_preproc.la
../libsf_dynamic_utils.la $(LUA_LIBS)
else
nodist_libsf_appid_preproc_la_SOURCES = \
../include/sf_dynamic_preproc_lib.c \
../include/sf_ip.c \
../include/sfPolicyUserData.c \
../include/sfxhash.c \
../include/sfghash.c \
../include/sflsq.c \
../include/sfhashfcn.c \
../include/sfmemcap.c \
../include/sfprimetable.c
libsf_appid_preproc_la_LIBADD = $(LUA_LIBS)
endif
libsf_appid_preproc_la_CFLAGS = -DDYNAMIC_PREPROC_CONTEXT -DSTATIC=static $(LUA_CFLAGS)
libsf_appid_preproc_la_SOURCES = $(APPID_SOURCES)
all-local: $(LTLIBRARIES)
$(MAKE) DESTDIR=`pwd`/../build install-dynamicpreprocessorLTLIBRARIES
在Makefile_defs中:
APPID_SRC_DIR = ${top_srcdir}/src/dynamic-preprocessors/appid
...
APPID_SOURCES = \
$(APPID_SRC_DIR)/vfml/fc45.lex \
$(APPID_SRC_DIR)/vfml/fc45.y \
...
当我 运行 程序时出现以下错误:
libsf_appid_preproc.so: undefined symbol: FC45SetFile
虽然 FC45SetFile() 已在 fc45.lex 文件中定义。
fc45.lex :
%{
#include "fc45.tab.h"
//#include "vfml.h"
#include <string.h>
#include <stdlib.h>
/* HERE doesn't match strings starting with numbers other than 0 right */
char string_buf[4000]; /* BUG - maybe check for strings that are too long? */
char *string_buf_ptr;
void FC45FinishString(void);
extern int gLineNumber;
%}
%x str_rule
%%
<str_rule,INITIAL>\|[^\n]* ;
[\ \t\r]+ ;
\n gLineNumber++;
\. { return '.';}
, { return ',';}
: { return ':';}
ignore { return tIgnore; }
continuous { return tContinuous; }
discrete { return tDiscrete; }
[^:?,\t\n\r\|\.\\ ] string_buf_ptr = string_buf; unput(yytext[0]); BEGIN(str_rule);
<str_rule>[:,?] FC45FinishString(); unput(yytext[0]); return tString;
<str_rule>\.[\t\r\ ] FC45FinishString(); unput(yytext[1]); unput(yytext[0]); return tString;
<str_rule>\.\n FC45FinishString(); unput(yytext[1]); unput(yytext[0]); return tString; gLineNumber++;
<str_rule><<EOF>> {
int len = strlen(string_buf);
// printf("eof rule.\n");
if(len == 1 && string_buf[0] == '.') {
//printf(" period at end of file\n");
return '.';
} else if(string_buf[len - 1] == '.') {
// printf(" period: %s - unput .\n", string_buf);
FC45FinishString(); unput('.'); return tString;
} else {
// printf(" no-period: %s\n", string_buf);
FC45FinishString(); return tString;
}
}
<str_rule>\: *string_buf_ptr++ = ':';
<str_rule>\\? *string_buf_ptr++ = '?';
<str_rule>\, *string_buf_ptr++ = ',';
<str_rule>\. *string_buf_ptr++ = '.';
<str_rule>\n *string_buf_ptr++ = ' '; gLineNumber++;
<str_rule>[ \t\r]+ *string_buf_ptr++ = ' ';
<str_rule>[^:?,\t\n\r\|\.\\ ]+ {
char *yptr = yytext;
while(*yptr) {
*string_buf_ptr++ = *yptr++;
}
}
%%
int fc45wrap(void) {
return 1;
}
void FC45SetFile(FILE *file) {
fc45in = file;
yyrestart(fc45in);
}
void FC45FinishString(void) {
int len;
char *tmpStr;
BEGIN(INITIAL);
*string_buf_ptr = '[=14=]';
len = strlen(string_buf);
/* remove any ending spaces */
while(string_buf[len - 1] == ' ') {
string_buf[len - 1] = '[=14=]';
len--;
}
tmpStr = MNewPtr(len + 1);
strncpy(tmpStr, string_buf, len + 1);
fc45lval.string = tmpStr;
string_buf[0] = '[=14=]';
}
fc45.y :
%{
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include "ExampleSpec1.h"
//#include "AttributeTracker.c"
//#include "vfml.h"
%}
%{
int fc45lex(void);
int fc45error(const char *);
/* HERE figure out how to give better error messages */
/* BUG needs a \n at the end of the names file */
/* These tmps are allocated at the begining of parsing and then
used during parsing. For example, so that we can simply
add terrains to an area while parsing. After parsing a
statement, the associated tmp is added to the appropriate
global list, and a new tmp is allocated. Finally, at the
end of parsing, all the tmps are freed
*/
ExampleSpecPtr exampleSpec;
AttributeSpecPtr attributeSpec;
int gLineNumber;
%}
%union {
int integer;
float f;
char *string;
}
%token <integer> tInteger
%token <string> tString
%token tIgnore tContinuous tDiscrete tEOF
%%
ExampleSpec: ClassList '.' AttributeList;
ClassList: ClassList ',' ClassSpec | ClassSpec /* ending */;
ClassSpec: tString { ExampleSpecAddClass(exampleSpec, ); };
AttributeList: AttributeList AttributeSpec | /* ending */;
AttributeSpec: tString ':' AttributeInfo '.' {
AttributeSpecSetName(attributeSpec, );
ExampleSpecAddAttributeSpec(exampleSpec, attributeSpec);
attributeSpec = AttributeSpecNew();
};
AttributeInfo: tIgnore {
AttributeSpecSetType(attributeSpec, asIgnore);} |
tContinuous {
AttributeSpecSetType(attributeSpec, asContinuous);} |
tDiscrete tString {
AttributeSpecSetType(attributeSpec, asDiscreteNoName);
AttributeSpecSetNumValues(attributeSpec, atoi()); } |
AttributeValueNameList {
AttributeSpecSetType(attributeSpec, asDiscreteNamed); };
AttributeValueNameList: AttributeValueNameList ',' tString {
AttributeSpecSetNumValues(attributeSpec,
AttributeSpecGetNumValues(attributeSpec) + 1);
AttributeSpecAddValue(attributeSpec, ); } |
tString {
AttributeSpecSetNumValues(attributeSpec,
AttributeSpecGetNumValues(attributeSpec) + 1);
AttributeSpecAddValue(attributeSpec, ); };
%%
void FC45SetFile(FILE *file);
int fc45error(const char *msg) {
fprintf(stderr, "%s line %d\n", msg, gLineNumber);
return 0;
}
ExampleSpecPtr ParseFC45(const char *file) {
FILE *input;
input = fopen(file, "r");
if(input == 0) {
return 0;
}
FC45SetFile(input);
exampleSpec = ExampleSpecNew();
attributeSpec = AttributeSpecNew();
gLineNumber = 0;
if(fc45parse()) {
/* parse failed! */
fprintf(stderr, "Error in parsing: %s\n", file);
}
fclose(input);
/* free the left over attribute spec */
AttributeSpecFree(attributeSpec);
return exampleSpec;
}
我在 Internet 上搜索了解决方案,但找不到任何解决方案。
希望有人认识到这个问题并快速解决它。任何帮助将不胜感激。
我只是 运行 通过 a simple example,添加以下 Autotools 文件:
configure.ac:
AC_PREREQ([2.69])
AC_INIT([example], [0.1a], [example@example.com])
AC_CONFIG_SRCDIR([ex1.l])
# Used only to shorten the otherwise lengthy compilation line in the output below.
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([foreign])
# I used C instead of C++.
AC_PROG_CC
AM_PROG_LEX
AC_PROG_YACC
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
Makefile.am(几乎直接取自 the Automake manual):
BUILT_SOURCES = ex1.h
AM_YFLAGS = -d
bin_PROGRAMS = ex1
ex1_SOURCES = ex1.l ex1.y
原来你不能用相同的基本文件名来命名文件。就我而言,我有 ex1.l 和 ex1.y。当我调用 make
:
时,使用 ex1_SOURCES = ex1.l ex1.y
会产生以下输出
make[1]: Entering directory '/home/kit/ex1'
/bin/bash ./ylwrap ex1.l lex.yy.c ex1.c -- flex
make[1]: Leaving directory '/home/kit/ex1'
make all-am
make[1]: Entering directory '/home/kit/ex1'
gcc -DHAVE_CONFIG_H=1 -I. -g -O2 -MT ex1.o -MD -MP -MF .deps/ex1.Tpo -c -o ex1.o ex1.c
ex1.l:5:17: fatal error: ex1.h: No such file or directory
#include "ex1.h"
^
compilation terminated.
Makefile:378: recipe for target 'ex1.o' failed
make[1]: *** [ex1.o] Error 1
make[1]: Leaving directory '/home/kit/ex1'
Makefile:281: recipe for target 'all' failed
make: *** [all] Error 2
请注意在第二行中调用了 flex,但 bison/yacc 没有。什么原因?好吧,ylwrap
脚本是原因:
ex1.c: ex1.l
ex1.c: ex1.y
因为脚本将 ex1.l 的输出从 "lex.yy.c" 重命名为 "ex1.c",makefile 认为 ex1.c 已经构建,所以它不会做任何事情使用 bison/yacc 文件,这意味着 ex1.h 也未构建。
您无法禁用 ylwrap
脚本,但您可以解决它:只需重命名您的 flex 源文件并更改 Makefile.in 和 [=50] 中对文件名的引用=] 必要的文件。你不应该需要重命名你的 bison/yacc 源文件,因为这意味着在每个 C 文件以及你的 flex 中将每个 #include "fc45.h"
更改为 #include "fc45_g.h"
源文件。
问题是 make 和 automake 都不知道非标准的 .lex
文件扩展名,所以当你有一个以 .lex
结尾的源文件时,他们不知道什么用它来做。您 可以 创建规则来处理 .lex
,但使用 .l
文件扩展名重命名文件可能更容易,他们知道如何处理。
我是 GNU autotools 的新手,在我的项目中,lex 和 yacc 解析器是 used.Including 它们作为源 makefile.am 产生以下错误:
configure.in :
...
AC_CHECK_PROGS(YACC,bison yacc,none)
if test "x$YACC" = "xbison"; then
YACC="$YACC -y"
fi
AC_CHECK_PROGS(LEX,flex,none)
...
makefile.am :
## $Id
AUTOMAKE_OPTIONS=foreign no-dependencies
include $(srcdir)/Makefile_defs
dynamicpreprocessordir = ${libdir}/snort_dynamicpreprocessor
dynamicpreprocessor_LTLIBRARIES = libsf_appid_preproc.la
libsf_appid_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@
if SO_WITH_STATIC_LIB
libsf_appid_preproc_la_LIBADD = ../libsf_dynamic_preproc.la
../libsf_dynamic_utils.la $(LUA_LIBS)
else
nodist_libsf_appid_preproc_la_SOURCES = \
../include/sf_dynamic_preproc_lib.c \
../include/sf_ip.c \
../include/sfPolicyUserData.c \
../include/sfxhash.c \
../include/sfghash.c \
../include/sflsq.c \
../include/sfhashfcn.c \
../include/sfmemcap.c \
../include/sfprimetable.c
libsf_appid_preproc_la_LIBADD = $(LUA_LIBS)
endif
libsf_appid_preproc_la_CFLAGS = -DDYNAMIC_PREPROC_CONTEXT -DSTATIC=static $(LUA_CFLAGS)
libsf_appid_preproc_la_SOURCES = $(APPID_SOURCES)
all-local: $(LTLIBRARIES)
$(MAKE) DESTDIR=`pwd`/../build install-dynamicpreprocessorLTLIBRARIES
在Makefile_defs中:
APPID_SRC_DIR = ${top_srcdir}/src/dynamic-preprocessors/appid
...
APPID_SOURCES = \
$(APPID_SRC_DIR)/vfml/fc45.lex \
$(APPID_SRC_DIR)/vfml/fc45.y \
...
当我 运行 程序时出现以下错误:
libsf_appid_preproc.so: undefined symbol: FC45SetFile
虽然 FC45SetFile() 已在 fc45.lex 文件中定义。
fc45.lex :
%{
#include "fc45.tab.h"
//#include "vfml.h"
#include <string.h>
#include <stdlib.h>
/* HERE doesn't match strings starting with numbers other than 0 right */
char string_buf[4000]; /* BUG - maybe check for strings that are too long? */
char *string_buf_ptr;
void FC45FinishString(void);
extern int gLineNumber;
%}
%x str_rule
%%
<str_rule,INITIAL>\|[^\n]* ;
[\ \t\r]+ ;
\n gLineNumber++;
\. { return '.';}
, { return ',';}
: { return ':';}
ignore { return tIgnore; }
continuous { return tContinuous; }
discrete { return tDiscrete; }
[^:?,\t\n\r\|\.\\ ] string_buf_ptr = string_buf; unput(yytext[0]); BEGIN(str_rule);
<str_rule>[:,?] FC45FinishString(); unput(yytext[0]); return tString;
<str_rule>\.[\t\r\ ] FC45FinishString(); unput(yytext[1]); unput(yytext[0]); return tString;
<str_rule>\.\n FC45FinishString(); unput(yytext[1]); unput(yytext[0]); return tString; gLineNumber++;
<str_rule><<EOF>> {
int len = strlen(string_buf);
// printf("eof rule.\n");
if(len == 1 && string_buf[0] == '.') {
//printf(" period at end of file\n");
return '.';
} else if(string_buf[len - 1] == '.') {
// printf(" period: %s - unput .\n", string_buf);
FC45FinishString(); unput('.'); return tString;
} else {
// printf(" no-period: %s\n", string_buf);
FC45FinishString(); return tString;
}
}
<str_rule>\: *string_buf_ptr++ = ':';
<str_rule>\\? *string_buf_ptr++ = '?';
<str_rule>\, *string_buf_ptr++ = ',';
<str_rule>\. *string_buf_ptr++ = '.';
<str_rule>\n *string_buf_ptr++ = ' '; gLineNumber++;
<str_rule>[ \t\r]+ *string_buf_ptr++ = ' ';
<str_rule>[^:?,\t\n\r\|\.\\ ]+ {
char *yptr = yytext;
while(*yptr) {
*string_buf_ptr++ = *yptr++;
}
}
%%
int fc45wrap(void) {
return 1;
}
void FC45SetFile(FILE *file) {
fc45in = file;
yyrestart(fc45in);
}
void FC45FinishString(void) {
int len;
char *tmpStr;
BEGIN(INITIAL);
*string_buf_ptr = '[=14=]';
len = strlen(string_buf);
/* remove any ending spaces */
while(string_buf[len - 1] == ' ') {
string_buf[len - 1] = '[=14=]';
len--;
}
tmpStr = MNewPtr(len + 1);
strncpy(tmpStr, string_buf, len + 1);
fc45lval.string = tmpStr;
string_buf[0] = '[=14=]';
}
fc45.y :
%{
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include "ExampleSpec1.h"
//#include "AttributeTracker.c"
//#include "vfml.h"
%}
%{
int fc45lex(void);
int fc45error(const char *);
/* HERE figure out how to give better error messages */
/* BUG needs a \n at the end of the names file */
/* These tmps are allocated at the begining of parsing and then
used during parsing. For example, so that we can simply
add terrains to an area while parsing. After parsing a
statement, the associated tmp is added to the appropriate
global list, and a new tmp is allocated. Finally, at the
end of parsing, all the tmps are freed
*/
ExampleSpecPtr exampleSpec;
AttributeSpecPtr attributeSpec;
int gLineNumber;
%}
%union {
int integer;
float f;
char *string;
}
%token <integer> tInteger
%token <string> tString
%token tIgnore tContinuous tDiscrete tEOF
%%
ExampleSpec: ClassList '.' AttributeList;
ClassList: ClassList ',' ClassSpec | ClassSpec /* ending */;
ClassSpec: tString { ExampleSpecAddClass(exampleSpec, ); };
AttributeList: AttributeList AttributeSpec | /* ending */;
AttributeSpec: tString ':' AttributeInfo '.' {
AttributeSpecSetName(attributeSpec, );
ExampleSpecAddAttributeSpec(exampleSpec, attributeSpec);
attributeSpec = AttributeSpecNew();
};
AttributeInfo: tIgnore {
AttributeSpecSetType(attributeSpec, asIgnore);} |
tContinuous {
AttributeSpecSetType(attributeSpec, asContinuous);} |
tDiscrete tString {
AttributeSpecSetType(attributeSpec, asDiscreteNoName);
AttributeSpecSetNumValues(attributeSpec, atoi()); } |
AttributeValueNameList {
AttributeSpecSetType(attributeSpec, asDiscreteNamed); };
AttributeValueNameList: AttributeValueNameList ',' tString {
AttributeSpecSetNumValues(attributeSpec,
AttributeSpecGetNumValues(attributeSpec) + 1);
AttributeSpecAddValue(attributeSpec, ); } |
tString {
AttributeSpecSetNumValues(attributeSpec,
AttributeSpecGetNumValues(attributeSpec) + 1);
AttributeSpecAddValue(attributeSpec, ); };
%%
void FC45SetFile(FILE *file);
int fc45error(const char *msg) {
fprintf(stderr, "%s line %d\n", msg, gLineNumber);
return 0;
}
ExampleSpecPtr ParseFC45(const char *file) {
FILE *input;
input = fopen(file, "r");
if(input == 0) {
return 0;
}
FC45SetFile(input);
exampleSpec = ExampleSpecNew();
attributeSpec = AttributeSpecNew();
gLineNumber = 0;
if(fc45parse()) {
/* parse failed! */
fprintf(stderr, "Error in parsing: %s\n", file);
}
fclose(input);
/* free the left over attribute spec */
AttributeSpecFree(attributeSpec);
return exampleSpec;
}
我在 Internet 上搜索了解决方案,但找不到任何解决方案。 希望有人认识到这个问题并快速解决它。任何帮助将不胜感激。
我只是 运行 通过 a simple example,添加以下 Autotools 文件:
configure.ac:
AC_PREREQ([2.69])
AC_INIT([example], [0.1a], [example@example.com])
AC_CONFIG_SRCDIR([ex1.l])
# Used only to shorten the otherwise lengthy compilation line in the output below.
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([foreign])
# I used C instead of C++.
AC_PROG_CC
AM_PROG_LEX
AC_PROG_YACC
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
Makefile.am(几乎直接取自 the Automake manual):
BUILT_SOURCES = ex1.h
AM_YFLAGS = -d
bin_PROGRAMS = ex1
ex1_SOURCES = ex1.l ex1.y
原来你不能用相同的基本文件名来命名文件。就我而言,我有 ex1.l 和 ex1.y。当我调用 make
:
ex1_SOURCES = ex1.l ex1.y
会产生以下输出
make[1]: Entering directory '/home/kit/ex1'
/bin/bash ./ylwrap ex1.l lex.yy.c ex1.c -- flex
make[1]: Leaving directory '/home/kit/ex1'
make all-am
make[1]: Entering directory '/home/kit/ex1'
gcc -DHAVE_CONFIG_H=1 -I. -g -O2 -MT ex1.o -MD -MP -MF .deps/ex1.Tpo -c -o ex1.o ex1.c
ex1.l:5:17: fatal error: ex1.h: No such file or directory
#include "ex1.h"
^
compilation terminated.
Makefile:378: recipe for target 'ex1.o' failed
make[1]: *** [ex1.o] Error 1
make[1]: Leaving directory '/home/kit/ex1'
Makefile:281: recipe for target 'all' failed
make: *** [all] Error 2
请注意在第二行中调用了 flex,但 bison/yacc 没有。什么原因?好吧,ylwrap
脚本是原因:
ex1.c: ex1.l
ex1.c: ex1.y
因为脚本将 ex1.l 的输出从 "lex.yy.c" 重命名为 "ex1.c",makefile 认为 ex1.c 已经构建,所以它不会做任何事情使用 bison/yacc 文件,这意味着 ex1.h 也未构建。
您无法禁用 ylwrap
脚本,但您可以解决它:只需重命名您的 flex 源文件并更改 Makefile.in 和 [=50] 中对文件名的引用=] 必要的文件。你不应该需要重命名你的 bison/yacc 源文件,因为这意味着在每个 C 文件以及你的 flex 中将每个 #include "fc45.h"
更改为 #include "fc45_g.h"
源文件。
问题是 make 和 automake 都不知道非标准的 .lex
文件扩展名,所以当你有一个以 .lex
结尾的源文件时,他们不知道什么用它来做。您 可以 创建规则来处理 .lex
,但使用 .l
文件扩展名重命名文件可能更容易,他们知道如何处理。