表达式如何在一次性编译器中工作?
How does expressions work in one pass compiler?
我看过很多关于 one pass 和 multi pass 编译器的帖子,我认为 [=20] 的基本部分=]One Pass Compiler如下。
- Lexical Analysis
- Parse and Syntax Check
- Symbol Table
- Code Generation
但是我有一个问题,我无法理解。 Expression 如何在 one pass compiler(没有 AST)
中工作
我们以1 + 2 / 3
为例。假设您需要为此生成汇编代码。创建解析器后,如何从中生成程序集? ( 直接 )汇编代码如何生成不出错?
你能举个例子解释一下吗?请告诉我这个问题是否有问题。我是 Whosebug 的新手 :)
single-shot 编译器处理类似 a=b*c[i]+d*e;
的最简单方法是处理遇到的每个标记:
a
生成代码将 a
的地址压入堆栈
=
记录堆栈顶部项目将用作赋值目标的事实。
b
生成代码将 b
的地址压入堆栈
*
生成代码以弹出地址(b
),获取那里的对象,然后推送它。
- 同时记录栈顶项将用作乘法运算的左操作数这一事实。
c
生成代码将 c
的地址压入堆栈
[
记录栈顶项将是 [
的左操作数这一事实,并计算以下表达式
i
生成代码将 i
的地址压入堆栈
]
生成代码以弹出地址(i
),获取那里的对象,然后推送它。
- 同时弹出栈上的两项(
i
的值和c
的地址,相加,压入那个结果
+
生成代码以弹出地址(c[i]
),获取那里的对象,然后推送它
- 同时生成代码以弹出前两个值(
c[i]
和 b
),将它们相乘,然后推送结果
- 同时记录栈顶项将是
+
的左操作数这一事实
d
生成代码将 d
的地址压入堆栈
*
生成代码以弹出地址,获取那里的对象,然后推送它。
- 同时记录栈顶项将用作乘法运算的左操作数这一事实。
e
生成代码将 e
的地址压入堆栈
- (语句结束):生成代码以弹出地址(
e
),获取那里的对象,然后推送它
- 同时生成代码以弹出前两个值(
e
和 d
),将它们相乘,然后推送结果
- 同时生成代码以弹出前两个值(
d*e
和 b*c[i]
),将它们相加,然后推送结果
- 同时生成代码以弹出一个值 (
b*c[i]+d*e
) 和地址 a
并将值存储到地址
请注意,在许多平台上,如果将以推送结束的操作的代码生成推迟到生成下一个操作,并且如果将紧跟在推送之后的 pop 与它们合并,则性能可能会大大提高;此外,让编译器记录赋值运算符的左侧是 a
这一事实可能很有用,而不是生成代码来压入该地址,然后让赋值运算符直接执行存储到 a
而不是先计算地址,然后将其用于商店。另一方面,所描述的方法将能够为所有内容生成机器代码,直到正在处理的机器代码的确切字节,而无需跟踪需要展开的挂起操作之外的许多操作。
我看过很多关于 one pass 和 multi pass 编译器的帖子,我认为 [=20] 的基本部分=]One Pass Compiler如下。
- Lexical Analysis
- Parse and Syntax Check
- Symbol Table
- Code Generation
但是我有一个问题,我无法理解。 Expression 如何在 one pass compiler(没有 AST)
中工作我们以1 + 2 / 3
为例。假设您需要为此生成汇编代码。创建解析器后,如何从中生成程序集? ( 直接 )汇编代码如何生成不出错?
你能举个例子解释一下吗?请告诉我这个问题是否有问题。我是 Whosebug 的新手 :)
single-shot 编译器处理类似 a=b*c[i]+d*e;
的最简单方法是处理遇到的每个标记:
a
生成代码将a
的地址压入堆栈=
记录堆栈顶部项目将用作赋值目标的事实。b
生成代码将b
的地址压入堆栈*
生成代码以弹出地址(b
),获取那里的对象,然后推送它。- 同时记录栈顶项将用作乘法运算的左操作数这一事实。
c
生成代码将c
的地址压入堆栈[
记录栈顶项将是[
的左操作数这一事实,并计算以下表达式i
生成代码将i
的地址压入堆栈]
生成代码以弹出地址(i
),获取那里的对象,然后推送它。- 同时弹出栈上的两项(
i
的值和c
的地址,相加,压入那个结果 +
生成代码以弹出地址(c[i]
),获取那里的对象,然后推送它- 同时生成代码以弹出前两个值(
c[i]
和b
),将它们相乘,然后推送结果 - 同时记录栈顶项将是
+
的左操作数这一事实
d
生成代码将d
的地址压入堆栈*
生成代码以弹出地址,获取那里的对象,然后推送它。- 同时记录栈顶项将用作乘法运算的左操作数这一事实。
e
生成代码将e
的地址压入堆栈- (语句结束):生成代码以弹出地址(
e
),获取那里的对象,然后推送它 - 同时生成代码以弹出前两个值(
e
和d
),将它们相乘,然后推送结果 - 同时生成代码以弹出前两个值(
d*e
和b*c[i]
),将它们相加,然后推送结果 - 同时生成代码以弹出一个值 (
b*c[i]+d*e
) 和地址a
并将值存储到地址
请注意,在许多平台上,如果将以推送结束的操作的代码生成推迟到生成下一个操作,并且如果将紧跟在推送之后的 pop 与它们合并,则性能可能会大大提高;此外,让编译器记录赋值运算符的左侧是 a
这一事实可能很有用,而不是生成代码来压入该地址,然后让赋值运算符直接执行存储到 a
而不是先计算地址,然后将其用于商店。另一方面,所描述的方法将能够为所有内容生成机器代码,直到正在处理的机器代码的确切字节,而无需跟踪需要展开的挂起操作之外的许多操作。