"解析"是"编译"的一个子集吗?

mpe*_*pen 6 compiler-construction parsing terminology

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

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

我想提到的是,如果我学习"编译"或阅读一本关于"编译"的书,我是否必须掌握解析非编译语言的技能?

Jul*_*iet 26

简短回答:解析不是编译的子集.

答案:一般来说,将源代码转换为另一种格式有3个步骤:

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

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

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

let x = 0
while x < 10
    print x
    x := x + 1
Run Code Online (Sandbox Code Playgroud)

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

[LET; String("x"); EQ; Int(0); NEWLINE; WHILE; String("x");
 LT; VAL(10); ... ]
Run Code Online (Sandbox Code Playgroud)

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

// 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)));
                ]
        );
    ]
Run Code Online (Sandbox Code Playgroud)

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

  • 您将AST转换为本机代码(编译).
  • 或者您可以动态解释AST,您可以使用动态编程语言或模板引擎.
  • 或者您可以迭代AST以使语法高亮显示.
  • 或者你可以走AST并输出另一种语言的等效代码.
  • 或者您可以查找所有实例Var("x")并使用Var("y")类似于代码重构工具替换它们.

因此,虽然您通常在编译之前解析输入,但这与说解析是编译的子集不同.


Jon*_*eet 5

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

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

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