使用程序进行短路评估

时间:2012-02-27 08:35:34

标签: compiler-construction language-design short-circuiting

我目前正在为非常有限的面向对象语言开发编译器。我希望将所有值视为对象,并将这些值上的运算符实现为方法。编译器将程序转换为基于堆栈的虚拟机的汇编程序。

在编译期间,我将整数文字转换为特殊“整数”类的对象。算术运算符作为该类的方法实现(使用内联汇编程序)。因此4 + 5基本上等于4.add(5)

我现在面临的问题是布尔值的特殊情况。如果有if声明:

if(10 > 5 || 12 < 10)

目前这将转换为:10.greaterThan(5).or(12.lessThan(10))

现在很明显,这些整数文字也可以调用具有副作用的函数。在这种情况下,将这些二元运算符实现为方法调用会产生问题,因为短路评估变得不可能。

所以我的问题是:

  1. 其他语言如何实现短路评估,但仍将每个值视为对象?

  2. 根据维基百科“ALGOL 68使用”程序“实现用户定义的短路操作员和程序”。 - 这是如何工作的?

3 个答案:

答案 0 :(得分:4)

我认为,通常的技术涉及call by namecall by need。我们的想法是or的参数不是比较的结果,而是将比较本身转换为thunk,每当(通过名称调用)转换为结果值或者第一次(需要时)需要它。

将表达式转换为thunk时,基本上是创建一个匿名函数,并且可以像这样处理编译问题。它涉及将表达式编译为将评估表达式的代码。它还涉及创建一个对象(thunk本身),该对象引用(或包含)表达式使用的局部变量的副本,以及指向表达式的已编译代码的指针。该对象需要与您的布尔类接口兼容,以便使用它的代码不必关心它是否具有真正的布尔值或thunk如此。每当有人需要布尔值时,thunk将执行编译的表达式代码并提供结果值。

如果按姓名打电话对你来说已经足够了,那就是它的全部内容。对于按需调用,缓存评估结果会增加复杂性。

答案 1 :(得分:1)

IIRC ALGOL使用按名称调用的参数,这就是该解决方案有效的原因。

||运算符可以实现为(伪代码):

if (cond1) goto label;
if (cond2) goto label;

label:
  <body>

nomatch:
  ...

对于&&,可以完成上述反转。

答案 2 :(得分:1)

  重新:根据维基百科“ALGOL68使用”程序“实现用户   定义的短路运营商&amp;程序。“ - 这是如何工作的?

Algol68-r0(原始/未经修订的定义)有两个与短路评估相关的概念。

想象一下编码器想要定义一个执行“短路评估”的矩阵乘法运算符,所以一旦左参数为“零”矩阵,那么就会对右侧进行进一步的评估......这样用户定义的定义可以是:

MODE MAT = FLEX[0,0]REAL;
OP ISZERO = (MAT a)BOOL: ¢ insert actual code here ¢ ~;

PRIO TIMESF = 7;
OP TIMESF = (MAT a, PROC MAT in b)MAT: 
  IF ISZERO a THEN a ELSE MAT b = in b; ¢ insert actual code here ¢ ~ FI;

MAT a = 0, b = 16, c = 25;
print(a TIMESF b TIMESF c) ¢ would print 0 without calculating 16*25 ¢

相反,编码人员希望并行评估左手和右手参数。这样的用户定义定义可以是:

PRIO TIMESPAR = 7;
OP TIMESPAR = (MAT a, MAT b)MAT: ¢ insert actual code here ¢ ~;

逗号告诉编译器可以任意顺序,甚至并行地评估左手和右手。 (这使编译器可以选择优化评估)

或者编码员可能想强制评估是连续的:

PRIO TIMESSEQ = 7;
OP TIMESSEQ = (MAT a; MAT b)MAT: ¢ insert actual code here ¢ ~;

在这种情况下,“;”被称为“gomma”,用于“逗留逗号”。

Algol68-r1(1974年修订,在sourceforge上为windows和linux提供)删除了所有这些功能,让编码人员手动/专门应用“程序”......例如

第一组矩阵定义是相同的:

MODE MAT = FLEX[0,0]REAL;
PRIO TIMESF = 7;
OP TIMESF = (MAT a, PROC MAT in b)MAT: 
  IF ISZERO a THEN a ELSE MAT b = in b; ¢ insert actual code here ¢ ~ FI;

MAT a = 0, b = 16, c = 25; ¢ 3 1x1 matrices are "widening" from REAL numbers ¢ 

但用法不同,注意使用两个lambdas(MAT:b TIMES MAT:c)和(MAT:c):

print(a TIMESF MAT:b TIMESF MAT:c) ¢ would print 0 without calculating 16*25 ¢

Algol68-r1中保留了透明的去毛刺和扩宽。