将翻译成Lua时实现后置/前置递增/递减

我正在编写一个将LSL翻译成Lua的程序,但在实现递增和递减运算符时遇到了各种各样的问题。 LSL使用通常的类C语法(x ++,x-,++ x, - x)实现这些功能,但Lua不包含这些运算符。为避免大量的打字,我称这些运算符为“crements”。在下面的代码中,我将使用“...”来代表表达式的其他部分。

... x += 1 ...

不起作用,因为Lua只有简单的赋值。

... x = x + 1 ...

不起作用,因为这是一个语句,而Lua不支持在表达式中使用语句。LSL可以在表达式中使用crements。

function preIncrement(x)  x = x + 1;  return x;  end
... preIncrement(x) ...

虽然它在表达式中提供了正确的值,但是Lua对于数字是传值的,因此原来的变量不会改变。如果我可以使它实际上改变变量,那么就都好了。更改环境可能不是一个好主意,我不知道x的范围是什么。我想我会接下来调查一下这个。翻译器可以输出范围细节。

假设上述函数存在-

... x = preIncrement(x) ...

由于它是一个语句,所以不适用。

其他解决方案开始变得非常混乱。

x = preIncrement(x)
... x ...

很好用,除非原始的LSL代码是这样的-

while (doOneThing(x++))
{
  doOtherThing(x);
}

这会变成一大堆问题。在函数中使用表 -

function preIncrement(x)  x[1] = x[1] + 1;  return x[1];  end
temp = {x}
... preincrement(temp) ...
x = temp[1]

变得更加混乱,而且有相同的问题。

看起来我可能不得不分析周围的代码,而不仅仅是进行简单的翻译,以找出实现任何给定crement的正确方法。有没有简单的想法?

原文链接 https://stackoverflow.com/questions/9124751

点赞
stackoverflow用户734069
stackoverflow用户734069

Lua的设计基本上可以抵御这种实现。这可能是一个编译器/解释器问题,因为解释器可以知道变量仅在执行语句时才会改变。

在Lua中没有办法实现这种东西。在一般情况下不行。你可以通过将字符串传递给增量函数来为全局变量执行此操作。但显然它不能用于局部变量,或者在其自身是全局变量的表中的变量。

Lua不希望你这样做;最好在限制内找到工作方式。这意味着代码分析。

2012-02-03 06:53:20
stackoverflow用户312586
stackoverflow用户312586

你提出的解决方案只能在你的 Lua 变量全部都是全局变量的情况下才能够生效。除非 LSL 也采用了这种方法,否则将会遇到在不同位置使用同名变量的 LSL 程序转换为 Lua 程序时出现的问题。

Lua 只能修改一个 lvalue。传递给函数的表是这个规则的唯一例外。你可以使用一个本地化的表来存储所有的局部变量,在预增量和后增量方面可以有所帮助;它们可以在包含它们的表达式被求值之前求值。但是后增量需要在之后进行求值,这在 Lua 中是不可能的,至少不是不需要涉及到使用匿名函数的丑陋代码。

因此你只有一种选择:你必须接受某些 LSL 语句会转换成多个 Lua 语句的事实。

假设你有一个具有增量的 LSL 语句,就像这样:

f(integer x) {
  integer y = x + x++;
  return (y + ++y)
}

你可以将其转换为一个 Lua 语句,就像这样:

function f(x) {
  local post_incremented_x = x + 1 -- 步骤 1,为后增量语句多写一个语句
  local y = x + post_incremented_x
  x = post_incremented_x -- 步骤 2,为后增量语句多写一个语句

  local pre_incremented_y = y + 1
  return y + pre_incremented_y
  y = pre_incremented_y -- 这一行永远不会被执行
}

因此,基本上你将需要为每个增量和减量语句添加两个表述。对于复杂结构,这意味着需要计算表达式求值的顺序。

就我个人而言,我喜欢在语言中单独使用后减量和先减量的语句。但是当它们也可以用作表达式时,我认为这是语言的缺陷。它的语法糖很快就会成为语义上的糖尿病。

2012-02-03 09:05:08
stackoverflow用户284969
stackoverflow用户284969

我认为要真正正确地完成这个任务,你需要进行更详细的分析,并将一些表达式拆分为多个语句,尽管许多表达式可能可以直接翻译。

请注意,至少在 C 语言中,可以延迟后增量/减量到下一个“序列点”,并将前增量/减量放在前一个序列点之前;序列点只出现在几个地方:在语句之间,在“短路运算符”(&&||)中等等。(点击这里了解更多信息)

因此,将 x = *y++ + z * f(); 替换为 { x = *y + z * f(); y = y + 1; } 是可以的,因为用户不能假设 y 将在语句中的任何其他内容之前被增加,只有在增加之前使用的值 *y 将是增加前的 y。同样,可以使用 { y = y - 1; x = *y + z * f (); } 替换 x = *--y + z * f()

2012-02-03 13:53:09
stackoverflow用户1137552
stackoverflow用户1137552

经过一番研究和思考,我想到了一个可能可行的方法。

对于全局变量 –

function preIncrement(x)
  _G[x] = _G[x] + 1
  return _G[x]
end
... preIncrement("x") ...

对于局部变量和函数参数(也是局部变量),在解析 crement 时我知道它是局部变量,我可以存储四个标志来告诉我正在使用哪些四个 crement 变量的 AST 结构。然后,当定义变量的时候,我可以输出像这样的内容 –

local x;
function preIncrement_x() x = x + 1;  return x;  end
function postDecrement_x() local y = x;  x = x - 1;  return y;  end
... preIncrement_x() ...
2012-02-03 23:23:36
stackoverflow用户2070958
stackoverflow用户2070958

大多数时候你在对代码的配置性进行评估。你会尝试将一种数据类型从一个传递到另一个中去,并称其为“翻译器”。而在这一过程中,你错过了正则表达式和其他模式匹配能力。这些能力在 LUA 中比 LSL 更丰富。而且由于 LSL 代码被传递到 LUA 中去了,尝试使用它们以及其他函数。这将更好地定义工作,并将其视为翻译器,而不是一个硬编码。

是的,我知道这是一段时间前就提出的问题了。但是,对于这个主题的其他观众来说,永远不要忘记你所在的环境。使用它们所提供的能力,最大化你的能力。

2013-08-11 17:04:33