4

我正在编写一个 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的正确方法是什么。有人有任何简单的想法吗?

4

5 回答 5

1

我认为要真正正确地做到这一点,您将不得不进行一些更详细的分析,并将一些表达式拆分为多个语句,尽管许多语句可能可以非常直接地翻译。

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

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

于 2012-02-03T13:53:09.950 回答
0

Lua 被设计成几乎不受这类事情的实现的影响。它可以作为一种编译器/解释器问题来完成,因为解释器可以知道变量仅在执行语句时才会改变。

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

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

于 2012-02-03T06:53:20.003 回答
0

只有当您的 Lua 变量都是全局变量时,您提出的解决方案才有效。除非 LSL 也这样做,否则在翻译使用在不同地方以相同方式调用的变量的 LSL 程序时会遇到麻烦。

Lua 只能修改每个语句的一个左值 - 传递给函数的表是该规则的唯一例外。您可以使用本地表来存储所有本地人,这将帮助您处理 pre-...-crements;可以在评估它们所包含的表达式之前评估它们。但是 post-...-crements 必须在以后进行评估,这在 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
}

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

值得一提的是,我喜欢将后减量和预减量作为语言中的单独语句。但是当它们也可以用作表达式时,我认为这是语言的缺陷。句法糖很快就变成了语义糖尿病。

于 2012-02-03T09:05:08.487 回答
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() ...
于 2012-02-03T23:23:36.113 回答
0

在您评估代码的可配置性的大部分情况下。您正在尝试将数据类型从一种硬传递到另一种。并称其为“翻译器”。在所有这些中,您会错过正则表达式和其他模式匹配功能。LUA 中比 LSL 更多。并且由于 LSL 代码被传递到 LUA 中。尝试使用它们以及其他功能。这会将工作更多地定义为翻译,而不是硬通行证。

是的,我知道这是不久前被问到的。不过,对于这个主题的其他观众。永远不要忘记您工作的环境。永远。使用他们给你的最好的能力。

于 2013-08-11T17:04:33.433 回答