【问题标题】:Conditional statement parsing in yaccyacc 中的条件语句解析
【发布时间】:2017-01-12 17:14:39
【问题描述】:

我正在为某种语言编写一个 llvm 代码生成演示,其中包括 if 语句。以下是与我的问题相对应的规则和操作:

IfStatement : IF CondExpression THEN Statement                      {if_Stmt(string($2),string($4));}                     %prec LOWER_THAN_ELSE ;  
            | IF CondExpression THEN Statement ELSE Statement       {if_else_Stmt(string($2),string($4),string($6));} 
            ;            

CondExpression : Expression Relop Expression            { $$ = operation($2,string($1),string($3));printf("Relop value : %s \n",$2);}
                | Expression                            {$$ = $1;}
               ;

Relop :     EE                  {$$ = (char *)(string("icmp eq ").c_str());printf("%s\n",$$);}                  
      | NE                  {$$ = (char *)(string("icmp ne ").c_str());} 
      | LT                  {$$ = (char *)(string("icmp slt ").c_str());} 
      | GT                  {$$ = (char *)(string("icmp sgt ").c_str());} 
      | LTE                 {$$ = (char *)(string("icmp sle ").c_str());}  
      | GTE                 {$$ = (char *)(string("icmp sge ").c_str());} 
          ;

CondExpression 规则应该解析条件表达式。我正在使用打印函数来打印类型为 的 Relop 令牌的值。 Relop 应该具有字符串函数内的条件标记的值,如上面的代码所示。但是打印函数的结果是0

 Relop value : 0

而且Relop里面第二次打印的结果是正确的,

Relop value : icmp eq 

为什么 CondExpression 中的 Relop 值为 0 以及如何使其取 Relop 规则返回的正确值。

【问题讨论】:

  • 你的语义类型是什么?
  • char * 用于 CondExpression 和 Relop

标签: llvm yacc llvm-clang llvm-ir llvm-gcc


【解决方案1】:

不仅是

(char *)(string("icmp ne ").c_str()

一种荒谬的写作方式

"icmp ne"

它还引入了简单而明显的替代方案中不存在的未定义行为。 string 构造函数创建并返回一个临时字符串,然后c_str 用于返回指向该临时内部存储的指针。然后,您将该指针存储到解析器堆栈中并让临时对象被解构,从而使存储的指针成为孤儿。因此,当您尝试打印字符串时,您传递的是一个悬空指针,任何事情都可能发生,例如内存被其他对象重用导致打印一个神秘的字符串。

当然,如果你的语义类型是char *,C++ 会抱怨$$ = "icmp eq"; 不是常量安全的。对我来说,为什么不使用 char *const 作为语义类型并不是很明显,除非代码的其他部分打算修改字符串或可能需要释放内存(因为在某些情况下,字符串是动态分配的)。在这种情况下,您可以使用例如strdup 来强制复制字符串。如果您的库不提供 strdup 或者您不想依赖它,则可以轻松将其定义为类似

char* strdup(const char* s, size_t len=strlen(s)) {
  char* r = malloc(len + 1);
  memcpy(r, s, len);
  r[len] = 0;
  return r;
}

虽然更类似于 C++ 的解决方案是使用 std::string* 作为语义类型,但允许您编写:

$$ = new std::string("icmp eq");

【讨论】:

  • 这些是等于、不等于、小于、大于..等的字符串:releases.llvm.org/2.7/docs/LangRef.html。我要求找到一个不造成问题的解决方案
  • @rational:我理解字符串的含义。解决方案是解决我发现的问题。使用字符串文字或字符串文字的副本(如果出于某种原因需要副本。)但不要创建悬空指针。
猜你喜欢
  • 2019-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多