从C语言移植duff的设备到JavaScript

5

我有一种在C语言中实现的Duff装置,它可以很好地工作(将文本格式化为货币):

#include <stdio.h>
#include <string.h>

char *money(const char *src, char *dst)
{
    const char *p = src;
    char *q = dst;
    size_t len;

    len = strlen(src);
    switch (len % 3) {
        do {
            *q++ = ',';
            case 0: *q++ = *p++;
            case 2: *q++ = *p++;
            case 1: *q++ = *p++;
        } while (*p);
    }
    *q++ = 0;
    return dst;
}

int main(void)
{
    char str[] = "1234567890123";
    char res[32];

    printf("%s\n", money(str, res));
    return 0;
}

输出:

1,234,567,890,123

但是我在尝试用Javascript实现时遇到了问题:

function money(src, dst) {
    var len = src.length;
    var i = 0;

    switch (len % 3) {
        do {
            dst += ',';
            case 0: dst += src[i++];
            case 2: dst += src[i++];
            case 1: dst += src[i++];
        } while (src[i]);
    }
    return dst;
}

var str = "1234567890123";
var res = "";

console.log(money(str, res));

Node.js返回以下错误:

        do {
        ^^
SyntaxError: Unexpected token do

我的问题是:JavaScript是否支持计算GOTO语句?
P.D: 我不想要替代方案,我只想知道为什么它不起作用。
相关问题:Duff's Device在其他语言中是否可行?
2个回答

8
我的问题是:javascript 是否支持计算GOTO语句? 不太支持。 P.D: 我不想要一个替代方法,我只想知道为什么它不起作用。 它不起作用是因为在JavaScript中,switch 语句必须只包含 case。 虽然你可能不在寻找解决方法,但是其他人可能会在搜索中找到这个问题,所以我将提供一个解决方法。
credit for this one goes to mnieper who suggested it at asm.js。 基本思路是在顶层有一个while(true)循环,并在其中放置一个switch语句。
goto:
while(true)
{
    switch(where)
    {
        // no breaks
        case 0:
            // some code...
        case 1:
            // some other code...
        // ...
    }
}

为了模拟goto,可以使用
where = 1;
continue goto;

为了模拟Duff的设备,只需要将循环作为外部结构,并在switch语句中使用一个变量,该变量在第一次迭代后设置为触发switch语句从其第一个case开始的值。
所以在您的情况下,这意味着交换switch和do...while(),并添加一个default case和一个控制变量:
var where = len % 3;
do {
    switch (where) {
        default: dst += ',';
        case 0:  dst += src[i++];
        case 2:  dst += src[i++];
        case 1:  dst += src[i++];
    }
    where = -1;
} while (src[i]);

这种方法的一个巨大缺点是它不能跨回调函数使用,而回调函数在JavaScript中几乎无处不在。
只要它在单个顺序上下文中使用,它应该可以工作。
有关详细信息,请参见发布在asm.js存储库上的票证

1
对不起,我不理解:“它不会在回调之间工作”,这是什么意思? - David Ranieri
1
基本上它不能跨函数工作。在JavaScript中,传递函数对象以作为对未来值或事件的反应是很常见的,例如等待100毫秒:window.setTimeout(function(){ /* */ }, 100);。如果这样的函数在循环内部声明,它可能会给人留下在循环内部运行(因此能够使用breakcontinue等)的印象,但如果异步执行,则不是这种情况。只需搜索“javascript return not working”,你就会找到大量新手问题,询问这个问题,只是换成了返回值而已。 - Siguza

2
JavaScript的`switch`语句不是这样工作的。
switch (expr) {
  case expr:
    statements;
    break;
  case expr:
    statements;
    break;
  default:
    statements;
    break;
}

但是JavaScript确实提供了标签来控制您的循环。

来自MDN的示例

(注:link1指向一个链接或标签,需要根据上下文具体翻译)
var itemsPassed = 0;
var i, j;

top:
for (i = 0; i < items.length; i++){
  for (j = 0; j < tests.length; j++) {
    if (!tests[j].pass(items[i])) {
      continue top;
    }
  }

  itemsPassed++;
}

来自 MDN 的另一个例子。
var allPass = true;
var i, j;

top:
for (i = 0; items.length; i++)
  for (j = 0; j < tests.length; i++)
    if (!tests[j].pass(items[i])){
      allPass = false;
      break top;
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接