asm语句的功能是在Neo Pascal程序中内嵌汇编代码。在实践中,内嵌汇编机制也被程序员广泛应用于各种场合,尤其是系统、硬件方面的开发。
内嵌汇编的优点如下:
(1)内嵌汇编可以完成一些高级语言无法实现的功能。
(2)内嵌汇编可以实现一些对空间、时间要求较高的应用。
(3)有时,内嵌汇编可以简化实现的复杂程度。在实践应用中,这种情况也并不少见。
下面,就来讨论内嵌汇编机制是如何实现的。在现代编译技术中,比较常见的实现方式主要有如下两种:
(1)将汇编语言的文法完全引入高级语言文法中,由编译器统一进行词法、语法、语义等分析。实际上,这种实现方式使得编译器必须实现汇编的词法、语法、语义分析等功能,从而增加编译器实现的复杂度。不过,其优点在于一些内嵌汇编代码中的错误可以尽早被发现。当然,也有利于一些指令级的优化算法得以进行。经典的Turbo Pascal、Delphi都是基于这种方式实现内嵌汇编的。
(2)将汇编代码作为字符串直接嵌入目标代码中,由汇编器统一进行汇编分析。这种方式实现比较简单,编译器不需要关注内嵌汇编的具体代码,只需将其作为普通的单词即可。不过,这种方式会使得一些指令级的优化算法失效,也许这就是易于实现的代价吧。从纠错方面而言,两种方式的纠错能力是相同的,仅有的差别在于报错的阶段不同而已。著名的GCC就是基于这种方式实现内嵌汇编的。同样地,Neo Pascal也是选择了这种实现方式。
下面谈谈Neo Pascal的内嵌汇编机制。一般来说,在处理内嵌汇编时,编译器设计者关注的是如何实现内嵌汇编与输入源程序的信息交换。当然,符号命名规则是保证内嵌汇编与输入源程序顺利实现信息交换的主要因素。换句话说,内嵌汇编访问输入源程序中的变量时,只能是依据该符号的实际名字(即编译器分配的名字),而不是由用户指定的名字。因此,在编译器设计中,用户声明的符号的实际命名并不是完全随机的,为了便于内嵌汇编的访问,统一的命名规则是必不可少的。不过,出于安全考虑,编译器很少允许内嵌汇编直接根据命名规则访问用户变量。因为这种不受限的访问会给编译带来很大的不可控性,这并不是编译器设计者愿意见到的。笔者从GCC的设计中得到灵感,引入了汇编参数的设计方案。
在Neo Pascal中,内嵌汇编主要是由两个部分组成:汇编程序、汇编参数。顾名思义,汇编程序就是内嵌汇编的主体程序段,编译器最终会将其稍作变换后插入到目标代码中。这里,值得注意的是汇编参数。汇编参数同样是一个字符串常量,其主要作用就是指出汇编程序中访问的用户变量。同时,内嵌汇编程序也就是通过这个接口与高级语言程序进行数据交换的。例如:
【声明5-8】
注意,第6行的字符串就是一个汇编参数列表。在本例中,一共有两个参数,即i和i。其中,“@”符号前的字母用于标识参数的读写状态,“r”表示只读,“w”表示只写,“a”表示即读又写。而汇编程序则通过“%X”的方式引用参数。在本例中,“%0”即表示引用i,而“%1”则表示引用j。注意,由于编译器并不分析汇编程序本身的语义,因此,也不严格判定参数中读写状态与实际引用的方式是否一致。因两者不一致而造成的后果,完全是由用户承担的。注意,正确设置读写状态是非常重要的,在后续章节的优化处理中,这个状态标志是具有非常重要的意义的。(www.daowen.com)
下面详细分析内嵌汇编的相关实现。
程序5-25 semantic.cpp
第3~4行:获取汇编参数字符串。
第5~6行:获取汇编程序字符串。注意,汇编程序段在前,而汇编参数字符串在后。
第8行:AsmParaTbl是一张全局向量表,用于存储内嵌汇编的参数信息。当然,根据它的实际用途,将其理解为一个辅助的数据结构可能更合适。
第10~60行:分析汇编参数字符串。注意,这里完成的工作主要包括:分析读写状态标志、分析变量。实际上,这里的本质就是字符串处理。根据先前定义的汇编参数的格式,应该不难理解。下面,笔者对此作简单分析。
第20~38行:分析读写状态标志。
第39~57行:分析变量信息。这里主要有两项工作需要完成:获取变量名、变量名的有效性检查。注意,在进行有效性检查时,同样要关注两级命名空间的问题。
第61~76行:遍历汇编程序,判断汇编程序中引用参数是否存在越界,即引用参数的编号是否超过汇编参数列表给出的参数个数。这里的检查非常必要,否则代码生成可能会出错。值得注意的是,汇编参数列表中的参数可以不被引用,但越界引用却是不允许的。
第77~85行:生成ASM指令。从IR设计的角度来说,ASM指令只有一个操作数,即汇编程序的字符串常量。不过,汇编参数也是一个非常重要的信息,虽然它可能很难直接通过OpInfo传递到后续阶段。这里,笔者借助于操作数2、结果操作数的m_iLink属性传递汇编参数信息。其中,操作数2的m_iLink属性用于标识参数列表在AsmParaTbl表中的起始位置,而结果操作数的m_iLink属性则用于标识参数列表在AsmParaTbl表中的结束位置。后续阶段就可以通过这两种属性访问汇编参数信息了。注意,这里只是借助于这两个操作数而己,但它们本身并不是作为真正的操作数存在于IR中,因此,笔者将两个操作数的m_iType属性都设置为Oplnfo::NONE,以免给后续处理带来不便。
至此,笔者已经详细阐述了语句翻译的理论与实现,这是IR生成的核心部分之一。语句翻译的重点就是建立翻译方案与语义子程序之间的联系,因此,设计翻译方案将是极其重要的。在第6章中,笔者将揭示IR生成的另一个重要部分一一表达式翻译。其中,将涉及类型系统、数组计算、指针引用等复杂而有趣的话题。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。