将duff的设备从C移植到JavaScript

时间:2016-05-03 22:44:53

标签: javascript loop-unrolling duffs-device

我在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));

nodejs返回此错误:

        do {
        ^^
SyntaxError: Unexpected token do

我的问题是:javascript是否支持计算GOTO语句?

P.D:我不想要替代方案,我只是想知道为什么不起作用。

相关问题:Does Duff's Device work in other languages?

2 个答案:

答案 0 :(得分:3)

  

我的问题是:javascript是否支持计算GOTO语句?

真的

  

P.D:我不想要替代方案,我只是想知道为什么不起作用。

它无效,因为在JavaScript中switch statements must only contain case blocks

虽然可能没有找到解决方法,其他人可能会在寻找一个问题时找到这个问题,所以无论如何我都会提供一个。
这个信用额归mnieper asm.jsthe ticket posted on the asm.js repo提出。

基本思路是在顶层设置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语句从这是第一个案例。

因此,在您的情况下,这意味着要交换switchdo...while()并添加default案例和控制变量:

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中的任何地方。
只要它在单个连续的上下文中使用,它应该可以工作。

有关详细信息,请参阅AgendaCalendarView

答案 1 :(得分:1)

JavaScript switch语句不能像那样工作。

switch (expr) {
  case expr:
    statements;
    break;
  case expr:
    statements;
    break;
  default:
    statements;
    break;
}

但JavaScript确实提供labels来控制你的循环

  

来自MDN的示例

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;
    }