C嵌套开关:外部开关';s外壳内部开关
我正在为我正在编写的解释器添加协同程序支持,我想做如下事情:C嵌套开关:外部开关';s外壳内部开关,c,language-design,interpreter,coroutine,C,Language Design,Interpreter,Coroutine,我正在为我正在编写的解释器添加协同程序支持,我想做如下事情: typedef enum { bar_stuff, bar_other } Bar; typedef enum { foo_error=-1, foo_none=0, foo_again } Foo_state; Foo_state do_foo(Bar bar,Foo_state foo) { switch(foo) { ca
typedef enum {
bar_stuff,
bar_other
} Bar;
typedef enum {
foo_error=-1,
foo_none=0,
foo_again
} Foo_state;
Foo_state do_foo(Bar bar,Foo_state foo)
{
switch(foo)
{
case foo_none: //start
switch(bar)
{
case bar_stuff:
//do stuff
return foo_none;
case bar_other:
//do other stuff
return foo_again;
case foo_again: //!! this doesn't work
/* edit: this is supposed to be a case of
* switch(foo), not switch(bar)
*/
//do more other stuff
return foo_none;
default:
//stuff
return foo_none;
}
default:
//fail
return foo_error;
}
}
显然,这不起作用(我得到了重复的case值,备选方案可能是未定义的行为/segfault)。我可以将switch(bar)写为if/else if/else链,但我希望有更好的方法
如果有区别的话,我会使用gcc
编辑:
以下各项可行,但需要保持:
Foo_state do_foo2(Bar bar,Foo_state foo)
{
switch(foo)
{
case foo_none: goto case_foo_none;
case foo_again: goto case_foo_again;
default:
//fail
return foo_error;
}
case_foo_none: //start
switch(bar)
{
case bar_stuff:
//do stuff
return foo_none;
case bar_other:
//do other stuff
return foo_again;
case_foo_again:
//do more other stuff
return foo_none;
default:
//stuff
return foo_none;
}
}
编辑2:
好吧,这似乎并没有产生上述“更好的方式”,所以我想知道是否有人预见到这样写的问题:
Foo_state do_foo3(Bar bar,Foo_state foo)
{
switch(foo)
{
case foo_none: //start
if(bar == bar_stuff)
{
printf("do stuff\n");
return foo_none;
}
else if(bar == bar_other)
{
printf("do other stuff\n");
return foo_again;
case foo_again: //continue
printf("do more other stuff\n");
return foo_none;
}
else
{
printf("stuff\n");
return foo_none;
}
default:
//fail
return foo_error;
}
}
我看到的问题是缺少一个bar_*值(因为有几个这样的函数,一些枚举有几十个值),但我认为一个测试脚本应该可以工作…Hm。。。使用卡诺图的等价物简化逻辑,并使用
if (cond1 && cond2) {
doX();
return;
}
if (cond3 && cond4) {
doY();
return;
}
// Sometimes you can take shortcuts
if (cond5) {
doZ();
} else {
doW();
}
return;
这段代码是可读的。如果可能,最好避免嵌套的东西
首先检查最简单的条件将使函数更简单
在您的情况下,请从以下内容开始:
Foo_state do_foo2(Bar bar,Foo_state foo) {
if (foo != foo_none && foo != foo_again) {
return foo_error;
}
...
if (foo == foo_none) {
...
}
// Implicit Else
...
嗯。。。使用卡诺图的等价物简化逻辑,并使用
if (cond1 && cond2) {
doX();
return;
}
if (cond3 && cond4) {
doY();
return;
}
// Sometimes you can take shortcuts
if (cond5) {
doZ();
} else {
doW();
}
return;
这段代码是可读的。如果可能,最好避免嵌套的东西
首先检查最简单的条件将使函数更简单
在您的情况下,请从以下内容开始:
Foo_state do_foo2(Bar bar,Foo_state foo) {
if (foo != foo_none && foo != foo_again) {
return foo_error;
}
...
if (foo == foo_none) {
...
}
// Implicit Else
...
一个简单的修复方法是更改bar_uuu枚举中的值,使它们相对于foo_uuu枚举是唯一的。但是,这并不能解决您的代码令人困惑的问题。为什么要在bar_uu开关语句中查找foo_u值?从语法上讲,它是有效的(只要值是唯一的),但它的编码很差。一个简单的修复方法是更改条形枚举中的值,使它们相对于foo枚举是唯一的。但是,这并不能解决您的代码令人困惑的问题。为什么要在bar_uu开关语句中查找foo_u值?从语法上讲,它是有效的(只要值是唯一的),但它的编码很差。您也可以将{}放在每个大小写中:statement
如果没有它们,整个案例堆栈将作为单个单元进行评估,因此无法在一个案例中定义任何变量: 但是
case blah:
{
// do stuff
}
break;
您可以在case语句中放入任何内容。您也可以在每个case语句中放入{}:statement
如果没有它们,整个案例堆栈将作为单个单元进行评估,因此无法在一个案例中定义任何变量: 但是
case blah:
{
// do stuff
}
break;
您可以在case语句中放入任何内容。好的,您的代码似乎可以这样做:
bar \ foo foo_none foo_again other
bar_stuff doStuff, return foo_none do more other stuff, return foo_none return foo_error
bar_other do other stuff, return foo_again do more other stuff, return foo_none return foo_error
other stuff, return foo_none do more other stuff, return foo_none return foo_error
这就是我所说的卡诺图。下面是最简单的实现:
Foo_state do_foo2(Bar bar,Foo_state foo) {
if (foo == foo_again) {
// do more stuff
return foo_none;
}
if (foo != foo_none) { // other
return foo_error;
}
// foo_none
if (bar == bar_stuff) {
// do stuff
return foo_none;
}
if (bar == bar_other) {
// do other stuff
return foo_again;
}
// At this point bar = other
// stuff
return foo_none;
}
我相信这和你的代码是一样的,但是不使用开关和GOTO。您可以用结果填写一个表格,还可以对两个实现进行单元测试,以确保它们对所有输入都执行相同的操作。好的,您的代码似乎执行以下操作:
bar \ foo foo_none foo_again other
bar_stuff doStuff, return foo_none do more other stuff, return foo_none return foo_error
bar_other do other stuff, return foo_again do more other stuff, return foo_none return foo_error
other stuff, return foo_none do more other stuff, return foo_none return foo_error
这就是我所说的卡诺图。下面是最简单的实现:
Foo_state do_foo2(Bar bar,Foo_state foo) {
if (foo == foo_again) {
// do more stuff
return foo_none;
}
if (foo != foo_none) { // other
return foo_error;
}
// foo_none
if (bar == bar_stuff) {
// do stuff
return foo_none;
}
if (bar == bar_other) {
// do other stuff
return foo_again;
}
// At this point bar = other
// stuff
return foo_none;
}
我相信这和你的代码是一样的,但是不使用开关和GOTO。您可以用结果填写一个表格,还可以对两个实现进行单元测试,以确保它们对所有输入都执行相同的操作。如果
(foo==foo\u再次)
我希望在返回foo\u之后恢复该操作
@lpthnc:我同意你的方法…听起来像是使用嵌套的switch语句将有限状态机编码在一起…但是你的方法更干净、更简单!如果(foo==foo\u再次)
我希望它在再次返回foo\u之后继续运行,那么这就不一样了
@lpthnc:我同意你的方法…听起来像是使用嵌套的switch语句将有限状态机编码在一起…但是你的方法更干净、更简单!当你说你想要“像下面这样的东西”,然后发布无效代码时,我们认为你真正想要的是什么?如果代码是有效的,它会做什么?是的,PITA是正确的。。。为什么不在纸上画出一个状态机,在纸上简化它,然后给出变量的专有名称,至少在某种程度上可以自我记录这个过程?您正在用这些变量表示一个状态。为什么不使用一个变量来表示状态呢?我发布了一个引用,说明了我的意思。(但我希望找到一种不那么难看的方法。)认真地说,在Excel中绘制一个3 x 3的表格,列出要执行的内容和要返回的值。将这些条件组合在一起。你可以用if(foo_-reach&&bar_-other){…}走另一条捷径,这应该给你留下一条switch语句。可能有用:(虽然其中一些是C++特有的,但switch hack在C中是相同的,它显示了如何从单个逻辑中排除“co调用”)然后发布无效代码,我们认为你真正想要什么?如果代码是有效的,它会做什么?是的,PITA是正确的。。。为什么不在纸上画出一个状态机,在纸上简化它,然后给出变量的专有名称,至少在某种程度上可以自我记录这个过程?您正在用这些变量表示一个状态。为什么不使用一个变量来表示状态呢?我发布了一个引用,说明了我的意思。(但我希望找到一种不那么难看的方法。)认真地说,在Excel中绘制一个3 x 3的表格,列出要执行的内容和要返回的值。将这些条件组合在一起。您可以使用if(foo_reach&&bar_other){…}使用另一个快捷方式,这应该会给您留下一个switch语句。可能有用:(虽然其中一些是特定于C++的,但switch hack在C中是相同的,它显示了如何从单个逻辑中排除“co调用”)