【问题标题】:move subtree from one part of AST to another将子树从 AST 的一部分移动到另一部分
【发布时间】:2013-05-07 09:37:15
【问题描述】:

我正在开发一种将 Oracle SQL 转换为 ANSI SQL 的工具。我有一个可以同时解析 Oracle SQL 和 ANSI SQL 的语法。

我想从 AST 的 where 子句部分提取 Oracle 外连接表达式,并在匹配的 select 或子查询的 AST 的 from 子句部分的末尾插入新的连接子句。

具有重写规则的树解析器可以进行这种类型的树转换吗?

即获取从 Oracle SQL 生成的 AST

SELECT
  a.columna, b.columnb
FROM
  tablea a,
  tableb b
WHERE
  a.columna2 (+) = b.columnb2 (+)
  AND
  a.columna3 = 'foo'
  AND
  b.columnb3 = 'bar'

并将其转换为 ANSI SQL 的 AST

SELECT
  a.columna, b.columnb
FROM
  tablea a FULL OUTER JOIN tableb b ON (a.columna2 = b.columnb2 )
WHERE
  a.columna3 = 'foo'
  and
  b.columnb3 = 'bar'

注意1:tableatableb 的表引用从FROM 子句中删除,并替换为引用相同表和表别名的JOIN 子句。

注意 2:Oracle 连接条件通过 sql_condition 比较两侧的 OuterJoinIndicator (+) 标识为 FULL OUTER JOIN

注意 3:连接条件比较已从 WHERE 子句中删除,并用于构造连接子句 ON 条件[删除了 OuterJoinIndicator(s)]。

【问题讨论】:

    标签: antlr antlr3 abstract-syntax-tree


    【解决方案1】:

    是的,这很有可能,特别是因为您的语法可以识别 Oracle 和 ANSI SQL。我曾经写过一个从 AREV BASIC 到 Visual BASIC 的翻译器,并且做了很多类似的转换。

    在我的项目中,我使用了 ANTLR 2 并编写了一个主树语法,它什么也没做,只是根据我语法中的所有规则完全遍历树。然后我使用 ANTLR 2 的子类化来覆盖特定的规则来进行转换。我喜欢这个,因为它让我可以通过传递来构建翻译,并在一个传递中保留我的所有表达式处理,在另一传递中保持控制结构等。

    ANTLR 3 不提供语法子类化,因此您将无法使用该方法。您将需要完整的树语法来打印生成的树。就个人而言,我会先编写该树语法并使其正常工作。然后我会复制该语法并删除所有操作,但添加重写 AST 的选项。然后修改转换所需的规则。如果您进行许多转换,您可能希望使用多遍,每遍使用一个树语法。您可能有一两次进行分析以帮助推动以后的传球。在我的 BASIC 翻译项目中,我进行了控制流分析、数据流分析和分析过程中的死代码删除。

    如果您在编写特定转换时需要帮助,您需要分享您的树语法。有很多树语法习语可以让你一头雾水。如果您需要帮助,Terence 的 ANTLR 3 书将是一笔宝贵的购买。如果您还没有编写树语法,请在遇到困难时发布问题。选择正确的根节点很重要。如果您想了解如何构建树和树解析器,可以查看我的 C 语法。它是 ANTLR 2,但树构建概念是相同的。 http://www.antlr3.org/grammar/cgram/grammars/

    您需要保留 cmets 和格式吗?这增加了另一层复杂性,我建议为此创建另一个问题。

    【讨论】:

      【解决方案2】:

      如果您有两种不同的语法,您可能会发现语法中的“微小差异”会导致这些子句的 AST 相当不同,因此您真正的问题是将其中一种的树结构转换为树另一个结构。您必须对整棵树分段执行此操作,因为这些差异遍布整个语法。 YMMV。

      ANTLR 的树解析器很可能让您识别任意片段;这些当然是在其他语法的 AST 中生成等价物的线索。但是你必须编写很多这样的片段,以及代码对应的例程来逐个节点地组装等效的树。作为大型语法(如 Oracle SQL)的一般规则,这可能是相当多的工作。你可以这样做。

      另一种选择是program transformation 系统。这些工具允许您编写表面语法模式(例如,Oracle SQL 和 ANSI SQL 中的短语)来直接编码和应用您的转换。恕我直言,以这种方式编写转换要容易得多。你最终会写出这样的东西:

       source domain Oracle.
       target domain ANSISQL.
       rule xlate_Oracle_SELECT(c: columns, t1: table, t2: table,
                                c1: column, c2: column,
                                more_conditions: conditions):SQL_phrase
           "SELECT \c FROM \t1, \t2 WHERE c1 (+) = c2 (+) and \more_conditions";
        =>
            "SELECT \c FROM  \t1 FULL OUTER JOIN \t2 on ( c1 = c2 ) WHERE \more_conditions";
      

      (反斜杠 ID 是模式变量,可以匹配在该位置合法的声明语法类型的任意子树。)

      之所以如此,是因为转换工具使用第一个语法解析第一个模式,因此得到一个可以匹配第一个语法树的树,并且类似地使用 second 解析第二个模式em> 语法,得到一个遵循第二个语法规则的替换树。转换引擎将树匹配第一个模式,并用树替换第二个。因此,这样的规则将一小组蓝色树节点从蓝色树转换为一小组所需树类型的绿色节点。颜色类比应该清楚地表明,如果您想要准确的翻译,您必须将所有蓝色节点翻译成绿色节点。

      您需要额外的规则来翻译各种子条款,以掩盖语法上的差异,例如:

      rule translate column(t: IDENTIFIER, c: IDENTIFIER, ):table->table
          "\t.\c" -> " \toSQLidentifier\(\t\).\toSQLidentifier\(\c\)";
      

      这将通过调用自定义函数 toSQLidentifier 来处理两种语言拼写标识符的差异。

      我认为 ANTLR 不支持这种转换规则。你可以通过大量的代码来模拟它。

      如果您对两种语言都有一个“联合”语法(这是您所暗示的),您可能会避免其中的一些,但这通常会给您带来高度模棱两可的语法,这会带来很多麻烦。如果你成功了,那么你只需要在语言不同的地方应用翻译规则(例如,一切都是蓝色节点)。

      你也可以破解它:从左到右扫描树; prettyprint 等效的部分(弄清楚这一点比看起来更难),它们不同的地方,prettyprint 替换。这是一种非常脆弱的方法。

      【讨论】:

      • 只有 1 种语法可以解析 Oracle SQL 和我们需要的所有 ANSI SQL 语法。
      • 语法识别需要处理的sql_condition的情况,并添加可按token类型搜索的“标签”。
      • condition_comparison : ( ( column_reference OuterJoinSign relop column_reference OuterJoinSign ) => col1a=column_reference oj1a=OuterJoinSign rop1=relop col1b=column_reference oj1b=OuterJoinSign -> ^( 't_full_join_condition' $col1a $oj1a $rop1 $col1b $oj1b ) | ( column_reference OuterJoinSign relop column_reference ) => col2a=column_reference oj2a=OuterJoinSign rop2=relop col2b=column_reference -> ^( 't_right_join_condition' $col2a $oj2a $rop2 $col2b )
      • 我通过在转换后漂亮地打印 AST 来重新生成 ANSI SQL。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-03-22
      • 2017-12-08
      • 2022-06-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多