扩展阅读:解释下语法分析和语义分析的区别

回顾编译过程

学习过编译原理的话,编译过程包含的主要步骤,我们应该都有这方面认识。Go编译期编译过程主要包含这么几个步骤:

  • 词法分析(Lexical Analysis):将源代码转换为单词流(tokens),识别关键字、标识符、运算符等;
  • 语法分析(Syntax Analysis):将 token 流解析为抽象语法树(AST);
  • 语义分析(Semantic Analysis):检查 AST 的语义,处理变量声明、类型检查、作用域等;
  • 中间代码生成(Intermediate Code Generation):将 AST 转换为静态单赋值(SSA)形式,便于优化;
  • 目标代码生成(Target Code Generation):将 SSA 中间表示转换为平台特定的汇编代码;

ps: ELF 符号表和调试信息(DWARF),编译器在处理中间代码时,会收集符号信息并生成 DWARF 调试数据。

语法 vs 语义

其中语法分析、语义分析,没有其他几个步骤字面上区分度那么高,如果没有亲自尝试写编译器,只是看这个术语本身的话,很容易混淆它们的不同。其实,语法分析和语义分析,是有明显不同之处的:

1. 目标不同

  • 语法分析的主要目的是验证源代码是否符合语言的语法规则,并将其转换为抽象语法树(AST)。这一步骤关注的是代码的结构是否正确,确保没有语法错误。
  • 语义分析则侧重于理解代码的意义和逻辑。它在生成的AST基础上进行进一步的处理,如类型检查、作用域分析等,以确保代码在语义上是正确的。

2. 输入与输出不同

  • 语法分析的输入是源代码文本,其输出是一个抽象语法树(AST),表示代码的结构。
  • 语义分析的输入是抽象语法树(AST),其输出是对程序进行了一系列语义检查和处理后的中间表示,确保每个元素在类型和逻辑上都是合理的。

3. 关注点不同

  • 语法分析中,编译器关注的是代码的形式结构,比如词法单元是否正确组合成有效的语句和表达式。
  • 而在语义分析中,编译器不仅检查结构的正确性,还要确保变量的使用符合其声明类型,函数调用参数与定义一致等。

4. 错误类型

  • 语法分析过程中发现的错误通常是词法或语法错误,如拼写错误、括号不匹配等。
  • 语义分析过程中发现的错误是语义错误,如类型不兼容、变量未声明等。

5. 实现步骤

  • 语法分析一般包括:

    • 扫描源代码生成token流。
    • 解析token流生成AST。
  • 语义分析一般包括:

    • 建立符号表,管理变量的作用域。
    • 进行类型检查,确保操作的合法性。
    • 处理表达式和语句的语义信息。

6. 在Go编译器中的实现

  • 语法分析主要由 parser.go文件中的 ParseFile()函数实现,生成AST。
  • 语义分析主要由 noder.go文件中的 NewNoder()Noder.Emit()函数实现,处理中间表示并进行类型检查。

7. 示例

举个简单的例子:

func main() {
    var a int
    a = 5
}
  • 语法分析会将这段代码转换为一个AST,包含函数定义、变量声明和赋值操作。
  • 语义分析则会在生成的AST基础上检查:

    • a是否在作用域内被正确声明。
    • 赋值操作中5是否与int类型兼容。
    • 函数调用等其他可能的操作是否符合语义规则。

通过以上步骤和示例,可以看出语法分析和语义分析虽然都是编译过程中的关键阶段,但它们关注的焦点和处理的内容是不同的。语法分析确保代码的结构正确,而语义分析则确保代码在逻辑上合理且无误。

results matching ""

    No results matching ""