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调用”)