【问题标题】:Is "parsing" a subset of "compiling"?“解析”是“编译”的子集吗?
【发布时间】:2011-05-18 03:06:07
【问题描述】:

当我想到“编译”时,我想到将 C++ 代码转换为二进制文件。或者也许将 C# 转换为 CLR 字节码。但“解析”可能类似于解析 Python 或 Web 模板语言,它不需要生成任何二进制文件,但可以立即执行代码、逐条语句或直接输出 HTML。

在这两种情况下,你基本上都会做同样的任务吗?忽略语言语法,编译 C++ 是否与解析网站模板文件(Django、Smarty 等)或 Python 一样困难?

我想暗示的是,如果我学习“编译”或阅读一本关于“编译”的书,我是否一定会掌握解析非编译语言的技能? p>

【问题讨论】:

  • 编译需要解析,但是解析不需要编译。存在关系,但没有 is-a 关系。
  • 再添一块拼图,在asp.net中我们可以直接部署源代码文件,无需编译,因为Dynamic Compilation!

标签: parsing compiler-construction terminology


【解决方案1】:

简答:解析不是编译的子集。

长答案:通常,将源转换为另一种格式有 3 个步骤:

  1. Lexing,将某种形式的输入转换为令牌流。
  2. 解析,将令牌流转换为抽象语法树 (AST)。
  3. 编译,将 AST 转换为一组可执行指令(本机代码、字节码等)。

(对于非常简单的语言,您甚至可能不需要解析器,您可以直接编译令牌流,或者您的解析器可以直接输出本机代码。)

所以从这样的原始字符串开始:

let x = 0
while x < 10
    print x
    x := x + 1

词法分析器会将其转换为令牌流,可能是这样的:

[LET; String("x"); EQ; Int(0); NEWLINE; WHILE; String("x");
 LT; VAL(10); ... ]

解析器会将流转换成更有意义的数据结构,你的抽象语法树:

// AST definition
type expr =
    | Block of expr list
    | Assign of string * expr
    | While of expr * expr
    | Call of string * expr list
    | Add of expr * expr
    | Var of string
    | Int of int

// AST instance created from token stream
Block
    [
        Assign("x", Int(10));
        While
        (
            LessThan(Var("x"), Int(10)),
            Block
                [
                    Call("print", [Var("x")]);
                    Assign("x", Add(Var("x"), Int(1)));
                ]
        );
    ]

一旦你有了 AST,你就可以用它做任何事情:

  • 您将 AST 转换为本机代码(编译)。
  • 或者您可以即时解释 AST,您可以使用动态编程语言或模板引擎来执行此操作。
  • 或者您可以迭代 AST 来制作语法高亮。
  • 或者您可以遍历 AST 并以另一种语言输出等效代码。
  • 或者您可以查找Var("x") 的所有实例并将它们替换为Var("y"),类似于代码重构工具)。

因此,虽然您通常在编译之前解析输入,但这并不等同于说解析是编译的一个子集。

【讨论】:

  • 哇。没想到这么详细的回答。谢谢!不知道这个:)
【解决方案2】:

不,解析和编译可以完全独立。

  • 解析器可能根本不会发出任何代码。它可能正在解析一些数据对象(JSON、XML 等)
  • 编译器可能没有源代码开始 - 它可以呈现一个抽象语法树,已经解析,只需要发出相关代码

大多数编译器包含一个解析步骤,但我认为它不一定是编译的“子集”,解析当然与编译没有任何关系。

【讨论】:

  • 如果你是编译源代码,那么我认为解析是必要的。
  • @jjnguy:我同意。但是,我认为编译器并不总是将源代码作为其输入。 JIT 编译器就是一个例子。
【解决方案3】:

...“我会学习解析非编译语言的技能吗?”是的,你会的,但你可以自己研究解析。

然而,您会发现很多编译(名称解析、类型推断、模式匹配、编译为指令 [pcode 而不是机器码]、高性能执行、针对特殊情况进行优化)在 处理非编译语言。因此,如果您打算做的不仅仅是字面意义上的解析,那么无论如何您都需要学习编译器技术。

【讨论】:

    【解决方案4】:

    编译实际上比解析更困难,因为它只是编译的初步步骤之一。

    解析后生成符号表,从中生成实际的二进制代码。

    在 Javascript 等解释性语言中,可以在解析每个语句时执行语句。

    http://en.wikipedia.org/wiki/Parsing

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-28
      • 1970-01-01
      • 1970-01-01
      • 2019-03-01
      • 2012-12-05
      • 2012-02-29
      相关资源
      最近更新 更多