The code block surrounded by 'if' ... 'endif' is reduced into if_stmt,
which is accepted in the 'choice' context. Therefore, you can write any
statements within a choice block by wrapping 'if y' ... 'end'.
For example, you can create a menu inside a choice, like follows:
---------------->8----------------
  choice
          prompt "choice"
  config A
          bool "A"
  config B
          bool "B"
  if y
  menu "strange menu"
  config C
          bool "C"
  endmenu
  endif
  endchoice
---------------->8----------------
I want to change such a weird structure into a syntax error.
In fact, the USB gadget Kconfig had used nested 'choice' for no good
reason until commit 
df8df5e4bc37 ("usb: get rid of 'choice' for
legacy gadget drivers") killed it.
I think the 'source' inside 'choice' is on the fence. It is at least
gramatically sensible as long as the included file contains only
bool/tristate configs. However, it makes the code unreadable, and people
tend to forget the fact that the file is included from the choice
block. Commit 
10e5e6c24963 ("usb: gadget: move choice ... endchoice to
legacy/Kconfig") got rid of the only usecase.
Going forward, you can only use 'config', 'comment', and 'if' inside
'choice'. This also recursively applies to 'if' blocks inside 'choice'.
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
 
 stmt_list:
          /* empty */
-       | stmt_list common_stmt
+       | stmt_list assignment_stmt
        | stmt_list choice_stmt
+       | stmt_list comment_stmt
+       | stmt_list config_stmt
+       | stmt_list if_stmt
        | stmt_list menu_stmt
+       | stmt_list menuconfig_stmt
+       | stmt_list source_stmt
        | stmt_list T_WORD error T_EOL  { zconf_error("unknown statement \"%s\"", $2); }
        | stmt_list error T_EOL         { zconf_error("invalid statement"); }
 ;
 
-common_stmt:
-         if_stmt
-       | comment_stmt
-       | config_stmt
-       | menuconfig_stmt
-       | source_stmt
-       | assignment_stmt
+stmt_list_in_choice:
+         /* empty */
+       | stmt_list_in_choice comment_stmt
+       | stmt_list_in_choice config_stmt
+       | stmt_list_in_choice if_stmt_in_choice
+       | stmt_list_in_choice error T_EOL       { zconf_error("invalid statement"); }
 ;
 
 /* config/menuconfig entry */
        }
 };
 
-choice_stmt: choice_entry choice_block choice_end
+choice_stmt: choice_entry stmt_list_in_choice choice_end
 ;
 
 choice_option_list:
        | T_DEF_BOOL            { $$ = S_BOOLEAN; }
        | T_DEF_TRISTATE        { $$ = S_TRISTATE; }
 
-choice_block:
-         /* empty */
-       | choice_block common_stmt
-;
-
 /* if entry */
 
 if_entry: T_IF expr T_EOL
 if_stmt: if_entry stmt_list if_end
 ;
 
+if_stmt_in_choice: if_entry stmt_list_in_choice if_end
+;
+
 /* menu entry */
 
 menu: T_MENU T_WORD_QUOTE T_EOL