单目运算符(技术文章:表达式的语法分析)

精英怪
广告

表达式,是编程语言里最重要的语法。

单目运算符(技术文章:表达式的语法分析)

编程语言的主要内容可以分成两部分,计算逻辑

表达式就是计算的过程和结果,而 if / else / while / for等语句表示的都是逻辑。

从广义上来说,逻辑也是二进制的计算。

if (flag)

i += 1;

else

i += 2;

也可以表示成。

编程的哲学思维先说到这里,接着说说表达式的语法分析。

表达式的语法分析也与其他模块一样,源代码怎么写,语法分析就怎么写

当然,表达式的语法分析比其他模块的复杂,我在scf框架里写了1000行左右。

表达式,是由变量、单目运算符、双目运算符、常量、小括号、中括号等组成的,以逗号或分号结尾。

小括号在表达式里的语义有多种:

1,表示子表达式,修改原表达式的计算顺序

例如:

(1 + 3) / 2 就需要先计算1 + 3,而1 + 3 / 2 就需要先计算3 / 2,跟小学数学里的一样。

2,表示类型转换,T* p = (T*) malloc(sizeof(T));

左小括号后面跟类型名,然后再跟右小括号,然后跟子表达式,是类型转换的语法。

3,表示函数调用,malloc(16),这里的小括号就表示函数调用。

函数调用的语法,是函数名后面跟左小括号,然后跟实参列表,然后跟右小括号

实参列表可以为空,也可以为1个子表达式,或多个以逗号分隔的子表达式。

中括号在表达式里的语义是取数组的成员,语法是数组名字后面跟左中括号,然后跟表示数组索引子表达式,然后跟右中括号

不管是数组名、函数名、还是类型名,都是标志符

变量名也是标志符。

它们表示的具体语法元素,可以通过从抽象语法树当前位置往根节点方向搜索得到,从而实现对源代码的作用域控制。

int a = 1;

{

int a = 2;

{

int a = 3;

int c = 4 + a; //这个a肯定是当前作用域的3

}

}

上述代码的抽象语法树

如上图,在给a = 3赋值时,先找到的肯定是当前作用域的变量a,而不可能是父作用域的变量a。

这在编程语言里叫变量名字的隐藏,即使用的变量是最近的作用域里的变量。

与使用位置在同一个作用域里的变量,肯定是最最近的[呲牙]

c = 4 + a这行表达式,使用的a也肯定是最近的a。

常量和变量语法分析阶段的表达式里,几乎没有区别。它们之间的区别可以留待语义分析时再处理。

if (1 == a) 如果被写成 if (1 = a)了,在语法分析时可以认为这两个条件表达式都是对的,到了语义分析时再判断数字常量1不能被赋值。

这样在语法分析时就只需要检查表达式的语法错误,而不必检查语义错误

这样在语法分析时就不需要把赋值运算符=做特别处理,把它当作普通的双目运算符就行。

表达式的运算符主要分单目运算符双目运算符

单目运算符unary operator)可以位于表达式的开头,一般都是右结合的。

双目运算符binary operator)必须位于两个变量或常量(或子表达式)的中间,一般都是左结合的,但赋值类的运算符是右结合的。

sizeof也是一个单目运算符,但它的操作数放在小括号里,这个小括号要做特别处理,我在scf框架里给它单独做了一个sizeof模块。

数组成员的运算符是[],语法是array [ index ],它的两个操作数是数组array和索引index,写法有点特别,要对左右中括号做特别处理。

结构体指针的运算符->,语法是s->member,它的两个操作数是结构体指针s和成员member,其中member要去结构体自己的作用域里查找。

星号的语义有2个,一是双目运算符乘法,二是单目运算符指针解引用。

当星号位于两个变量或常量(或子表达式)之间的时候是乘号(a * b)。

当星号*位于表达式的开头(*p),或者其他运算符的后面(!*p)时是指针解引用。

表达式语法的具体编辑如下,已加注释,共4张图。

构建抽象语法树的代码就不解释了,1000多行实在太多了,估计也没几个人有耐心看[捂脸]

发表评论

快捷回复: 表情:
AddoilApplauseBadlaughBombCoffeeFabulousFacepalmFecesFrownHeyhaInsidiousKeepFightingNoProbPigHeadShockedSinistersmileSlapSocialSweatTolaughWatermelonWittyWowYeahYellowdog
评论列表 (暂无评论,391人围观)

还没有评论,来说两句吧...