Playing with the grammar: part 1, else if

Paul Svensson paul at svensson.org
Tue Jun 12 11:15:55 EDT 2001


While poking around to figure out the Python lexer/parser/grammar all
hangs together, I happened on the discussion here about the merits of
'else if' vs 'elif'.  Changing it turned out to be much easier than I
had expected, so now you can try for yourself which one you like better.
Apply this patch to your Python 1.2, and it will understand both.

	/Paul

------------------------------------------------------------------------------
diff -r -c Python-2.1/Grammar/Grammar Python-2.1-UNRESERVED/Grammar/Grammar
*** Python-2.1/Grammar/Grammar	Tue Feb 27 13:36:14 2001
--- Python-2.1-UNRESERVED/Grammar/Grammar	Fri Jun  8 12:20:47 2001
***************
*** 57,63 ****
  assert_stmt: 'assert' test [',' test]
  
  compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef
! if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
  while_stmt: 'while' test ':' suite ['else' ':' suite]
  for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite]
  try_stmt: ('try' ':' suite (except_clause ':' suite)+ #diagram:break
--- 57,63 ----
  assert_stmt: 'assert' test [',' test]
  
  compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef
! if_stmt: 'if' test ':' suite (('elif' | 'else' 'if') test ':' suite)* ['else' ':' suite]
  while_stmt: 'while' test ':' suite ['else' ':' suite]
  for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite]
  try_stmt: ('try' ':' suite (except_clause ':' suite)+ #diagram:break
diff -r -c Python-2.1/Modules/parsermodule.c Python-2.1-UNRESERVED/Modules/parsermodule.c
*** Python-2.1/Modules/parsermodule.c	Sun Jan  7 00:59:59 2001
--- Python-2.1-UNRESERVED/Modules/parsermodule.c	Thu Jun  7 12:34:22 2001
***************
*** 937,983 ****
  }
  
  
  /*  if_stmt:
!  *      'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
   */
  static int
  validate_if(node *tree)
  {
      int nch = NCH(tree);
      int res = (validate_ntype(tree, if_stmt)
                 && (nch >= 4)
                 && validate_name(CHILD(tree, 0), "if")
-                && validate_test(CHILD(tree, 1))
                 && validate_colon(CHILD(tree, 2))
                 && validate_suite(CHILD(tree, 3)));
  
!     if (res && ((nch % 4) == 3)) {
          /*  ... 'else' ':' suite  */
!         res = (validate_name(CHILD(tree, nch - 3), "else")
                 && validate_colon(CHILD(tree, nch - 2))
                 && validate_suite(CHILD(tree, nch - 1)));
          nch -= 3;
      }
!     else if (!res && !PyErr_Occurred())
          (void) validate_numnodes(tree, 4, "if");
!     if ((nch % 4) != 0)
!         /* Will catch the case for nch < 4 */
!         res = validate_numnodes(tree, 0, "if");
      else if (res && (nch > 4)) {
!         /*  ... ('elif' test ':' suite)+ ...  */
!         int j = 4;
!         while ((j < nch) && res) {
!             res = (validate_name(CHILD(tree, j), "elif")
!                    && validate_colon(CHILD(tree, j + 2))
!                    && validate_test(CHILD(tree, j + 1))
!                    && validate_suite(CHILD(tree, j + 3)));
!             j += 4;
          }
      }
      return (res);
  }
  
  
  /*  parameters:
   *      '(' [varargslist] ')'
   *
--- 937,1007 ----
  }
  
  
+ 
  /*  if_stmt:
!  *      'if' test ':' suite (('elif' | 'else' 'if') test ':' suite)* ['else' ':' suite]
   */
  static int
  validate_if(node *tree)
  {
+     int j = 0;
      int nch = NCH(tree);
+     node *last_else = nch > 4 ? CHILD(tree, nch - 3) : NULL;
      int res = (validate_ntype(tree, if_stmt)
                 && (nch >= 4)
                 && validate_name(CHILD(tree, 0), "if")
                 && validate_colon(CHILD(tree, 2))
+                && validate_test(CHILD(tree, 1))
                 && validate_suite(CHILD(tree, 3)));
  
!     if (res && last_else && TYPE(last_else) == NAME
!                          && STR(last_else) == "else") {
          /*  ... 'else' ':' suite  */
!         res = (validate_name(last_else, "else")
                 && validate_colon(CHILD(tree, nch - 2))
                 && validate_suite(CHILD(tree, nch - 1)));
          nch -= 3;
      }
!     else if (!res && !PyErr_Occurred()) {
          (void) validate_numnodes(tree, 4, "if");
!     }
      else if (res && (nch > 4)) {
!         /*  ... (('elif' | 'else' 'if') test ':' suite)+ ...  */
!         j = 4;
!         while (res && j < nch) {
!             res = validate_ntype(CHILD(tree, j), NAME);
!             if (!res)
!                 break;
!             if (strcmp(STR(CHILD(tree, j)), "else") == 0) {
! 		if (j > nch - 5)
!                     break;
!                 res = (validate_name(CHILD(tree, j), "else")
!                        && validate_name(CHILD(tree, j + 1), "if")
!                        && validate_colon(CHILD(tree, j + 3))
!                        && validate_test(CHILD(tree, j + 2))
!                        && validate_suite(CHILD(tree, j + 4)));
!                 j += 5;
!             }
!             else {
! 		if (j > nch - 4)
!                     break;
!                 res = (validate_name(CHILD(tree, j), "elif")
!                        && validate_colon(CHILD(tree, j + 2))
!                        && validate_test(CHILD(tree, j + 1))
!                        && validate_suite(CHILD(tree, j + 3)));
!                 j += 4;
!             }
          }
      }
+     if (res && j != nch) {
+         /* Will catch the case for nch < 4 */
+         res = validate_numnodes(tree, 0, "if");
+     }
      return (res);
  }
  
  
+ 
  /*  parameters:
   *      '(' [varargslist] ')'
   *
diff -r -c Python-2.1/Python/compile.c Python-2.1-UNRESERVED/Python/compile.c
*** Python-2.1/Python/compile.c	Sat Apr 14 13:51:48 2001
--- Python-2.1-UNRESERVED/Python/compile.c	Thu Jun  7 14:00:39 2001
***************
*** 2813,2825 ****
  static void
  com_if_stmt(struct compiling *c, node *n)
  {
! 	int i;
  	int anchor = 0;
  	REQ(n, if_stmt);
! 	/*'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] */
  	for (i = 0; i+3 < NCH(n); i+=4) {
! 		int a = 0;
! 		node *ch = CHILD(n, i+1);
  		if (is_constant_false(c, ch))
  			continue;
  		if (i > 0)
--- 2812,2830 ----
  static void
  com_if_stmt(struct compiling *c, node *n)
  {
! 	int i, a;
  	int anchor = 0;
+ 	node *ch;
  	REQ(n, if_stmt);
! 	/*'if' test ':' suite (('elif' | 'else' 'if') test ':' suite)* ['else' ':' suite] */
  	for (i = 0; i+3 < NCH(n); i+=4) {
! 		a = 0;
! 		if (TYPE(CHILD(n, i+3)) == COLON) {
! 			i++;
! 			if (i+3 >= NCH(n))
! 				break;
! 		}
! 		ch = CHILD(n, i+1);
  		if (is_constant_false(c, ch))
  			continue;
  		if (i > 0)



More information about the Python-list mailing list