使用 antlr 为另一种语言生成源代码

usage of antlr for generating source code for another language

可以ANTLR用于解析一种语言的源代码并为另一种语言创建源代码吗?

因为到目前为止,看着所有这些听众,我看不出有什么方法可以隔离不同的设施——比如不同的 statement 块等等——以创建另一种语言设施

(program (programHeading program (identifier HelloWorld) ;) 
(block (procedureAndFunctionDeclarationPart (procedureOrFunctionDeclaration 
(procedureDeclaration procedure (identifier myprocedure) (formalParameterList ( 
(formalParameterSection (parameterGroup (identifierList (identifier x) , (identifier y)) : (typeIdentifier integer))) )) ; 
(block (compoundStatement begin (statements (statement (unlabelledStatement (simpleStatement (procedureStatement (identifier writeln) ( 
(parameterList (actualParameter (expression (simpleExpression (term (signedFactor (factor (variable (identifier x))))) + (term (signedFactor 
(factor (unsignedConstant (string ' : '))))) + (term (signedFactor (factor (variable (identifier y))))))))) ))))) ; 
(statement (unlabelledStatement (simpleStatement emptyStatement)))) end)))) ;) (compoundStatement begin (statements 
(statement (unlabelledStatement (simpleStatement (procedureStatement (identifier from))))) i := 1 to 10 do begin writeln ( i ) ;) end)) ; writeln ( 'Hello, World!' ) ; end .)

例如,我看不到一种方法来定义一个 begin 语句从哪里开始而另一个 end 结束。

好吧,我可以使用 stack 助手来做一些事情,但在那种情况下我可以自己逐行解析文件...

是这段代码的解析结果

program HelloWorld;

procedure myprocedure(x, y: integer);
begin
    writeln(x + ' : ' + y);
end;

begin
    from i := 1 to 10 do
    begin
        writeln(i);
    end;
    writeln('Hello, World!');
end.

可能是我看错了或者没看懂?

是的,ANTLR 可用于将 L1 语言翻译成 L2 语言。但这远没有人们说的那么容易。

方法 1:为 L1 构建一个解析器。遍历 L1 实例的树。在每个节点,使用 ANTLR 的字符串模板吐出 L2 的翻译文本。

您会发现很难准确决定要生成什么,因为您在每个位置生成的内容取决于上下文(周围的声明、代码以及您决定如何翻译其他语言结构)。考虑翻译:

 a+b

如果 "a" 是一个数字,与 "a" 是一个字符串相比,您想要生成的内容可能会有很大不同。您无法通过查看该表达式中的 "a" 来了解这一点;您必须找到并解释 "a" 的声明(例如,构建并参考符号 table)。

您会发现很难生成 好的 代码,因为(字符串模板)输出是原始文本,您无法轻松解释该文本以对其进行优化。 例如,假设您想翻译:

x = y + "abc"
x = x + "def"

一个简单的翻译器(逐个陈述)可能会产生(作为纯文本):

set(x,concat(y,"abc"))
set(x,concat(x,"def"))

但优化翻译器理想情况下会产生:

set(x,concat(y,"abcdef"))

只能通过检查输出并意识到可以优化输出来做到这一点。 (好吧,在这个例子中你可以先优化输入,但语言差异可能会阻止)。

这个问题激发...

方法 2:为 L1 构建一个解析器。为 L2 构建一个解析器。走过 L1 树。在每个节点上,使用 ANTLR 为 L2 生成的节点构造函数构建一个 L2 树。出于同样的原因,您将很难决定生成什么,但是现在您有了 L2 树,您至少可以考虑编写代码来遍历 L2 树并对其进行优化,例如,实现 L2-to -实现上述操作的L2树变换。

完成后,prettyprint the L2 tree。您可以使用 ANTLR 的 L2 节点字符串模板来提供帮助。

纯 parser-based 翻译器的其他问题

这两种方法都存在像 ANTLR 这样的纯解析器生成器所具有的普遍问题:它们没有(简单)方法 collect context information needed to implement a good translator。 [这将适用于您选择的任何 纯解析器生成器]。

您通常还需要其他支持,例如漂亮的印刷机。如果可以直接写下变换,生活也会更方便,例如

 rule translate_square(t: term): product -> product
      "  \t**2 " =>   " \t * \t "

而不是编写代码在树上走来走去来确定根是 "power" 运算符,而右边的 child 是常数 2。您需要编写数百位如果 L1 是一种重要的语言,则翻译 L1 中所有结构的代码,并且在程序上执行此操作会很快变得令人厌烦。

因此,您可以使用任何解析器生成器构建从一种语言到另一种语言的翻译器。这肯定比只构建一个没有解析器生成器的翻译器要好,你也可以这样做(许多真正的编译器都是这样构建的)。但是,虽然解析器生成器帮助了一些,但它几乎无法解决问题。你需要更多的机器,并且应该比仅仅让解析器工作花费更多的努力(许多真正的编译器付出这个代价来实现他们的结果)。