nju-pa摸鱼记2-计算机与λ演算
一、前言
在上一篇中,讨论了如何使用预处理指令或是宏来识别某个宏是否被定义,以实现通过配置进行有选择的编译。不过,仅使用上一篇讨论的isdef
宏还不能达到和预处理指令一样的效果,本篇将继续讨论框架中如何使用宏来实现“如果某个宏被定义,则预处理后保留某些语句或代码块,反之抛弃这些部分”的功能。之所以提到
二、浅谈 演算
1、简介
其中
通过柯里化方法,可以定义二输入函数:
其中
2、用抽象化函数表示布尔逻辑
在
用自然语言来描述
上面的三个函数都是利用了
当且仅当
3、 演算与计算机的联系
这个函数看起来有些奇怪,似乎只是把三个参数排列在一起输出了,并不能看出其中的“选择功能”,但是
if
语句:
1 |
|
三、更进一步
有了
其中isdef
是在上一篇定义的宏函数,如果
通过上面的抽象定义,已经实现了预期的功能,但是到C语言中,还面临着一些细节问题。首先,isdef
的值是1
或0
,而不是上面定义的和函数。这就导致C语言预处理器并不会把isdef
替换为1
或0
后再当作一个“函数”来解释。其次,isdef
中使用了strcmp
函数,这显然不能在函数外面使用,函数的运行结果在运行时才被计算出来。
对于第一个问题,如何将isdef
的值解释为一个函数呢?由于1
和0
在C语言中被解释为整型字面量,所以可以给这个1
或者0
“加点东西”,然后定义新的宏,这里用到了##
运算符:
1 |
|
宏concat
将两个参数粘连起来,MUX
仍然是上面抽象的函数。假设MUX_OUT
的输入参数是(code_block, , isdef(foo)
,并且宏foo
已经被定义过,先不考虑其他问题,经过宏MUX_MID
和concat
,最终传入MUX
的参数将会变为(code_block, , PREFIX_1)
。如果我们继续定义宏函数PREFIX_1
和PREFIX_0
,就可以解决第一个问题了:
1 |
|
这里定义的TRUE
和FALSE
宏函数其实就是上面MUX
怎么定义,我们想要将最后的PREFIX_1
或者PREFIX_0
作用在a
和b
上,那么只需要改一下参数的顺序,再加个括号就行了:
1 |
|
下面来看第二个问题,宏isdef
在预处理阶段不会被替换为1
或0
,因此,不能通过MUX_OUT(a, b, isdef(macro))
来使用这个宏,这样肯定是有问题的。需要一个宏,能在预处理阶段就产生1
或0
的结果。由于我们是在配置编译时使用,所以对于某个选项,要么它被定义了,要么它没被定义,而被定义的宏我们并不在乎它是什么值,所以可以限制为:“一旦定义,就将它定义为t
”(这个限制只在本篇中成立)。
再整理一下,现在需要一个宏,来检测一个“一旦定义,就被一定被定义成t
”的宏是否被定义,如果被定义了,预处理时它会被替换成1
,否则被替换成0
。在这个假设下,被定义了的宏会被替换为t
,而没有被定义的宏在预处理阶段会保留为宏名。可以使用刚才的“加点东西”技术,把替换后的t
再进一步替换为别的东西:
1 |
|
这一系列宏的关键之处在于choose2nd_mid
宏定义中p_macro
和a
之间没有逗号,如果macro
被定义成了t
,则会被替换为“t,
”(t
后面有一个逗号分隔),从而成为了第二个参数;当未被定义或者被定义成别的,是第二个参数。
上面的讨论中已经涉及了大部分NEMU框架中所使用的技巧和方法,实现这些宏的思路与
四、参考资料
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!