Update to reflect recent grammar changes (list comprehensions, extended
print statement), and fix up the extended call syntax support.

Minor stylistic cleanups.
diff --git a/Modules/parsermodule.c b/Modules/parsermodule.c
index d581c9b..57a3046 100644
--- a/Modules/parsermodule.c
+++ b/Modules/parsermodule.c
@@ -58,7 +58,7 @@
 = "This is an interface to Python's internal parser.";
 
 static char*
-parser_version_string = "0.4";
+parser_version_string = "0.5";
 
 
 typedef PyObject* (*SeqMaker) (int length);
@@ -888,10 +888,10 @@
 VALIDATER(stmt);                VALIDATER(simple_stmt);
 VALIDATER(expr_stmt);           VALIDATER(power);
 VALIDATER(print_stmt);          VALIDATER(del_stmt);
-VALIDATER(return_stmt);
+VALIDATER(return_stmt);         VALIDATER(list_iter);
 VALIDATER(raise_stmt);          VALIDATER(import_stmt);
-VALIDATER(global_stmt);
-VALIDATER(assert_stmt);
+VALIDATER(global_stmt);         VALIDATER(list_if);
+VALIDATER(assert_stmt);         VALIDATER(list_for);
 VALIDATER(exec_stmt);           VALIDATER(compound_stmt);
 VALIDATER(while);               VALIDATER(for);
 VALIDATER(try);                 VALIDATER(except_clause);
@@ -906,6 +906,7 @@
 VALIDATER(subscriptlist);       VALIDATER(sliceop);
 VALIDATER(exprlist);            VALIDATER(dictmaker);
 VALIDATER(arglist);             VALIDATER(argument);
+VALIDATER(listmaker);
 
 
 #define is_even(n)      (((n) & 1) == 0)
@@ -986,7 +987,7 @@
 }
 
 
-/*  VALIDATE(class)
+/*  validate_class()
  *
  *  classdef:
  *      'class' NAME ['(' testlist ')'] ':' suite
@@ -1078,7 +1079,7 @@
 }
 
 
-/*  VALIDATE(suite)
+/*  validate_suite()
  *
  *  suite:
  *      simple_stmt
@@ -1120,15 +1121,51 @@
 }
 
 
-/*  VALIDATE(varargslist)
+/* '*' NAME [',' '**' NAME] | '**' NAME
+ */
+static int
+validate_varargslist_trailer(node *tree, int start)
+{
+    int nch = NCH(tree);
+    int res = 0;
+    int sym;
+
+    if (nch <= start) {
+        err_string("expected variable argument trailer for varargslist");
+        return 0;
+    }
+    sym = TYPE(CHILD(tree, start));
+    if (sym == STAR) {
+        /*
+         *  ('*' NAME [',' '**' NAME]
+         */
+        if (nch-start == 2)
+            res = validate_name(CHILD(tree, start+1), NULL);
+        else if (nch-start == 5)
+            res = (validate_name(CHILD(tree, start+1), NULL)
+                   && validate_comma(CHILD(tree, start+2))
+                   && validate_doublestar(CHILD(tree, start+3))
+                   && validate_name(CHILD(tree, start+4), NULL));
+    }
+    else if (sym == DOUBLESTAR) {
+        /*
+         *  '**' NAME
+         */
+        if (nch-start == 2)
+            res = validate_name(CHILD(tree, start+1), NULL);
+    }
+    if (!res)
+        err_string("illegal variable argument trailer for varargslist");
+    return res;
+}
+
+
+/*  validate_varargslist()
  *
  *  varargslist:
- *      (fpdef ['=' test] ',')* ('*' NAME [',' '*' '*' NAME] | '*' '*' NAME)
- *    | fpdef ['=' test] (',' fpdef ['=' test])* [',']
- *
  *      (fpdef ['=' test] ',')*
- *           ('*' NAME [',' ('**'|'*' '*') NAME]
- *         | ('**'|'*' '*') NAME)
+ *           ('*' NAME [',' '**' NAME]
+ *         | '**' NAME)
  *    | fpdef ['=' test] (',' fpdef ['=' test])* [',']
  *
  */
@@ -1137,97 +1174,150 @@
 {
     int nch = NCH(tree);
     int res = validate_ntype(tree, varargslist) && (nch != 0);
+    int sym;
 
-    if (res && (nch >= 2) && (TYPE(CHILD(tree, nch - 1)) == NAME)) {
-        /*  (fpdef ['=' test] ',')*
-         *  ('*' NAME [',' '*' '*' NAME] | '*' '*' NAME)
-         */
-        int pos = 0;
-        int remaining = nch;
-
-        while (res && (TYPE(CHILD(tree, pos)) == fpdef)) {
-            res = validate_fpdef(CHILD(tree, pos));
-            if (res) {
-                if (TYPE(CHILD(tree, pos + 1)) == EQUAL) {
-                    res = validate_test(CHILD(tree, pos + 2));
-                    pos += 2;
-                }
-                res = res && validate_comma(CHILD(tree, pos + 1));
-                pos += 2;
-            }
-        }
-        if (res) {
-            remaining = nch - pos;
-            res = ((remaining == 2) || (remaining == 3)
-                   || (remaining == 5) || (remaining == 6));
-            if (!res)
-                (void) validate_numnodes(tree, 2, "varargslist");
-            else if (TYPE(CHILD(tree, pos)) == DOUBLESTAR)
-                return ((remaining == 2)
-                        && validate_ntype(CHILD(tree, pos+1), NAME));
-            else {
-                res = validate_star(CHILD(tree, pos++));
-                --remaining;
-            }
-        }
-        if (res) {
-            if (remaining == 2) {
-                res = (validate_star(CHILD(tree, pos))
-                       && validate_ntype(CHILD(tree, pos + 1), NAME));
-            }
-            else {
-                res = validate_ntype(CHILD(tree, pos++), NAME);
-                if (res && (remaining >= 4)) {
-                    res = validate_comma(CHILD(tree, pos));
-                    if (--remaining == 3)
-                        res = (validate_star(CHILD(tree, pos + 1))
-                               && validate_star(CHILD(tree, pos + 2)));
-                    else
-                        res = validate_ntype(CHILD(tree, pos + 1), DOUBLESTAR);
-                }
-            }
-        }
-        if (!res && !PyErr_Occurred())
-            err_string("Incorrect validation of variable arguments list.");
+    if (nch < 1) {
+        err_string("varargslist missing child nodes");
+        return 0;
     }
-    else if (res) {
-        /*  fpdef ['=' test] (',' fpdef ['=' test])* [',']  */
-        if (TYPE(CHILD(tree, nch - 1)) == COMMA)
-            --nch;
+    sym = TYPE(CHILD(tree, 0));
+    if (sym == STAR || sym == DOUBLESTAR)
+        res = validate_varargslist_trailer(tree, 0);
+    else if (sym == fpdef) {
+        int i = 0;
 
-        /*  fpdef ['=' test] (',' fpdef ['=' test])*  */
-        res = (is_odd(nch)
-               && validate_fpdef(CHILD(tree, 0)));
-
-        if (res && (nch > 1)) {
-            int pos = 1;
-            if (TYPE(CHILD(tree, 1)) == EQUAL) {
-                res = validate_test(CHILD(tree, 2));
-                pos += 2;
-            }
-            /*  ... (',' fpdef ['=' test])*  */
-            for ( ; res && (pos < nch); pos += 2) {
-                /* ',' fpdef */
-                res = (validate_comma(CHILD(tree, pos))
-                       && validate_fpdef(CHILD(tree, pos + 1)));
-                if (res
-                    && ((nch - pos) > 2)
-                    && (TYPE(CHILD(tree, pos + 2)) == EQUAL)) {
-                    /* ['=' test] */
-                    res = validate_test(CHILD(tree, pos + 3));
-                    pos += 2;
+        sym = TYPE(CHILD(tree, nch-1));
+        if (sym == NAME) {
+            /*
+             *   (fpdef ['=' test] ',')+
+             *       ('*' NAME [',' '**' NAME]
+             *     | '**' NAME)
+             */
+            /* skip over (fpdef ['=' test] ',')+ */
+            while (res && (i+2 <= nch)) {
+                res = validate_fpdef(CHILD(tree, i));
+                ++i;
+                if (res && TYPE(CHILD(tree, i)) == EQUAL && (i+2 <= nch)) {
+                    res = (validate_equal(CHILD(tree, i))
+                           && validate_test(CHILD(tree, i+1)));
+                    if (res)
+                        i += 2;
                 }
+                if (res && i < nch) {
+                    res = validate_comma(CHILD(tree, i));
+                    if (res)
+                        ++i;
+                }
+            }
+            /* handle '*' NAME [',' '**' NAME] | '**' NAME */
+            if (res)
+                res = validate_varargslist_trailer(tree, i);
+        }
+        else {
+            /*
+             *  fpdef ['=' test] (',' fpdef ['=' test])* [',']
+             */
+            if (sym == COMMA) {
+                res = validate_comma(CHILD(tree, nch-1));
+                if (!res)
+                    return 0;
+                --nch;
+            }
+            /*
+             *  fpdef ['=' test] (',' fpdef ['=' test])*
+             */
+            res = validate_fpdef(CHILD(tree, 0));
+            ++i;
+            if (res && (i+2 < nch) && TYPE(CHILD(tree, 1)) == EQUAL) {
+                res = (validate_equal(CHILD(tree, 1))
+                       && validate_test(CHILD(tree, 2)));
+                i += 2;
+            }
+            /*
+             *  ... (',' fpdef ['=' test])*
+             *  i ---^^^
+             */
+            while (res && (nch - i) >= 2) {
+                res = (validate_comma(CHILD(tree, i))
+                       && validate_fpdef(CHILD(tree, i+1)));
+                i += 2;
+                if (res && (nch - i) >= 2
+                    && TYPE(CHILD(tree, i)) == COMMA) {
+                    res = (validate_comma(CHILD(tree, i))
+                           && validate_test(CHILD(tree, i+1)));
+                    if (res)
+                        i += 2;
+                }
+            }
+            if (res && nch - i != 0) {
+                res = 0;
+                err_string("illegal formation for varargslist");
             }
         }
     }
-    else {
-        err_string("Improperly formed argument list.");
-    }
-    return (res);
+    return res;
 }
 
 
-/*  VALIDATE(fpdef)
+/*  list_iter:  list_for | list_if
+ */
+static int
+validate_list_iter(node *tree)
+{
+    int res = (validate_ntype(tree, list_iter)
+               && validate_numnodes(tree, 1, "list_iter"));
+    if (res && TYPE(CHILD(tree, 0)) == list_for)
+        res = validate_list_for(CHILD(tree, 0));
+    else
+        res = validate_list_if(CHILD(tree, 0));
+
+    return res;
+}
+
+/*  list_for:  'for' exprlist 'in' testlist [list_iter]
+ */
+static int
+validate_list_for(node *tree)
+{
+    int nch = NCH(tree);
+    int res;
+
+    if (nch == 5)
+        res = validate_list_iter(CHILD(tree, 4));
+    else
+        res = validate_numnodes(tree, 4, "list_for");
+
+    if (res)
+        res = (validate_name(CHILD(tree, 0), "for")
+               && validate_exprlist(CHILD(tree, 1))
+               && validate_name(CHILD(tree, 2), "in")
+               && validate_testlist(CHILD(tree, 3)));
+
+    return res;
+}
+
+/*  list_if:  'if' test [list_iter]
+ */
+static int
+validate_list_if(node *tree)
+{
+    int nch = NCH(tree);
+    int res;
+
+    if (nch == 3)
+        res = validate_list_iter(CHILD(tree, 2));
+    else
+        res = validate_numnodes(tree, 2, "list_if");
+
+    if (res)
+        res = (validate_name(CHILD(tree, 0), "if")
+               && validate_test(CHILD(tree, 1)));
+
+    return res;
+}
+
+
+/*  validate_fpdef()
  *
  *  fpdef:
  *      NAME
@@ -1387,8 +1477,8 @@
 
 /*  print_stmt:
  *
- *      'print' (test ',')* [test]
- *
+ *      'print' ( [ test (',' test)* [','] ]
+ *              | '>>' test [ (',' test)+ [','] ] )
  */
 static int
 validate_print_stmt(node *tree)
@@ -1396,19 +1486,40 @@
     int j;
     int nch = NCH(tree);
     int res = (validate_ntype(tree, print_stmt)
-               && (nch != 0)
+               && (nch > 0)
                && validate_name(CHILD(tree, 0), "print"));
 
-    if (res && is_even(nch)) {
-        res = validate_test(CHILD(tree, nch - 1));
-        --nch;
-    }
-    else if (!res && !PyErr_Occurred())
-        (void) validate_numnodes(tree, 1, "print_stmt");
-    for (j = 1; res && (j < nch); j += 2)
-        res = (validate_test(CHILD(tree, j))
-               && validate_ntype(CHILD(tree, j + 1), COMMA));
+    if (res && nch > 1) {
+        int sym = TYPE(CHILD(tree, 1));
+        int i = 1;
+        int allow_trailing_comma = 1;
 
+        if (sym == test)
+            res = validate_test(CHILD(tree, i++));
+        else {
+            if (nch < 3)
+                res = validate_numnodes(tree, 3, "print_stmt");
+            else {
+                res = (validate_ntype(CHILD(tree, i), RIGHTSHIFT)
+                       && validate_test(CHILD(tree, i+1)));
+                i += 2;
+                allow_trailing_comma = 0;
+            }
+        }
+        if (res) {
+            /*  ... (',' test)* [',']  */
+            while (res && i+2 <= nch) {
+                res = (validate_comma(CHILD(tree, i))
+                       && validate_test(CHILD(tree, i+1)));
+                allow_trailing_comma = 1;
+                i += 2;
+            }
+            if (res && !allow_trailing_comma)
+                res = validate_numnodes(tree, i, "print_stmt");
+            else if (res && i < nch)
+                res = validate_comma(CHILD(tree, i));
+        }
+    }
     return (res);
 }
 
@@ -1466,10 +1577,54 @@
 }
 
 
+static int
+validate_import_as_name(node *tree)
+{
+    int nch = NCH(tree);
+    int ok = validate_ntype(tree, import_as_name);
+
+    if (ok) {
+        if (nch == 1)
+            ok = validate_name(CHILD(tree, 0), NULL);
+        else if (nch == 3)
+            ok = (validate_name(CHILD(tree, 0), NULL)
+                  && validate_name(CHILD(tree, 1), "as")
+                  && validate_name(CHILD(tree, 2), NULL));
+        else
+            ok = validate_numnodes(tree, 3, "import_as_name");
+    }
+    return ok;
+}
+
+
+/* dotted_as_name:  dotted_name [NAME NAME]
+ */
+static int
+validate_dotted_as_name(node *tree)
+{
+    int nch = NCH(tree);
+    int res = validate_ntype(tree, dotted_as_name);
+
+    if (res) {
+        if (nch == 1)
+            res = validate_ntype(CHILD(tree, 0), dotted_name);
+        else if (nch == 3)
+            res = (validate_ntype(CHILD(tree, 0), dotted_name)
+                   && validate_name(CHILD(tree, 1), "as")
+                   && validate_name(CHILD(tree, 2), NULL));
+        else {
+            res = 0;
+            err_string("Illegal number of children for dotted_as_name.");
+        }
+    }
+    return res;
+}
+
+
 /*  import_stmt:
  *
- *    'import' dotted_name (',' dotted_name)*
- *  | 'from' dotted_name 'import' ('*' | NAME (',' NAME)*)
+ *    'import' dotted_as_name (',' dotted_as_name)*
+ *  | 'from' dotted_name 'import' ('*' | import_as_name (',' import_as_name)*)
  */
 static int
 validate_import_stmt(node *tree)
@@ -1477,32 +1632,35 @@
     int nch = NCH(tree);
     int res = (validate_ntype(tree, import_stmt)
                && (nch >= 2) && is_even(nch)
-               && validate_ntype(CHILD(tree, 0), NAME)
-               && validate_ntype(CHILD(tree, 1), dotted_name));
+               && validate_ntype(CHILD(tree, 0), NAME));
 
     if (res && (strcmp(STR(CHILD(tree, 0)), "import") == 0)) {
         int j;
 
+        res = validate_dotted_as_name(CHILD(tree, 1));
         for (j = 2; res && (j < nch); j += 2)
             res = (validate_comma(CHILD(tree, j))
                    && validate_ntype(CHILD(tree, j + 1), dotted_name));
     }
-    else if (res && validate_name(CHILD(tree, 0), "from")) {
+    else if (res && (res = validate_name(CHILD(tree, 0), "from"))) {
         res = ((nch >= 4) && is_even(nch)
-               && validate_name(CHILD(tree, 2), "import"));
+               && validate_name(CHILD(tree, 2), "import")
+               && validate_dotted_as_name(CHILD(tree, 1)));
         if (nch == 4) {
-            res = ((TYPE(CHILD(tree, 3)) == NAME)
-                   || (TYPE(CHILD(tree, 3)) == STAR));
-            if (!res)
-                err_string("Illegal import statement.");
+            if (TYPE(CHILD(tree, 3)) == import_as_name)
+                res = validate_import_as_name(CHILD(tree, 3));
+            else
+                res = validate_star(CHILD(tree, 3));
         }
         else {
-            /*  'from' NAME 'import' NAME (',' NAME)+  */
+            /*  'from' dotted_name 'import' import_as_name
+             *      (',' import_as_name)+
+             */
             int j;
-            res = validate_ntype(CHILD(tree, 3), NAME);
+            res = validate_import_as_name(CHILD(tree, 3));
             for (j = 4; res && (j < nch); j += 2)
                 res = (validate_comma(CHILD(tree, j))
-                       && validate_ntype(CHILD(tree, j + 1), NAME));
+                       && validate_import_as_name(CHILD(tree, j + 1)));
         }
     }
     else
@@ -1983,8 +2141,10 @@
 {
     int pos;
     int nch = NCH(tree);
-    int res = validate_ntype(tree, atom) && (nch >= 1);
+    int res = validate_ntype(tree, atom);
 
+    if (res && nch < 1)
+        res = validate_numnodes(tree, nch+1, "atom");
     if (res) {
         switch (TYPE(CHILD(tree, 0))) {
           case LPAR:
@@ -1995,11 +2155,15 @@
                 res = validate_testlist(CHILD(tree, 1));
             break;
           case LSQB:
-            res = ((nch <= 3)
-                   && validate_ntype(CHILD(tree, nch - 1), RSQB));
-
-            if (res && (nch == 3))
-                res = validate_testlist(CHILD(tree, 1));
+            if (nch == 2)
+                res = validate_ntype(CHILD(tree, 1), RSQB);
+            else if (nch == 3)
+                res = (validate_listmaker(CHILD(tree, 1))
+                       && validate_ntype(CHILD(tree, 2), RSQB));
+            else {
+                res = 0;
+                err_string("illegal list display atom");
+            }
             break;
           case LBRACE:
             res = ((nch <= 3)
@@ -2030,6 +2194,38 @@
 }
 
 
+static int
+validate_listmaker(node *tree)
+{
+    int nch = NCH(tree);
+    int ok = nch;
+
+    if (nch == 0)
+        err_string("missing child nodes of listmaker");
+    else
+        ok = validate_test(CHILD(tree, 0));
+
+    /*
+     *  list_iter | (',' test)* [',']
+     */
+    if (nch == 2 && TYPE(CHILD(tree, 1)) == list_iter)
+        ok = validate_list_iter(CHILD(tree, 1));
+    else {
+        /*  (',' test)* [',']  */
+        int i = 1;
+        while (ok && nch - i >= 2) {
+            ok = (validate_comma(CHILD(tree, i))
+                  && validate_test(CHILD(tree, i+1)));
+            if (ok)
+                i += 2;
+        }
+        if (ok && nch-i)
+            ok = validate_comma(CHILD(tree, nch-1));
+    }
+    return ok;
+}
+
+
 /*  funcdef:
  *      'def' NAME parameters ':' suite
  *
@@ -2068,81 +2264,70 @@
 
 /*  arglist:
  *
- *  (argument ',')* (argument* [','] | '*' test [',' '**' test] | '**' test)
+ *  (argument ',')* (argument [','] | '*' test [',' '**' test] | '**' test)
  */
 static int
 validate_arglist(node *tree)
 {
     int nch = NCH(tree);
-    int i, ok = 1;
-    node *last;
+    int i = 0;
+    int ok = 1;
 
     if (nch <= 0)
         /* raise the right error from having an invalid number of children */
         return validate_numnodes(tree, nch + 1, "arglist");
 
-    last = CHILD(tree, nch - 1);
-    if (TYPE(last) == test) {
-        /* Extended call syntax introduced in Python 1.6 has been used;
-         * validate and strip that off and continue;
-         * adjust nch to perform the cut, and ensure resulting nch is even
-         * (validation of the first part doesn't require that).
+    while (ok && nch-i >= 2) {
+        /* skip leading (argument ',') */
+        ok = (validate_argument(CHILD(tree, i))
+              && validate_comma(CHILD(tree, i+1)));
+        if (ok)
+            i += 2;
+        else
+            PyErr_Clear();
+    }
+    ok = 1;
+    if (nch-i > 0) {
+        /*
+         * argument | '*' test [',' '**' test] | '**' test
          */
-        if (nch < 2) {
-            validate_numnodes(tree, nch + 1, "arglist");
-            return 0;
-        }
-        ok = validate_test(last);
-        if (ok) {
-            node *prev = CHILD(tree, nch - 2);
-            /* next must be '*' or '**' */
-            if (validate_doublestar(prev)) {
-                nch -= 2;
-                if (nch >= 3) {
-                    /* may include:  '*' test ',' */
-                    last = CHILD(tree, nch - 1);
-                    prev = CHILD(tree, nch - 2);
-                    if (TYPE(prev) == test) {
-                        ok = validate_comma(last)
-                             && validate_test(prev)
-                             && validate_star(CHILD(tree, nch - 3));
-                        if (ok)
-                            nch -= 3;
-                    }
-                    /* otherwise, nothing special */
-                }
+        int sym = TYPE(CHILD(tree, i));
+
+        if (sym == argument) {
+            ok = validate_argument(CHILD(tree, i));
+            if (ok && i+1 != nch) {
+                err_string("illegal arglist specification"
+                           " (extra stuff on end)");
+                ok = 0;
             }
+        }
+        else if (sym == STAR) {
+            ok = validate_star(CHILD(tree, i));
+            if (ok && (nch-i == 2))
+                ok = validate_test(CHILD(tree, i+1));
+            else if (ok && (nch-i == 5))
+                ok = (validate_test(CHILD(tree, i+1))
+                      && validate_comma(CHILD(tree, i+2))
+                      && validate_doublestar(CHILD(tree, i+3))
+                      && validate_test(CHILD(tree, i+4)));
             else {
-                /* must be only:  '*' test */
-                PyErr_Clear();
-                ok = validate_star(prev);
-                nch -= 2;
-            }
-            if (ok && is_odd(nch)) {
-                /* Illegal number of nodes before extended call syntax;
-                 * validation of the "normal" arguments does not require
-                 * a trailing comma, but requiring an even number of
-                 * children will effect the same requirement.
-                 */
-                return validate_numnodes(tree, nch + 1, "arglist");
+                err_string("illegal use of '*' in arglist");
+                ok = 0;
             }
         }
-    }
-    /* what remains must be:  (argument ",")* [argument [","]] */
-    i = 0;
-    while (ok && nch - i >= 2) {
-        ok = validate_argument(CHILD(tree, i))
-             && validate_comma(CHILD(tree, i + 1));
-        i += 2;
-    }
-    if (ok && i < nch) {
-        ok = validate_comma(CHILD(tree, i));
-        ++i;
-    }
-    if (i != nch) {
-        /* internal error! */
-        ok = 0;
-        err_string("arglist: internal error; nch != i");
+        else if (sym == DOUBLESTAR) {
+            if (nch-i == 2)
+                ok = (validate_doublestar(CHILD(tree, i))
+                      && validate_test(CHILD(tree, i+1)));
+            else {
+                err_string("illegal use of '**' in arglist");
+                ok = 0;
+            }
+        }
+        else {
+            err_string("illegal arglist specification");
+            ok = 0;
+        }
     }
     return (ok);
 }