【问题标题】:Detect conditions of an if statements using Bison and Flex in C++在 C++ 中使用 Bison 和 Flex 检测 if 语句的条件
【发布时间】:2015-01-12 00:17:14
【问题描述】:

我想在 C++ 中获取 if 语句的所有条件。如果我输入(foo&&bar&&(one&&two)),那么我想打印foo - bar - one - two

我已经编译了scanner.l 和parser.y 文件,并单独测试:my yy.lex.c 有效:如果我输入(a&&b),那么我得到5 个令牌:(a&& , b) 我想要的。但是当我使用 .y 文件时,如果我输入相同的输入,则会得到 a&&bb)。请注意,在这种情况下,我得到 2 个令牌,因为令牌 a&&b 应该分为 3 个令牌 a&&b。我尝试引入一个更简单的条件:(a) 然后我得到:(a) 但我想得到 (a)

我不知道我做错了什么还是一个错误;希望是我的错。

parser.y

%{
    #include <iostream>
    #include <list>
    #include <stdio.h>
    #include <sstream>
    #include <string>

    using namespace std;

    int yylex(void);
    void yyerror(char *);

    list<string> tokenList;

    #define YYSTYPE char *
%}

%token  PAR_IZQ
        PAR_DER
        SIMBOLO
        FIN
        NADA
        AND
        OR

%start input

%%

input:

    |   input terminos
;

terminos:
        PAR_IZQ terminos PAR_DER    { }
    |   PAR_IZQ condicion PAR_DER   { }
;

condicion:
        terminos AND terminos       { }
    |   SIMBOLO AND terminos        { cout << " 1) CONDITION FOUND: " << $1 << endl; }
    |   terminos AND SIMBOLO        { cout << " 2) CONDITION FOUND: " << $3 << endl; }
    |   SIMBOLO AND SIMBOLO         { cout << " 3) CONDITION FOUND: " << $3 << " AND " << $1 << endl; }
    |   SIMBOLO                     { cout << " 4) CONDITION FOUND: " << $1 << endl; }
;

%%

void yyerror(char *s) {
    fprintf(stderr, "%s\n", s);
}

int main(void) {
    yyparse();
    return 0;
}

scanner.l

%option noyywrap
%{
    #include <iostream>
    #include "parser.tab.c"
    using namespace std;
%}

%%

[a-zA-Z0-9]+  {
    yylval = yytext;
    return SIMBOLO;
}

"&&" {
    return AND;
}

"||" {
    return OR;
}

[ \0\0] {
    return FIN;
}

"("     {
    yylval = yytext;
    return PAR_IZQ;
}

")"     {
    yylval = yytext;
    return PAR_DER;
}

.       {
    cout << "Entrada no permitida.";
    cout << endl << yytext << endl;
    exit(1);
}

%%

ma​​in.cpp

#include "mainwindow.h"
#include <QApplication>
#include "lex.yy.c"
#include <iostream>
#include <vector>
#include <string>

using namespace std;

typedef yy_buffer_state *YY_BUFFER_STATE;
extern int yyparse();
extern YY_BUFFER_STATE yy_scan_buffer(char *, size_t);

int main(int argc, char** argv) {

    char condition[] = "(a) \0\0";
    // note yy_scan_buffer is looking for a double null string
    yy_scan_buffer(condition, sizeof(condition));
    yyparse();
    return 0;
}

请注意,解析器的输入是一个字符串,所以我必须将它作为yy_scan_buffer 函数的参数传递。 \0\0 是必要的,否则程序将永远不会结束其执行。控制台显示红色“语法错误”,但我不知道为什么!

你知道如何修复它并获得我想要的令牌吗?

谢谢!

PS:我正在使用 Windows 8.1、Qt creator 2.8.1、win_bison 2.7 和 win_flex 2.5.37

【问题讨论】:

  • 离题但仍然:我真的可以推荐使用 Flexc++ 和 Bisonc++(不要与 bison++ 和 flex++ 混淆)。这些将生成适当的 C++ 代码供您使用,而不是 yy_ 的东西 ;-)
  • 我怀疑你需要增加解析器的前瞻。
  • 如果你想认真做这件事,你将需要一个匹配正在使用的 C++ 语法,以及所有 C++ 前端机制(宏扩展、名称解析、模板实例化,......处理 C++14 特性的方法,因为它实际上是目前的标准)。滚动一个非常简单的语法将无济于事。如果您这样做是为了获得教育体验,那么请继续并忽略我。

标签: c++ bison flex-lexer parser-generator


【解决方案1】:

问题是您的词法分析器将yytext 返回到解析器,因为yylval 与符号标记相关联,但yytext 是指向词法分析器内部标记缓冲区的指针,该缓冲区仅在下一个标记出现之前有效读。因此,当您稍后在您的条件下打印出令牌时,您会得到半随机垃圾(因为不久之后,您通常只会得到相同的原始令牌缓冲区,没有终止空字符)。

在将yytext 指向的字符串返回给解析器之前,您需要对其进行复制:

[a-zA-Z0-9]+  {
    yylval = strdup(yytext);
    return SIMBOLO;
}

当然,您还需要跟踪何时不再需要该字符串以及free

或者,由于您没有使用%union,请将#defineYYSTYPE 更改为

#define YYSTYPE  std::string

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多