在转换为Lua时实现post / pre递增/递减

时间:2012-02-03 06:47:42

标签: lua pass-by-reference lua-scripting-library

我正在写一个LSL到Lua翻译器,我在实现递增和递减运算符时遇到了各种各样的麻烦。 LSL使用通常的C语法(x ++,x - ,++ x, - x)进行此类操作,但Lua没有。为了避免大量打字,我将这些类型的运算符称为“创造”。在下面的代码中,我将使用“...”来表示表达式的其他部分。

... x += 1 ...

不工作,因为Lua只有简单的任务。

... x = x + 1 ...

不会工作因为这是一个声明,Lua不能在表达式中使用语句。 LSL可以在表达式中使用创意。

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]

甚至更加混乱,也有同样的问题。

开始看起来我可能必须实际分析周围的代码而不是仅仅进行简单的翻译来理清实现任何给定的创建的正确方法。有人有任何简单的想法吗?

5 个答案:

答案 0 :(得分:1)

我认为要真正做到这一点你必须做一些更详细的分析,并将一些表达式分成多个语句,尽管很多可能很容易翻译。

请注意,至少在C中,您可以将后递增/递减延迟到下一个“序列点”,并在前一个序列点之前放置的预递增/递减;序列点仅位于几个地方:语句之间,“短路操作员”(&&||)等。(more info here)

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

答案 1 :(得分:0)

Lua的设计非常不受此类事物的影响。它可以作为一种编译器/解释器问题来完成,因为解释器可以知道变量只在执行语句时才会改变。

在Lua中没有办法实现这种事情。不是一般情况。您可以通过将字符串传递给increment函数来为全局变量执行此操作。但显然它不适用于本地人,也不适用于本身就是全局的表中的变量。

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

答案 2 :(得分:0)

只有当您的Lua变量全局变量时,您提出的解决方案才有效。除非LSL也这样做,否则你将无法翻译在不同地方使用相同方式变量的LSL程序。

Lua只能修改每个语句的一个左值 - 传递给函数的表是此规则的唯一例外。您可以使用本地表来存储所有本地人,这将有助于您使用pre -...-创建;它们可以在包含它们的表达式被评估之前进行评估。但是后期必须对后期的评估进行评估,这在lua中根本不可能 - 至少没有一些涉及匿名函数的丑陋代码。

所以你有一个选择:你必须接受一些LSL语句将被翻译成几个Lua语句。

假设您有一个LSL语句,其增量如下:

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

您可以将此翻译为Lua语句,如下所示:

function f(x) {
  local post_incremented_x = x + 1 -- extra statement 1 for post increment
  local y = x + post_incremented_x
  x = post_incremented_x -- extra statement 2 for post increment

  local pre_incremented_y = y + 1
  return y + pre_incremented_y
  y = pre_incremented_y -- this line will never be executed
}

因此,您基本上必须在语句中使用每个..添加两个语句。对于复杂结构,这意味着计算表达式的计算顺序。

对于有价值的东西,我喜欢将后减法和预定义作为语言中的单个语句。但是当我们也可以将它们用作表达式时,我认为它是语言的一个缺陷。语法糖迅速成为语义糖尿病。

答案 3 :(得分:0)

经过一番研究和思考后,我想出了一个可行的想法。

对于全局 -

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

对于本地人和函数参数(本地人来说)我知道当我正在解析它是本地的创建时,我可以存储四个标志来告诉我变量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() ...

答案 4 :(得分:0)

在大多数对代码可配置性的评估中。您正在尝试将数据类型从一个硬件传递到另一个。称之为“翻译者”。在所有这些中,你会错过正则表达式和其他模式匹配能力。在LUA中存在的比LSL更多。因为LSL代码正在传递给LUA。尝试使用它们以及其他功能。这将把工作更多地定义为翻译,而不是硬传递。

是的,我知道这是前一段时间被问过的。虽然,对于这个话题的其他观众。永远不要忘记您正在工作的环境。永远。使用他们为您提供的最佳能力。