我最近使用C,Bison,Flex和this post作为起点制作了一种玩具编程语言。它看起来很像Python,除了没有冒号或空格规则。
代码是here,但它不如我坚持的概念/算法重要。
我设计了我的抽象语法树,就像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
答案 0 :(得分:0)
一些流行的基于堆栈的语言将值压入堆栈,然后由调用函数弹出。这可能对你有用。
当然,这依赖于具有已知返回类型的函数。如果函数是' void'那么Python返回PyNone。 (即什么都不返回)。 Python函数只返回一个值(可以是None,或者是对象或元组或其他)。
C类型语言也只返回函数中的一个值。
我认为重点是,在强类型语言中,您总是有一个返回值,您必须始终返回一个。在弱类型语言中,您可能或者可能返回一个值,但您仍然有一个。
答案 1 :(得分:0)
这个问题的答案很大程度上取决于代码如何运作的内部。
当我编写Mote Compiler(类似VB的编译器)时,我在函数启动时调用了MoteEngine.prototype.runFuncStart
。我创建了一个新对象来保存所有局部变量,然后将其推送到我的堆栈中。
MoteEngine.prototype.runFuncEnd
清理了堆栈。
答案 2 :(得分:0)
嗯,这很大程度上取决于你如何实现你的执行引擎。如果您遵循Rudi的建议,即使用递归调用彼此遍历AST的函数来实现执行引擎,那么要实现break
或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转换为更像线性的字节码或线程代码。