YACC | BISON:我如何操纵解析树?

时间:2012-01-11 16:39:13

标签: parsing bison yacc lex flex-lexer

我的应用程序的目标是验证一个sql代码并同时从该代码生成带有一些修改的格式化代码。
例如,where where子句:

  

其中
e.student_name = c.contact_name和(c.address =“nefta”   或c.address =“tozeur”)和e.age< 18

我们将具有格式化输出的内容:

  

其中e.student_name = c.contact_name
和(c.address = trim(“nefta”)   
或c.address = trim(“tozeur”))
和e.age< 18

我希望我已经很好地解释了我的目标


问题是语法可能包含使重写任务不可靠的递归规则;例如在我的sql语法中我有这个:

search_condition         : search_condition OR search_condition{clbck_or}
                         | search_condition AND search_condition{clbck_and}
                         | NOT search_condition {clbck_not}
                         | '(' search_condition ')'{clbck__}
                         | predicate {clbck_pre}
                         ;

知道我指定优先级优先级来解决轮班减少问题

  

%左OR   %左和   %left NOT

回到最后一个例子;我的条款将以这种方式消费:

  

c.address =“nefta”或c.address =“tozeur” - > search_condition
  (c.address =“nefta”或c.address =“tozeur”) - > search_condition
   e.student_name = c.contact_name和(c.address =“nefta”或c.address =“tozeur”) - > search_condition
   ......和e.age< 18-> search_condition

顺便说一句,你可以理解重建输入流是很困难的,因为每次减少都会引起回调,导致订单不一样。

对此问题有任何帮助吗?

2 个答案:

答案 0 :(得分:2)

你的问题有点模糊,所以我猜你在你的clbck_or()中实际上是 print 等.wildplasser提到的“常见”方式是使用“语义值” “, 一世。即(另):

search_condition         : search_condition OR search_condition{$$ = clbck_or($1, $3);}
                         | search_condition AND search_condition{$$ = clbck_and($1, $3);}
                         | NOT search_condition {$$ = clbck_not($2);}
                         | '(' search_condition ')'{$$ = clbck__($2);}
                         | predicate {$$ = clbck_pre($1);}
                         ;

如果你正在使用Bison,那么手册在“Infix Notation Calculator:`calc'”部分有一个很好的例子。使用字符串和C,您将不得不添加一些内存处理。

答案 1 :(得分:1)

Bison擅长解析,并且有一些手动帮助,擅长构建自定义语法树。在那之后,由你决定你想要的树。好消息是你可以随心所欲。坏消息是你仍然需要建立很多机器来做你想做的事情。重新生成源代码的基本问题称为“prettyprinting”;请参阅我的SO answer on how to prettyprint以了解执行此操作所需的内容,包括词汇语法的所有简介(您不要丢失文字字符串中的转义,对吧?)。你根本没有解决如何在树中找到你想要改变的构造,或者你如何粉碎树来改变它。

如果你不想做所有这些,那么你真正想要的是program transformation system,它擅长解析,为你构建一个语法树(所以你不必考虑它,SQL是一个非常大的语法),可以让你根据习惯的SQL语法在树中找到模式,在不了解树的形状的情况下进行树变化,最后可以通过prettyprint重新生成有效的源文本。我在上面的回答链接中描述。 (程序转换系统本质上包括一个解析器作为子程序)。

我们的DMS Software Reengineering Toolkit就是这样一个程序转换系统。它有一组预定义的language definitions,包括SQL2011和用于配置特定方言的方法。 使用DMS源到源语法规则,您可以使用以下规则在示例中执行更改:

 domain SQL;

 rule trim_c_members(f: identifier, s: string):condition->condition
 = " c.\f = \s " ->  " c.\f = trim(\s) ";

这是用于描述(“域”)SQL代码重写的DMS规则语言(元)语法。 该规则有一个名称(因为在复杂的应用程序中有很多规则)和它 作为句法占位符“f”和“s”;它只重写代码中的条件。 报价是RSL元报价;里面的东西是带有RSL元变量的SQL“\ f” 和“\ s”;外面的东西是RSL规则语法。规则是什么, “对于明确命名为'c'的变量的任何条件,任何字段f, 如果该字段通过相等性与某些文字字符串进行比较,则替换 'trim'的文字字符串应用于文字字符串“。

我省略了一些基本上说的代码,“将此规则应用于整个树,并且不要在同一个地方应用两次”。这种“策略”是DMS内置的众多策略之一。

关于规则如何运作的问题。这是通过DMS将SQL解析器应用于元引用的字符串来实现的,以生成带有占位符的“模式”语法树,其中写入了元变量。然后将左侧模式树与目标树匹配,占位符引用子树;右侧树拼接在左侧树匹配的位置,并且转移了占位符子树。所以,程序员看到你知道和喜爱的表面sytax;该工具适用于树木,因此不会被文本混淆。

现在,我认为我的规则并不完全符合你的意图,但这部分是因为我无法猜出你的实际意图。如果这不是您想要的,您可以编写其他规则。

这条规则完全由语法驱动;如果您希望将更复杂的条件应用于规则(例如,变量必须仅在您定义的某些范围内的变量),则可以添加语义谓词(未显示),并且说得更加混乱。但它比攀登AST的C代码更简单,更容易阅读(注意你没有在这里看到AST?)并试图弄清楚这一切。

解析和漂亮发生在规则申请之前和之后;有很多机器需要实现所有这些,但是这个机器内置在DMS中(例如,它有比[内置的Bison更强大]),对于预定义的域,如SQL,所有漂亮的打印工作都有也是预配置的。

如果你想更好地了解使用DMS进行完整循环所需要的东西(定义一个漂亮的打印机,定义一个漂亮的打印机,定义复杂的规则),这里有一个很好的完整example of defining and symbolically simplifying calculus使用DMS