【问题标题】:Parsing a statement and Adding Paranthesis to them解析语句并向它们添加括号
【发布时间】:2021-10-15 16:04:34
【问题描述】:

我正在尝试解析逻辑 BNF 语句,并尝试对它们应用括号。

例如: 我正在尝试将语句 a=>bc&d 解析为 ((a)=>(b))( (c)&(d)),以及类似的陈述。

面临的问题:有些语句工作正常,而有些则不行。上面提供的示例不起作用,解决方案打印为 ((c)&(d))((c)&(d)) 第二个 expr 似乎覆盖了第一个。

有效的条件:虽然其他简单的例子,如 ab , a|(b&c) 工作正常。

我认为我的代码中出现了一些基本错误,我无法弄清楚。

这是我的代码

lex 文件

letters [a-zA-Z]
identifier {letters}+
operator (?:<=>|=>|\||&|!)
separator [\(\)]    

%%
{identifier} {
    yylval.s = strdup(yytext);
    return IDENTIFIER; }
{operator} { return *yytext; }
{separator} { return *yytext; }
[\n] { return *yytext; }
%%

yacc 文件

%start program
%union  {char* s;}
%type <s> program expr IDENTIFIER
%token IDENTIFIER
%left '<=>'
%left '=>'
%left '|' 
%left '&'
%right '!'
%left '(' ')'

%%
program : expr '\n'     
          { 
            cout<<$$;
            exit(0);
          }
     ;
    
expr : IDENTIFIER  {  
        cout<<" Atom ";
        cout<<$1<<endl;
        string s1 = string($1);
        cout<<$$<<endl;
        
    }
     | expr '<=>' expr   {
        cout<<"Inside <=>\n";
        string s1 = string($1); 
        string s2 = string($3); 
        string s3 = "(" + s1 +")" +"<=>"+"(" + s2 +")";
        $$ = (char *    )s3.c_str();
        cout<<s3<<endl;
     }
     | expr '=>' expr   {
        cout<<"Inside =>\n";
        string s1 = string($1);
        string s2 = string($3); 
        string s3 = "(" + s1 +")" +"=>"+"(" + s2 +")";
        $$ = (char *)s3.c_str();
        cout<<$$<<endl;
     }
     | expr '|' expr    { 
 
        cout<<"Inside |\n";
        string s1 = string($1);
        string s2 = string($3); 
        string s3 = "(" + s1 +")" +"|"+"(" + s2 +")";
        $$ = (char *)s3.c_str();
        cout<<$$<<endl;
     }
     | expr '&' expr    {

        cout<<"Inside &\n";
        string s1 = string($1);
        string s2 = string($3); 
        string s3 = "(" + s1 +")" +"&"+"(" + s2 +")";
        $$ = (char *)s3.c_str();
        cout<<$$<<endl;
     }
     | '!' expr {      

        cout<<"Inside !\n"; 
        string s1 = string($2);
        cout<<s1<<endl;
        string s2 = "!" + s1;
        $$ = (char *)s2.c_str();
        cout<<$$<<endl;
     }
     | '(' expr ')'         {  $$ = $2; cout<<"INSIDE BRACKETS"; }
     ;
%%


请告诉我我犯的错误。

谢谢

【问题讨论】:

  • 你有很多悬空指针,导致未定义的行为。
  • @ChrisDodd 你能帮忙看看如何继续吗? 3 年后我将回到 yacc 和 lex。

标签: parsing flex-lexer yacc lex bisonc++


【解决方案1】:

您遇到的基本问题是您将 string::c_str() 返回的指针保存在 yacc 值堆栈中,但在操作完成并且 string 对象被销毁后,该指针不再有效。

要解决此问题,您需要完全不使用std::string,或者将%union 更改为{ std::string *s; }(而不是char *)。无论哪种情况,您都会遇到内存泄漏问题。如果您使用的是 Linux,则前者非常简单。你的行为会变成这样:

     | expr '<=>' expr   {
        cout<<"Inside <=>\n";
        asprintf(&$$, "(%s)<=>(%s)", $1, $3);
        cout<<$$<<endl;
        free($1);
        free($3);
     }

对于后者,操作如下所示:

     | expr '<=>' expr   {
        cout<<"Inside <=>\n";
        $$ = new string("(" + *$1 +")" +"<=>"+"(" + *$2 +")");
        cout<<$$<<endl;
        delete $1;
        delete $3;
     }

【讨论】:

  • 谢谢!只是一个疑问。如果我做前一部分,解析器会再次检查'(' expr ')' 规则吗?如果不行怎么办?
  • 不,解析器实际上并没有再次检查它。这就是我问你的原因。我希望它再次检查规则。至少我希望解析器再次检查 expr expr 规则。但它没有检查。
  • 对于该规则,您可以只使用'(' expr ')' { $$ = $2; },这将有效地删除括号。或者您可以使用 { asprintf(&amp;$$, "(%s)", $2); free($2); } 将它们放回去
  • 我不确定你所说的“检查”是什么意思——解析器不检查任何东西;它根据规则解析输入。
  • 对不起,让我重新表述我的问题。如果有规则 expr : expr '=>' expr , {$$ = '(' + $1 + ')'} 并且还有另一个规则 '(' expr ')' { $$ = $2; },对于输入a=>b,解析器是否有可能使用规则2,对于规则1的输出
猜你喜欢
  • 1970-01-01
  • 2020-08-22
  • 2013-01-22
  • 2020-05-05
  • 1970-01-01
  • 2016-05-18
  • 2017-05-23
  • 2019-12-14
  • 2011-04-11
相关资源
最近更新 更多