自己动手制作C 语言编译器(8):表达式

这是整个编译器的最后一部分,解析表达式。什么是表达式?表达式是将各种语言要素的一个组合,用来求值。例如:函数调用、变量赋值、运算符运算等等。

表达式的解析难点有二:一是运算符的优先级问题,二是如何将表达式编译成目标代码。我们就来逐一说明。

运算符的优先级

运算符的优先级决定了表达式的运算顺序,如在普通的四则运算中,乘法*优先级高于加法+,这就意味着表达式2 + 3 * 4的实际运行顺序是2 + (3 * 4)而不是(2 + 3) * 4。

C 语言定义了各种表达式的优先级,可以参考C 语言运算符优先级

传统的编程书籍会用“逆波兰式”实现四则运算来讲解优先级问题。实际上,优先级关心的就是哪个运算符先计算,哪个运算符后计算(毕竟叫做“优先级”嘛)。而这就意味着我们需要决定先为哪个运算符生成目标代码(汇编),因为汇编代码是顺序排列的,我们必须先计算优先级高的运算符。

那么如何确定运算符的优先级呢?答曰:栈(递归调用的实质也是栈的处理)。

举一个例子:2 + 3 - 4 * 5,它的运算顺序是这样的:

将2入栈

遇到运算符+,入栈,此时我们期待的是+的另一个参数

遇到数字3,原则上我们需要立即计算2+3的值,但我们不确定数字3是否属于优先级更高的运算符,所以先将它入栈。

遇到运算符-,它的优先级和+相同,此时判断参数3属于这前的+。将运算符+出栈,并将之前的2和3出栈,计算2+3的结果,得到5入栈。同时将运算符-入栈。

遇到数字4,同样不能确定是否能立即计算,入栈

遇到运算符*优先级大于-,入栈

遇到数字5,依旧不能确定是否立即计算,入栈

表达式结束,运算符出栈,为*,将参数出栈,计算4*5得到结果20入栈。

运算符出栈,为-,将参数出栈,计算5-20,得到-15入栈。

此时运算符栈为空,因此得到结果-15。

 

推荐C/C++编程交流学习群:941636044 群内许多资料可以下载哦!

综上,在计算一个运算符‘x’之前,必须先查看它的右方,找出并计算所有优先级大于‘x’的运算符,之后再计算运算符‘x’。

最后注意的是优先通常只与多元运算符相关,单元运算符往往没有这个问题(因为只有一个参数)。也可以认为“优先级”的实质就是两个运算符在抢参数。如果想一起交流的可以加这个群:941636044 ,有什么问题可以群里面交流,群里面也有一些方便学习C语言C++编程的资料可以给你利用哦!

一元运算符

上节中说到了运算符的优先级,也提到了优先级一般只与多元运算符有关,这也意味着一元运算符的优先级总是高于多元运算符。因为我们需要先对它们进行解析。

当然,这部分也将同时解析参数本身(如变量、数字、字符串等等)。

关于表达式的解析,与语法分析相关的部分就是上文所说的优先级问题了,而剩下的较难较烦的部分是与目标代码的生成有关的。因此对于需要讲解的运算符,我们主要从它的目标代码入手。

常量

首先是数字,用IMM指令将它加载到AX中即可:

if (token == Num) {

    match(Num);

 

    // emit code

    *++text = IMM;

    *++text = token_val;

    expr_type = INT;

}

接着是字符串常量。它比较特殊的一点是 C 语言的字符串常量支持如下风格:

char *p;

p = "first line"

    "second line";

即跨行的字符串拼接,它相当于:

char *p;

p = "first linesecond line";

所以解析的时候要注意这一点:

else if (token == '"') {

    // emit code

    *++text = IMM;

    *++text = token_val;

 

    match('"');

    // store the rest strings

    while (token == '"') {

        match('"');

    }

 

    // append the end of string character '', all the data are default

    // to 0, so just move data one position forward.

    data = (char *)(((int)data + sizeof(int)) & (-sizeof(int)));

    expr_type = PTR;

}

sizeof

sizeof是一个一元运算符,我们需要知道后面参数的类型,类型的解析在前面的文章中我们已经很熟悉了。

else if (token == Sizeof) {

    // sizeof is actually an unary operator

    // now only `sizeof(int)`, `sizeof(char)` and `sizeof(*...)` are

    // supported.

    match(Sizeof);

    match('(');

    expr_type = INT;

 

    if (token == Int) {

        match(Int);

    } else if (token == Char) {

        match(Char);

        expr_type = CHAR;

    }

 

    while (token == Mul) {

        match(Mul);

        expr_type = expr_type + PTR;

    }

 

    match(')');

 

    // emit code

    *++text = IMM;

    *++text = (expr_type == CHAR) ? sizeof(char) : sizeof(int);

 

    expr_type = INT;

}

注意的是只支持sizeo

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值