我目前正在阅读《SPARC架构、汇编语言编程和C.第二版》这本书。我到了书中的某个地方,我不明白或无法理解某个命令:
define(loc, 0)
define(sto, 'loc: 44 $1 define('loc', eval(loc+2))')
问题是,我确实理解第一行。但我真的不明白第二行的第二个参数。书上的解释也没有帮助。
摘自书中:
这里我们首先定义了一个符号 loc,其值为 0。该符号将代表位置计数器,即正在汇编的指令的内存地址。每个宏定义都已更改,首先打印 loc 的当前值,然后将 loc 重新定义为 loc 加上存储指令所需的内存位置。
宏的参数是字符和字符串,而不是数值。在重新定义 loc 的值时,我们使用另一个内置宏 eval。 eval 使用其字符串参数来表示算术表达式。 eval 计算该表达式并以数字字符串的形式返回其值。
我知道上述解释对您来说可能听起来很清楚,但对我来说却不然。我完全不明白的是这部分: 'loc: 44 $1 Define('loc', eval(loc+2))'
我不明白:
为什么这是一个字符串?
为什么loc必须在那里?
为什么定义了 44 $1 后,还有另一个定义,“define('loc', eval(loc+2))'?
听起来任务是使用 m4 宏制作汇编程序。预期的输出将类似于:
0000: 44 xx
0002: yy zz
...
也就是说,每一行都以地址为前缀,后跟机器代码字节。
开头的
loc:
将为您打印当前地址,44
可能是 sto
指令的操作码,$1
是参数。最后一部分是重新定义 loc
,使其指向下一个可用位置。由于该指令占用两个字节,因此loc
增加2。
请注意,m4 使用反引号来启动字符串。您可能从书中抄错了。
鉴于此示例输入:
define(loc, 0)
define(sto, `loc: 44 $1 define(`loc', eval(loc+2))')
sto(01)
sto(AA)
输出为:
0: 44 01
2: 44 AA
在理解m4时,你必须顽固地遵循m4所遵循的逻辑。
阅读
define(loc, 0)
这是一个宏,不会展开任何内容。接下来有一个新行,并且该新行仍然存在。然后它评估参数。 m4 查找loc。 幸运的是它还没有定义。如果是例如
define(loc, 0)
define(loc, 12)
然后第二个宏将在扩展后执行
define(0, 12)
并且loc的值仍然是0。 通常你应该转义你想要定义的宏的名称,所以
define(`loc', 0)
define(`loc', 12)
现在loc的展开确实是12。 (这应该会让你对本书作者的知识渊博感到厌倦。)
现在是第二行(已更正)
define(`sto', 'loc: 44 $1 define('loc', eval(loc+2))')
M4评估参数
sto
loc: 44 $1 define('loc', eval(loc+2))
显然 sto 将成为一个宏。 define(st.. 扩展为仅一个空行。
现在看看 sto 的用法,例如使用参数 orangutan 来调用它。
sto(`orangutan')
然后 m4 扩展 sto
0: 44 orangutan define(`loc', eval(0+2))
Pigheadely 将 loc 替换为 0,只要它没有转义。 该定义扩展为空,但具有给 loc 值 2 的效果。 因此,第二行扩展(具有 loc 的副作用)到
0: 44 orangutan