解释器如何翻译 for 循环?

liy*_*uan 2 compiler-construction interpreter compilation

我知道解释器将您的源代码逐行翻译成机器代码,并在遇到错误时停止。

我想知道,当你给它 for 循环时,解释器会做什么。

例如,我有以下(MATLAB)代码:

for i = 1:10000

pi*pi

end
Run Code Online (Sandbox Code Playgroud)

它真的运行并逐行翻译 for 循环 10000 次吗?

使用编译器时,机器代码更短,仅由一组语句组成,其中包含对 10000 次迭代有效的 go to 控制语句。

如果这没有意义,我很抱歉,我对编程的基础知识不是很了解,但我想快速理解。

sep*_*p2k 5

我知道解释器将您的源代码逐行翻译成机器代码,并在遇到错误时停止。

这是错误的。有许多不同类型的解释器,但很少有人逐行执行代码,而执行代码的解释器(主要是 shell)根本不生成机器代码。

一般来说,有四种或多或少的常见方式可以解释代码:

  • 逐语句执行

    这大概是你所说的逐行的意思,除了通常分号可以用作换行符的替代方法。正如我所说,这几乎只能由 shell 完成。

    它的工作原理是一次解析一个语句。那就是解析器读取标记直到语句完成。对于简单的语句,直到到达语句终止符为止,例如行尾或分号。对于其他语句(例如 if 语句、for 循环或 while 循环),直到找到相应的终止符(endif、fi 等)。无论哪种方式,解析器都会返回语句的某种表示(通常是某种类型的 AST),然后执行。任何时候都不会生成机器代码。

    这种方法有一个不寻常的特性,即文件末尾的语法错误不会阻止文件开头的执行。然而,一切仍然最多被解析一次,即使条件为假,if 语句等的主体仍将被解析(因此 an 中的语法错误if false仍将中止脚本)。

  • AST-walking 解释

    这里一次性解析整个文件并从中生成 AST。然后解释器简单地遍历 AST 来执行程序。原则上与上面相同,只是首先解析整个程序。

  • 字节码解释

    再次对整个文件进行一次解析,但解析器生成的不是 AST 类型的结构,而是生成一些字节码格式。然后逐条指令执行该字节码。

  • JIT 编译

    这是实际生成机器代码的唯一变体。这有两种变体:

    • 在调用之前为所有函数生成机器代码。这可能意味着在加载后立即翻译整个文件或在调用之前翻译每个函数。生成代码后,执行它。
    • 首先解释字节码,然后在执行多次后分别对特定函数或代码路径进行 JIT 编译。这使我们能够根据在解释期间收集的使用数据进行某些优化。这也意味着我们不会为调用次数不多的函数支付编译开销。一些实现(特别是一些 JavaScript 引擎)还会重新编译已经 JIT 的代码,以根据新收集的使用数据进行优化。

所以总结一下:逐行(或者更确切地说是逐语句)执行代码的实现与生成机器代码的实现之间的重叠应该非常接近于零。而那些逐个语句执行的实现仍然只解析一次代码。