用ebnf文法描述c

Describing c with ebnf grammar

这是EBNF中描述C:

的文法
stmt->  (CASE CONST ‘:’)* expression ‘;’
      | (CASE CONST ‘:’)* IF ‘(’ expression ‘)’ stmt [ELSE stmt]
      | (CASE CONST ‘:’)* WHILE ‘(’ expression ‘)’ stmt
      | (CASE CONST ‘:’)* SWITCH ‘(’ expression ‘)’ stmt
      | (CASE CONST ‘:’)* RETURN [expression] ‘;’
      | (CASE CONST ‘:’)* BREAK ‘;’
      | (CASE CONST ‘:’)* CONTINUE ‘;’
      | ‘{’ (stmt)* ‘}’

我想修改上面的限制条件:

  1. CASE 标签只能用于直接包含在命令 SWITCH 中的命令,而不能用于其嵌套的 IF 或 WHILE 命令中。
  2. BREAK 命令只能出现在 WHILE 命令或一个 SWITCH 命令,包括这些嵌套命令。
  3. CONTINUE 命令只能出现在 WHILE 命令中, 包括嵌套命令。

我的回答:

stmt-> ( CONST ‘:’)* expression ‘;’
     | ( CONST ‘:’)* IF ‘(’ expression ‘)’ stmt [ELSE stmt]
     | (CASE CONST ‘:’)* SWITCH ‘(’ expression ‘)’ stmt
     | ( CONST ‘:’)* WHILE ‘(’ expression ‘)’ stmt
     | (CASE CONST ‘:’)* BREAK ‘;’
     | (CASE CONST ‘:’)* CONTINUE ‘;’
     | ( CONST ‘:’)* RETURN [expression] ‘;’
     | ‘{’ (stmt)* ‘}’

这样对吗?

Is this right?

没有。语法展示只是说“只有 switchbreakcontinue 可以有 case some-constant : 标签,而其他的可以有 some-constant :.

也就是说 case 标签只能用于直接位于 switch 内部的命令、开关的主体,或者可能是作为主体的复合语句的主体开关的,必须是可以有 case 标签的语句或语句列表,而出现在其他地方的语句或语句列表必须是不能有 case 标签的语句类型.

因此定义一个像 MayBeLabeledStatement 这样可以有一个 case 标签的语法标记和另一个像 Statement 这样不能有一个 case 标签的语法标记。这两个语句都可以扩展为各种语句(表达式、ifwhile 等),但是 MayBeLabeledStatement 的语句也可能具有 case 标签。此外,所有 within a MayBeLabeledStatement 的语句都应该是 Statement 类型的语句,不能有 case 标签——除非你可能需要考虑如何处理 switch 中的单个语句(可以是复合语句,也可以不是)。

同样,您将需要不同的语法标记来处理 whileswitch(允许 break)内的语句与不在 whileswitchwhile 中的另一个(允许 continue) 与不在 while 中的那些。对于 [=24 中的语句,您可能还需要一些组合=] 并且直接在 switch 内与 while 内而不直接在 switch.

内的语句

您面临的任务非常复杂。作为一种方法(我认为这里没有足够的地方来充分解释它)你可以首先开始写类似的 stmt 非终结符,一个接受 case 声明,一个不接受.它们必须都来自您发布的原始 stmt

stmt_w_case ->  (CASE CONST ‘:’)* expression ‘;’
      | (CASE CONST ‘:’)* IF ‘(’ expression ‘)’ stmt [ELSE stmt]
      | (CASE CONST ‘:’)* WHILE ‘(’ expression ‘)’ stmt
      | (CASE CONST ‘:’)* SWITCH ‘(’ expression ‘)’ stmt
      | (CASE CONST ‘:’)* RETURN [expression] ‘;’
      | (CASE CONST ‘:’)* BREAK ‘;’
      | (CASE CONST ‘:’)* CONTINUE ‘;’
      | ‘{’ (stmt)* ‘}’

stmt_wo_case ->  expression ‘;’
      | IF ‘(’ expression ‘)’ stmt [ELSE stmt]
      | WHILE ‘(’ expression ‘)’ stmt
      | SWITCH ‘(’ expression ‘)’ stmt
      | RETURN [expression] ‘;’
      | BREAK ‘;’
      | CONTINUE ‘;’
      | ‘{’ (stmt)* ‘}’

现在你说你只想在 switch 语句中使用 stmt_w_case,那么 while stmt 应该改为 stmt_w_case 而所有其他必须改为stmt_wo_case,如

stmt_w_case ->  (CASE CONST ‘:’)* expression ‘;’
      | (CASE CONST ‘:’)* IF ‘(’ expression ‘)’ stmt_wo_case [ELSE stmt_wo_case]
      | (CASE CONST ‘:’)* WHILE ‘(’ expression ‘)’ stmt_wo_case
      | (CASE CONST ‘:’)* SWITCH ‘(’ expression ‘)’ stmt_w_case
      | (CASE CONST ‘:’)* RETURN [expression] ‘;’
      | (CASE CONST ‘:’)* BREAK ‘;’
      | (CASE CONST ‘:’)* CONTINUE ‘;’
      | ‘{’ (stmt_w_case)* ‘}’

stmt_wo_case ->  expression ‘;’
      | IF ‘(’ expression ‘)’ stmt_wo_case [ELSE stmt_wo_case]
      | WHILE ‘(’ expression ‘)’ stmt_wo_case
      | SWITCH ‘(’ expression ‘)’ stmt_w_case
      | RETURN [expression] ‘;’
      | BREAK ‘;’
      | CONTINUE ‘;’
      | ‘{’ (stmt_wo_case)* ‘}’

(查看 stmt_wo_case 如何将其条件传播到括号 {} 之间的嵌入式 stmt 以及 stmt_w_case 的类似情况)

那你可以说:

stmt -> stmt_wo_case

你的语法已经准备好了(但你以后可能会 运行 遇到麻烦,见下文)

break 语句的情况下,您应该对新语法执行相同的操作,但要小心,因为在这种情况下,您可以将 break 很好地嵌套在任何if 语句或类似语句的语句。对于我们刚刚分叉的每条规则......你需要做一个不同的 stmt_w_case_no_break 和一个 stmt_w_case_w_breakstmt_wo_case... 也是一样)你知道这是在哪里吗给我们带来?在每个地方,我们都需要某种规则,无论有无,我们都将规则的数量加倍......你会随着你做出的此类决定的数量呈指数级增长。