解释器包含什么?

What does an Interpreter contain?

我正在使用 Antlr4 创建解释器、词法分析器和解析器。它将使用的 GUI 包含 QScintilla2。

由于 QScintilla 不需要解析器并且有一个 CustomLexer 模块,(Antlr4 内置,Python3 目标)解释器是否足够?

我不是在征求意见,而是在征求事实指导。谢谢。

What does an Interpreter contain

解释器必须有某种方法来解析代码,然后有某种方法 运行 它。通常 "way to parse the code" 将由词法分析器+解析器处理,但无词法分析器的解析也是可能的。无论哪种方式,解析器都会创建代码的一些中间表示,例如树或字节码。 "way to run it" 将是一个迭代生成的树或字节码并执行它的阶段。 JIT 编译(即从树或字节码生成机器码然后执行)也是可能的,但更高级。您还可以 运行 解析和执行之间的各种分析(例如,您可以检查是否有任何未定义的变量或在任何地方使用,或者您可以进行静态类型检查——尽管后者在解释型语言中并不常见)。

当使用 ANTLR 时,ANTLR 会为您生成一个词法分析器和解析器,后者会生成一个解析树作为结果,您可以使用生成的侦听器或访问器对其进行迭代。在这一点上,您可以按照您认为适合自己的代码的方式进行。例如,您可以从解析树生成字节码并执行它,将解析树转换为简化树并执行它,或者直接在访问者中执行解析树。

QScintilla is about displaying the language and is not linked to the interpreter. In an IDE the console is where the interpreter comes into play along with running the script (from a 'Run' button for example). The only thing which is common to QScintilla and the interpreter is the script file - the interpreter is not connected or linked to QScintilla. Does this make basic sense?

是的,这是有道理的,但不必完全那样。也就是说,重用解释器的某些部分来实现 editor/IDE 中的某些功能是有意义的,但您不必这样做。

您特别提到了 "Run" 按钮,就此而言,解释器的实现(以及它是否使用 ANTLR)完全无关紧要。事实上,解释器使用哪种语言编写并不重要。如果您的解释器名为 mylangi,而您当前正在编辑名为 foo.mylang 的文件,则点击 "Run" 按钮应该简单地执行 subprocess.run(["mylangi", "foo.mylang"]) 并在某种选项卡或 window.

中显示结果

同样,如果你想有一个 "console" 或 "REPL" window 你可以在其中与解释器交互:你只需将解释器作为子进程调用并将其连接到选项卡或显示控制台的 subwindow。同样,解释器的实现与此无关——您可以像对待任何其他命令行应用程序一样对待它。

现在 IDE 和代码编辑器的其他功能是语法高亮显示、自动完成和错误高亮显示。

对于语法高亮,您需要一些代码来遍历源代码并告诉编辑器代码的哪些部分应该使用哪种颜色(或粗体等)。使用 QScintilla,您可以通过提供执行此操作的词法分析器 class 来完成此操作。您可以通过简单地编写必要的代码来手动检测标记的类型来定义这样的 class,但您也可以重新使用 ANTLR 生成的词法分析器。因此,这是可以在 editor/IDE 中重新使用解释器实现的一种方式。然而,由于语法高亮器通常很容易手写,因此您不必这样做。

对于代码完成,您需要了解文件中定义了哪些变量和函数、它们的范围是什么以及当前文件中还包含哪些其他文件。如今,在所谓的语言服务器中实现此逻辑变得很普遍,该语言服务器是可以从不同的编辑器和 IDE 中重复使用的独立工具。无论您是在这样的语言服务器中还是直接在您的编辑器中实现此逻辑,您都需要一个解析器(如果适用,还需要一个类型检查器)来回答这些类型的问题。同样,这也是您可以从解释器中重复使用的东西,这一次绝对是个好主意,因为编写第二个解析器将是一项重要的额外工作(并且很容易与解释器的解析器不同步)。

对于错误突出显示,您可以简单地在 "verify only" 模式下调用解释器(即仅打印出语法错误和其他可以静态检测到的错误,但实际上并不 运行 文件 - - 许多解释器都有这样的选项),然后解析输出以找出在何处绘制波浪线。但是你也可以从你的解释器中重新使用解析器(如果你有的话,分析)。如果您采用语言服务器的方式,错误和警告也将由语言服务器处理。