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

时间:2010-11-30 20:39:34

标签: parsing compiler-construction terminology

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

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

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

4 个答案:

答案 0 :(得分:25)

简短回答:解析是而不是编译的一个子集。

长答案:一般来说,将来源转换为其他格式需要3个步骤:

  1. Lexing,它将某种形式的输入转换为令牌流。
  2. 解析,将令牌流转换为抽象语法树(AST)。
  3. 编译,将AST转换为一组可执行指令(本机代码,字节代码等)。
  4. (对于非常简单的语言,您甚至可能不需要解析器,您可能可以直接编译令牌流,或者您的解析器可以直接输出本机代码。)

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

    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"),类似于代码重构工具。)

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

答案 1 :(得分:5)

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

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

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

答案 2 :(得分:2)

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

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

答案 3 :(得分:1)

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

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

在解释诸如Javascript之类的语言时,可以在解析每个语句时执行语句。

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