65.9K
CodeProject 正在变化。 阅读更多。
Home

堆栈机器的适应性语法汇编器

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.89/5 (3投票s)

2021年7月18日

GPL3

8分钟阅读

viewsIcon

7422

一种上下文敏感语言

本文旨在简要介绍一种在堆栈机上运行的、具有可适应语法的汇编语言。最初,所有指令都是字符;换句话说,机器语言指令就是字符编码。本文重点介绍该汇编器与其他堆栈机的区别,以及该语言与其他语言的区别,因为大多数读者已经了解堆栈机以及在堆栈机上运行的语言。

一些字符,如“1”,具有自然含义,而另一些字符,如“A”,则没有。由于某些字符没有自然含义,因此可以对其进行定义以赋予其含义。该机器为某些字符分配了含义,例如“Д表示定义。该语言称为Ameba;它运行在一个称为计算器的堆栈机上。

字符的固有含义是计算器将其定义为操作符或操作数。字符的自然含义是其文化内涵或人们普遍的理解。计算器在可能的情况下,将字符的固有含义定义为其自然含义。例如,字符“1”具有数值“1”,“+”表示加法,但“G”没有特定且一致的含义。另一方面,“1”和“+”在许多文化中具有相同的含义。

计算器的固有符号是具有固有含义的单个字符。可以声明或定义额外的单个或多个字符符号。声明的符号存在于符号表中,但没有定义。符号定义是由已定义符号组成的表达式。换句话说,一旦定义了一个符号,就可以用它来定义其他符号。随着越来越多的符号被定义,定义体不断增长。最终,计算器符号可能代表整个系统。

使用定义操作符Ð来声明或定义单个或多个字符符号。声明的符号存在于符号表中,但没有定义它的方法或属性。已定义的符号具有定义它的方法或属性。定义表达式的形式是Ðsym defð,其中sym是要定义的符号,以空格结束,而def是一个表达式,即一串已定义的符号,例如 Ðfifteen 9+6ð。符号必须在使用前声明。

定义可以嵌套在另一个定义内部,如下例所示:Ðfifteen Ðsix 6ð 9+sixð。内部定义(例如six)的范围仅限于外部定义(例如fifteen)。计算器实现可能支持也可能不支持线程;如果支持,每个线程将有一个本地符号表。

Ameba按照写入顺序计算表达式,没有优先级,采用类中缀语法。例如,a+b$c表示将a加到b并将结果保存在c中。没有行或语句,只有表达式,包括括号内的子表达式、循环和条件语句。循环语法使用字符£¤Ø。条件语法使用字符?:;¿。计算器可以对表达式进行部分求值,结果仍为表达式,例如5+6+B -> 11+B。

子表达式的形式如下:(e),其中e是表达式。Ameba调用自身来计算子表达式,包括循环和条件语句中的子表达式。

循环的形式如下:£ a ØB c ¤.其中£开始一个循环,¤终止它,B是一个布尔操作数子表达式,ac是每次迭代计算的子表达式,不同之处在于c的计算次数比a少一次,因为ØBB为真时退出循环。Ø操作符测试其操作数B,并在B=true时退出循环。

条件的形式如下:?B:a;c¿。其中ac是子表达式,B是一个布尔操作数子表达式;该条件可以理解为如果B为真,则条件的值由计算ac来确定。也可以理解为:如果Ba否则c

当计算器将文本代码翻译成令牌代码(一种p-code)时,它会创建一个符号表。令牌是一个指向符号的整数。符号是语言元素,如字面量、变量、表达式、条件语句或循环。以上面的例子a+b$c为例,符号有a+b$c+b$ca+b$c。符号a+b$c包含三个令牌,即分配给a+b$c的令牌。这三个令牌翻译成字符字符串a+b$c

符号是令牌的字符串,即令牌代码,长度各不相同;因此,符号在内存中的起始和结束地址是不规则的。令牌字符串以Null令牌(即Null令牌=0)终止。符号地址的向量由令牌索引。字符符号的令牌是其字符代码(例如,“0”是令牌#30,十六进制)。反向翻译令牌代码得到文本代码,这意味着令牌代码适用于求值、部分求值和程序化静态分析。

符号不能包含前导或尾随空格,因为空格会终止符号。除了空格字符和其他空白字符外,它们也以空白字符开头和结尾。未用空格分隔的符号可能无法被正确识别。当一个较长的符号包含一个较短的符号时,可能会出现歧义。例如:假设已定义的符号anyway包含已定义的符号aananyway。搜索文本anyway将找到符号anyway而不是anyway。换句话说,搜索算法优先选择较长的符号而不是较短的。要强制搜索找到anyway,请用空格分隔它们,例如any way

符号anyway 被分配一个令牌(例如,9037)。它由两个符号any way 组成,它们有自己的令牌,例如582代表any,620代表way。因此,多令牌字符串582 620存储在符号表中,而不是字符“anyway”。反过来,anyway也作为令牌字符串存在于符号表中。例如,way由三个令牌组成,即字符way的字符代码,它们是十六进制的77、61和79。

符号表是一个语法树,它捕获了由子表达式组成的表达式的本质,而这些子表达式又由子表达式组成……由字符组成的字符串组成。每个表达式、子表达式、字符字符串和字符都是符号表中表示的唯一符号。如果一个服务器管理符号表,那么许多人都可以访问它,它就变成了一个对象存储库,具有安全性和可能的版本控制。这样的服务器可以通过共享其符号来帮助最大化代码重用,无论组织有多大。  

符号表的访问方式是:通过令牌进行直接访问,或者通过符号进行搜索访问。令牌代码到文本代码的翻译需要直接访问。文本代码到令牌代码的翻译需要搜索访问。令牌代码的求值需要直接访问。

当调用一个中缀操作符(例如,+)时,左侧的操作数已被求值,其值将在堆栈顶部。其右侧的操作数尚未被求值或解析。操作符(例如,+)必须通过调用Ç函数(称为cull-operand)来获取并求值其右侧的操作数。收集过程将解析移入任何操作符(例如,+)的方法中。换句话说,cull-operand将语法处理与语义处理结合到方法代码中。因为它将语法的控制权交给了程序员,所以Ameba成为一种元语言。Cull-operand获取紧跟在调用Ç以获取操作数的操作符后面的下一个符号。在表达式1+2中,+操作符调用Ç来获取其右侧操作数2。

Ç函数使用堆栈上的返回地址,该地址是右侧操作数的位置,来设置计算器的程序计数器。它递归调用计算器来求值右侧的操作数,该操作数可以是简单的字面量,也可以是复杂的子表达式。Cull-operand还会将返回地址向前移动,使其指向刚刚收集的右侧操作数之后,这意味着一个操作符可以收集多个操作数。

Ameba将字面量、注释、子表达式、循环和条件语句等语法形式视为自声明符号。这些语法形式的第一个字符是一个操作符,它可以收集多个右侧操作数。例如,整数的第一个数字是一个操作符,它收集后续数字以构成一个整数,并在符号表中声明它。处理子表达式更复杂,因为括号之间的收集需要调用计算器来处理其中的符号。

总而言之,这是Ameba的一个草图,一个介绍,并非旨在涵盖其设计的全部细微之处。关键问题是如何通过消除单片机规则解析器来创建一种具有适应性语法的语言。计算器可以同时求值文本代码并将其翻译成令牌代码。它还可以独立于文本代码对令牌代码进行求值,从而获得更好的性能。适应性语法使Ameba成为一种元语言,能够编译其他语言(例如C)到令牌代码。此外,Ameba可以增强自身的语法,并应提供部分求值以进行专门化和优化。它需要一个集成开发环境(IDE),包含集成的测试管理器、静态分析系统和CASE扩展。它的限制仅限于处理器资源、时间和内存,以及我们的想象力。

感谢我的妻子Anna审阅,使本文档得以大大改进。

(c) Edwin E. Ross II 2021年7月

© . All rights reserved.