Flex Bison 和 Gnu Automake

Flex Bison and Gnu Automake

我写了一个基于 flex-lexer 和 bison 的小文本过滤器。 布尔表达式应用于指定的字符串 (logvar)。布尔表达式由字符串和布尔运算组成。

示例:

*intput*:
logvar=aa bb cc dd ee
aa & bb
*result*:
true

*input*:
logvar=aa bb cc dd ee
aa & rr
*result*:
false

*input*:
logvar=aa bb cc dd ee
aa | rr
*result*:
true

很简单。

这是词法分析器的来源-filter.l:

%{
#include <stdlib.h>
void yyerror(char *);
#include "grammar-filter.tab.h"
%}

%%

"&" {
    printf("LEX: & parsed\n");
    return AND;
}

"|" {
    printf("LEX: | parsed\n");
    return OR;
}

"logvar" {
    printf("LEX: logvar parsed\n");
    return LOGVAR;
}

[a-z ]+ {
    yylval.sValue = strdup(yytext);
    printf("LEX: string parsed: %s\n", yylval.sValue);
    return STRING;
}

[()=\n] { return *yytext; }
[ \t] ;
, { return *yytext; }
. yyerror("invalid character");
%%
int yywrap(void) {
    return 1;
}

和语法野牛文件:

%{
#include <string.h>
#include <stdio.h>
void yyerror(char *);
int yylex(void);
int sym[26];
char* log_line;
%}
%union {
    char *sValue;
    int iValue;
}

%token <iValue> BOOLEAN
%token <sValue> STRING
%token LOGVAR
%token AND OR
%left AND OR

%type<iValue> expr 

%%

prog :
prog logassigned '\n' statement '\n'
;

statement :
expr { printf("%d\n", ); }
;
    
logassigned :
LOGVAR '=' STRING { log_line = ; }
;

expr:
STRING { if (strstr(log_line, ) != NULL) {
                printf("%s is substring of %s\n", , log_line);
                $$ = 1;
         } else {
                 printf("%s doesn't substring of %s\n", , log_line);
                 $$ = 0;
         }
       }
| expr OR expr { if ( == 1 ||  == 1) { $$ = 1; } else { $$ = 0; } }
| expr AND expr { $$ =  * ; }
| NOT expr { if ( == 1) { $$ = 0; } else { $$ = 1; } }
| '(' expr ')' { $$ = ; }
;

%%
#include "lex.yy.c"
void yyerror(char *s) {
        fprintf(stderr, "%s\n", s);
}

int main(void) {
//        yy_scan_string(some_string_buffer);
        yyparse();
//        yylex_destroy();

    return 0;
}

最终的二进制文件是由一个简单的 make 文件构建的:

all:
    flex lexer-filter.l
    bison grammar-filter.y -d
    gcc grammar-filter.tab.c -ll

我有一个基于 gnu autotools 的库(automake、autoconf...)。是否可以将此解析器添加到库中并使用这三个结构 yy_scan_string(some_string_buffer); yyparse(); yylex_destroy(); 在我的图书馆?我如何 运行 flex 和 bison 从 automake 脚本生成文件(lex.yy.c grammar-filter.tab.c grammar-filter.tab.h)

问候,最大)

问候,最大

Autotools 有 built-in support for flex and bison,尽管它有点古怪(或如链接文档所说的“特殊”)。

至少,您需要做两件事:

  1. AC_PROG_LEXAC_PROG_YACC 添加到 configure.ac

  2. 添加 BUILT_SOURCES 的定义,它列出生成的 header 文件到 Makefile.am

参见 this answer for an example

您还需要稍微清理一下您的项目。 Autotools 假定解析器和扫描器将单独构建,因此您需要将它们分开。 #include在解析器中使用扫描器可能看起来很方便,但它并不是很好的项目组织。 (换句话说,这个要求不是 Autotools 的怪癖之一。)你需要 #include headers 适当的: bison-generated header 文件需要#includedd 在扫描仪源代码中,flex header 文件(您可以使用 flex 选项请求)需要在调用 flex 函数的源代码中为 #included。

而不是直接使用 flex-generated header,您可能想将自己的小包装器写入扫描仪本身,并为包装器函数编写自己的 header 文件。我通常这样做是为了避免对 flex 的紧密依赖。

您可以通过向扫描器添加 %option 声明来提高扫描器的可编译性,至少:

%option noinput nounput noyywrap

前两个选项避免了关于未使用函数的编译器警告,最后一个选项消除了对 yywrap 的需要,因此不需要 -ll(或 -lfl)。我通常也会添加 nodefault,这样如果某些输入会回退到默认规则,flex 就会产生错误,这通常表示扫描仪规范中存在错误。

总的来说,通常最好将生成的文件包含在分发中,而不是坚持要存在正确版本的 flex 和 bison。 Autotools 也可以以这种方式使用。