友情提示:本文共有 1167 个字,阅读大概需要 3 分钟。
语法分析(parse),是把词法分析(lex)生成的一个个词word,按照语法规则转化成语句,并生成抽象语法树(AST)的过程。
在这个过程中,要做语法检查,查看代码是否有语法错误,并提示修改。
语法分析程序,实际上并不怎么好写。
一般情况下,代码都含有大量的不同类型的语句嵌套,以及同类语句的递归嵌套,和递归函数调用。
这让各种类型的语句扭在一起,很难使用单一的语句类型去分析,而不得不多管齐下,还要互相调用,实际形成了深层次的复杂递归算法。
语法分析涉及的常见语句类型,大概有这几种:
1,表达式,
这是最重要,也是最常见的语句之一。
表达式,是由变量、常量、运算符、函数调用、数组索引、指针解引用、对象的成员变量、对象的成员函数调用等,组成的“复杂”式子。
数组索引[],函数调用(),指针解引用*,对象的成员变量->,对象成员函数调用obj->fun(),也都是特殊的运算符,其中最后一个要使用2个运算符和对象的指针变量名及成员函数名,本身就是一个表达式。
当然,简单的算术表达式,只包含变量、常量,和加减乘除模等简单运算。
2,声明和定义语句,
这是用来声明变量、函数、数据结构,以及定义函数、数据结构的内容的语句。
C语言只有结构体struct,C++的类class和结构体struct除了默认权限分别是private和public之外,差不多也是一回事。
以下统一叫类吧:(
函数和类的声明和定义可以分开,也可以写在一起。
定义本身就已经做了声明。
在语法分析时,定义和声明的区别是,定义在声明语句之后以“左大括号{”开始内容定义,并以“右大括号}”结束,而声明以“分号;”结束这行语句。
当然也可以使用其他符号,例如python就使用了“冒号:”和“换行n”。
变量的声明和定义,实际是一码事。变量的类型本身就已经提供了足够的信息。
3,if else语句,
就像它的英文名字一样,条件语句,用来选择代码执行的不同分支。
4,while循环语句,
5,for循环语句,
6,break,continue语句,
与if else语句搭配用在循环里,break也用在switch case里。
7,switch case语句,
类似if else语句,又略有区别,大多数情况下可以互相替代。
8,goto语句,
给了程序很大的灵活性,又破坏了程序的结构性的语句,尽量少用。
在中间代码优化阶段,goto写成的非结构化循环,会大大提高循环分析的难度,因为它可以导致循环有多个出口,甚至多个入口。
9,块,
由大括号{}标示开始和结束,其中可以含有其他语句,也可以含有子块,它本身还可以被其他语句包含。
这里就暗含着递归嵌套,也是导致语法分析复杂性的关键来源之一。
源代码里的嵌套,在语法分析时就会引起递归。
语法分析的复杂,主要是两个来源,一是表达式本身的复杂,二是各种语句可以通过块互相嵌套。
本文如果对你有帮助,请点赞收藏《编译器入门 语法分析 简介》,同时在此感谢原作者。