我如何在 C 中将 goto 与 switch 一起使用? (密克罗尼西亚联邦)

How do I use goto with swtich in C? (FSM)

假设我有这个代码


switch(x)
{

region_1:

  case a:
      ...
  case b:
      goto region_1:

region_2:
      
  case c:
      ...
  case d:
      goto region_2

  default:
      ...

}

在C中有没有可能有这样一个类似递归的算法?无论如何,我可以从哪里跳转到标签并再次检查案例?我要给我爷爷做一个FSM,他打算用它来钓鱼。

您可以执行以下操作

switch ( x )
{
case 1:
    L1: switch( y )
    {
    case a:
        //...
    case b:
        //... 
        goto L1;
    }

case 2:
    L2: switch( y )
    {
    case c:
        //...
    case d:
        //...
        goro L2;
    }

default:
    //...
}

为什么要使用开关。

例如,假设您想编写一个自动机来检查输入是否匹配模式 ab+c+

自动机:

  • S0:
    • a → S1
  • S1
    • b → S1
    • c → S2
  • S2
    • c → S2
    • EOF → 接受

这可以通过开关来完成,但也可以使用 goto:

来实现
S0: {
    int c = getch();
    if (c == 'a') goto S1;
    goto ERROR;
}

S1: {
    int c = getch();
    if (c == 'b') goto S1;
    if (c == 'c') goto S2;
    goto ERROR;
}

S3: {
    int c = getch();
    if (c == 'c') goto S2;
    if (c == EOF) goto ACCEPT;
    goto ERROR;
}

ACCEPT: exit(0);
ERROR:  exit(1);

不过你也可以这样写:

while (1) {
   int next_state;

   switch (state) {
      case ERROR:  exit(1);
      case ACCEPT: exit(0);

      case S0: {
         int c = getch();
         if      (c == 'a') { next_state = S1;    }
         else               { next_state = ERROR; }
         break;
      }

      case S1: {
         int c = getch();
         if      (c == 'b') { next_state = S1;    }
         else if (c == 'c') { next_state = S2;    }
         else               { next_state = ERROR; }
         break;
      }

      case S2: {
         int c = getch();
         if      (c == 'c') { next_state = S2;    }
         else               { next_state = ERROR; }
         break;
      }
   }

   state = next_state;
}

但这确实是使用 tables 的垫脚石。

#define TOK_OTHER 0
#define TOK_EOF   1
#define TOK_A     2
#define TOK_B     3
#define TOK_C     4

static int char_to_token_map[] = {
   /*          0  1  2  3   4  5  6  7   8  9  A  B   C  D  E  F */
   /* 0x00 */  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
   /* 0x10 */  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
   /* 0x20 */  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
   /* 0x30 */  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
   /* 0x40 */  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
   /* 0x50 */  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
   /* 0x60 */  0, 2, 3, 4,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
   /* 0x70 */  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0   
};

static int to_token(int c) {
   if (c >= 128) return 0;
   if (c == EOF) return 1;
   return char_to_token_map[c];
}

#define ERROR  -2
#define ACCEPT -1
#define S0      0
#define S1      1
#define S2      2

static int automata[3][5] {
   /* state   OTHER   EOF     a       b       c       */
   /* -----   ------- ------- ------- ------- ------- */
   /* S0 */ { ERROR   ERROR   S1,     ERROR,  ERROR   },
   /* S1 */ { ERROR,  ERROR,  ERROR,  S1,     S2,     },
   /* S2 */ { ERROR,  ACCEPT, ERROR,  ERROR,  S2,     }
};

int state = S0;
while (1) {
   int new_state;

   switch (state) {
      case ERROR:  exit(1);
      case ACCEPT: exit(0);
      default:     new_state = automata[ state ][ to_token(getch()) ];
   }

   state = new_state;
}

如果您需要在切换状态之前执行任何操作,只需在该状态的切换中添加一个特例即可。或者使用 table 由状态索引的函数指针。