4

我最近使用 C、Bison、Flex 和这篇文章作为起点制作了一种玩具编程语言。它看起来很像 Python,只是没有冒号或空格规则。

代码在这里,但它不如我坚持的概念/算法重要。

我设计了我的抽象语法树,就像Rudi在上面链接的帖子中所做的那样。

诀窍是,我想不出从用户定义函数返回或跳出循环的好方法。return如果我在用户定义函数的末尾只需要一个语句,它是可行的(实际上这是当前对用户定义函数有效的)。

例子:

i = 0
while 1 do
  if i > 15 then
     break
  end
done

示例 2:

def mean(somelist)
  if len(list) == 0 then
    return 0  # throw error
  else
    return sum(somelist) / len(somelist)
  end
end
4

3 回答 3

0

一些流行的基于堆栈的语言将一个值压入堆栈,然后由调用函数弹出。这可能对你有用。

当然,这依赖于具有已知返回类型的函数。如果函数为“void”(即不返回任何内容),Python 将返回 PyNone。Python 函数只返回一个值(可以是 None,也可以是对象或元组或其他任何值)。

C 类型语言也只从函数返回一个值。

我认为重点在于,在强类型语言中,你总是有一个返回值,而且你必须总是返回一个。在您可能或可能返回值的弱类型语言中,您仍然有一个值。

于 2012-09-21T15:46:25.550 回答
0

这个问题的答案很大程度上取决于您的代码如何工作的内部结构。

当我编写我的Mote 编译器(一个类似 VB 的编译器)时,我MoteEngine.prototype.runFuncStart在一个函数启动时调用了 。我创建了一个新对象来保存所有局部变量,然后将其推送到我的堆栈中。

MoteEngine.prototype.runFuncEnd清理堆栈。

于 2012-09-21T15:51:49.220 回答
0

好吧,这在很大程度上取决于您如何实现执行引擎。如果你按照 Rudi 的建议,用递归调用对方遍历 AST 的函数来实现执行引擎,那么要实现一个breakor return,你需要通过几级 C 调用堆栈返回。您可以使用 setjmp/longjmp 执行此操作。例如,您的代码可能类似于:

struct ExecEnviron {
    /* other contents of ExecEnviron, we're just adding a bit */
    jmp_buf *break_context;  /* where a 'break' or 'continue' should jump to */
    jmp_buf *return_context; /* where a 'return' should jump to */
};

void ExecWhile(ExecEnviron *e, AstElement *a) {
    jmp_buf local, *old = e->break_context;
    e->break_context = &local;

    if (setjmp(&local) != 1)
        while (dispatchExpression(a->whileStmt.cond))
            dispatchStatement(a->whileStmt.body);
    e->break_context = old;
}
void ExecBreak((ExecEnviron *e, AstElement *a) {
    longjmp(e->break_context, 1);
}
void ExecContinue((ExecEnviron *e, AstElement *a) {
    longjmp(e->break_context, 2);
}

Setjmp/longjmp 可以很好地打破嵌套上下文,但不适用于一般的标签/goto 处理(因为它们允许跳转到循环的中间)。如果你想处理这个问题,你将不得不使用一个完全不同的执行引擎,并将 AST 转换成更线性的东西,比如字节码或线程代码。

于 2012-09-21T18:27:05.367 回答