Parsing 野牛:我如何操作解析树?

Parsing 野牛:我如何操作解析树?,parsing,bison,yacc,lex,flex-lexer,Parsing,Bison,Yacc,Lex,Flex Lexer,我的应用程序的目标是验证一个sql代码,同时从该代码生成一个经过一些修改的格式化代码。例如,where子句: 其中e.student\u name=c.contact\u name和(c.address=“nefta” 或者c.address=“tozeur”)和e.age您的问题有点模糊,所以我猜您实际上是在您的clbck_或()中打印的。wildplasser提到的“常见”方式是使用“语义值”,即。E(未经测试): 如果您使用的是Bison,手册中“中缀符号计算器:`calc'”一节中有一个

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

其中
e.student\u name=c.contact\u name和(c.address=“nefta”
或者c.address=“tozeur”)和
e.age您的问题有点模糊,所以我猜您实际上是在您的clbck_或()中打印的。wildplasser提到的“常见”方式是使用“语义值”,即。E(未经测试):


如果您使用的是Bison,手册中“中缀符号计算器:`calc'”一节中有一个很好的例子。对于字符串和C,您必须添加一些内存处理。

Bison擅长解析,并且在一些手动帮助下,擅长构建自定义语法树。在那之后,你可以对这棵树做你想做的事。好消息是你可以做任何你想做的事。坏消息是你仍然需要建造很多机器来做你想做的事情。重新生成源代码的基本问题称为“预打印”;请参阅my以了解执行此操作所需的步骤,包括词法语法的所有细节(您不希望丢失文本字符串中的转义,对吗?)。你根本没有提到如何在树中找到你想要改变的结构,或者如何打破树来改变它

如果你不想做所有这些,那么你真正想要的是一个,擅长解析的,为你构建语法树(因此你不必考虑,SQL是非常大的语法),它可以让你根据你习惯的SQL语法在树中找到模式,在不太了解树的形状的情况下修改树,最终可以通过预打印重新生成有效的源文本,正如我在上面的答案链接中所描述的。(程序转换系统基本上包括作为子例程的解析器)

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

 domain SQL;

 rule trim_c_members(f: identifier, s: string):condition->condition
 = " c.\f = \s " ->  " c.\f = trim(\s) ";
这是DMS规则语言(meta)语法,用于描述对(“域”)SQL代码的重写。 规则有一个名称(因为在复杂的应用程序中有很多规则),并且 作为句法上的占位符“f”和“s”;它只重写代码中的条件。 引号是RSL元引号;里面的内容是带有RSL元变量“\f”的SQL 和“\s”;外部的东西是RSL规则语法。规则说的是, “对于显式命名为‘c’的变量的任何条件,以及任何字段f, 如果将该字段与某个文本字符串进行相等比较,则替换 应用于“文本字符串”的“trim”文本字符串

我遗漏了一些基本上是这样的代码,“将此规则应用于整个树,不要在同一个地方应用两次”。这一“战略”是DMS中内置的众多战略之一

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

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

这个规则纯粹是由语法驱动的;如果您希望将更复杂的条件应用于规则(例如,变量必须仅在您定义的特定范围内),可以添加语义谓词(未显示),这让messier这么说。但是它比爬过AST(注意,您在这里没有看到AST?)并试图找出所有这些的C代码要简单得多,也更容易阅读

解析和预打印在规则应用前后进行;实现这一切需要很多机器,但这些机器是内置在DMS中的(例如,它的内置功能类似于[但更强大],而对于预定义的域(如SQL),所有漂亮的打印工作也都已预配置


如果您想更好地了解DMS的完整使用周期(定义您自己的语言解析器、定义漂亮的打印机、定义复杂的规则),下面是一个使用DMS的好方法。

到底是什么问题?是否要在完成后转换查询树?是否要更改子句中术语的“顺序”?@wildplasser触发CLBCK的顺序与写入输入的顺序不同;我想用相同的顺序重写where子句,而不做任何更改树节点中的顺序由左/右关联性和优先规则决定。行走或操纵时,您可以选择按顺序/顺序/顺序后行走。你可以将((a&b)&c)重写为(a&(b&c),甚至((c&b)&a)for OR(当然不是for And And OR combined),如果只使用优先级来构建表达式树,他就必须使用优先级来解构它。(a+b)*c可能将树编码为[[a b+]c]缺少括号;简单的按树顺序行走会打印出+BC,因此他需要使用相同的优先级信息重新生成括号。[您的示例似乎将括号保留在树中,这对于“抽象语法树”来说是不寻常的;如果您想重新生成源文,我恰好同意这是一个好主意]为什么要构建一个单独的树?我阅读了这个问题,因为查询者想要转换一些SQL。@TimLandscheidt是的,我实际上做了一些打印(在全局缓冲区中连接字符串)
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);}
                         ;
 domain SQL;

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