Index: src/main/org/codehaus/groovy/antlr/treewalker/CompositeVisitor.java
===================================================================
--- src/main/org/codehaus/groovy/antlr/treewalker/CompositeVisitor.java	(revision 20590)
+++ src/main/org/codehaus/groovy/antlr/treewalker/CompositeVisitor.java	(revision )
@@ -758,6 +758,16 @@
         while (itr.hasNext()) {((Visitor)itr.next()).visitModAssign(t,visit);}
     }
 
+    public void visitMultiCatch(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitMultiCatch(t, visit);}
+    }
+
+    public void visitMultiCatchTypes(final GroovySourceAST t, final int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitMultiCatchTypes(t, visit);}
+    }
+
     public void visitNls(GroovySourceAST t, int visit) {
         Iterator itr = itr(visit);
         while (itr.hasNext()) {((Visitor)itr.next()).visitNls(t,visit);}
Index: src/test/groovy/MultiCatchTest.groovy
===================================================================
--- src/test/groovy/MultiCatchTest.groovy	(revision )
+++ src/test/groovy/MultiCatchTest.groovy	(revision )
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2003-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package groovy
+
+class MultiCatchTest extends GroovyTestCase{
+
+    void testDynamicCatch() {
+        def catched = false
+        try {
+            throw new RuntimeException("Error")
+        } catch (e) {
+            catched = true
+        }
+        assert catched
+    }
+
+    void testRegularCatch() {
+        def catched = false
+        try {
+            throw new RuntimeException("Error")
+        } catch (RuntimeException ex) {
+            catched = true
+        }
+        assert catched
+    }
+
+    void testMultipleCatchJavaStyle() {
+        def catched = false
+        try {
+            throw new IOException("Error")
+        } catch (NullPointerException e) {
+            catched = false
+        } catch (IOException e) {
+            catched = true
+        }
+        assert catched
+    }
+
+    void testMultipleCatchGroovyStyle1() {
+        def catched = false
+        try {
+            throw new IOException("Error")
+        } catch (NullPointerException | IOException e) {
+            catched = true
+        }
+        assert catched
+    }
+
+    void testMultipleCatchGroovyStyle2() {
+        def catched = false
+        try {
+            throw new NullPointerException()
+        } catch (NullPointerException | IOException e) {
+            catched = true
+        }
+        assert catched
+    }
+
+    void testMultipleCatchGroovyStyle3() {
+        def catched = false
+        try {
+            throw new RuntimeException()
+        } catch (NullPointerException | IOException e) {
+            catched = false
+        } catch (RuntimeException e) {
+            catched = true
+        }
+        assert catched
+    }
+
+
+}
Index: src/main/org/codehaus/groovy/antlr/treewalker/TraversalHelper.java
===================================================================
--- src/main/org/codehaus/groovy/antlr/treewalker/TraversalHelper.java	(revision 20587)
+++ src/main/org/codehaus/groovy/antlr/treewalker/TraversalHelper.java	(revision )
@@ -203,6 +203,8 @@
                 case GroovyTokenTypes.NLS                           :   v.visitNls(ast,n);                          break;
                 case GroovyTokenTypes.NOT_EQUAL                     :   v.visitNotEqual(ast,n);                     break;
                 case GroovyTokenTypes.NULL_TREE_LOOKAHEAD           :   v.visitNullTreeLookahead(ast,n);            break;
+                case GroovyTokenTypes.MULTICATCH                    :   v.visitMultiCatch(ast,n);                   break;
+                case GroovyTokenTypes.MULTICATCH_TYPES              :   v.visitMultiCatchTypes(ast,n);              break;
                 case GroovyTokenTypes.NUM_BIG_DECIMAL               :   v.visitNumBigDecimal(ast,n);                break;
                 case GroovyTokenTypes.NUM_BIG_INT                   :   v.visitNumBigInt(ast,n);                    break;
                 case GroovyTokenTypes.NUM_DOUBLE                    :   v.visitNumDouble(ast,n);                    break;
Index: src/main/org/codehaus/groovy/antlr/treewalker/SourcePrinter.java
===================================================================
--- src/main/org/codehaus/groovy/antlr/treewalker/SourcePrinter.java	(revision 20587)
+++ src/main/org/codehaus/groovy/antlr/treewalker/SourcePrinter.java	(revision )
@@ -18,6 +18,7 @@
 import java.io.PrintStream;
 import java.util.Stack;
 
+import antlr.collections.AST;
 import org.codehaus.groovy.antlr.GroovySourceAST;
 import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
 
@@ -420,7 +421,7 @@
     }
 
     public void visitLiteralCatch(GroovySourceAST t,int visit) {
-        printUpdatingTabLevel(t,visit," catch (",null,") ");
+        printUpdatingTabLevel(t, visit, " catch (", null, ") ");
     }
 
     public void visitLiteralChar(GroovySourceAST t, int visit) {
@@ -666,6 +667,22 @@
         print(t,visit," %= ",null,null);
     }
 
+    @Override
+    public void visitMultiCatch(final GroovySourceAST t, final int visit) {
+        if (visit == CLOSING_VISIT) {
+            final AST child = t.getFirstChild();
+            if ("MULTICATCH_TYPES".equals(child.getText())) {
+                print(t, visit, null, null, " "+child.getNextSibling().getText());
+            } else {
+                print(t, visit, null, null, " "+child.getFirstChild().getText());
+            }
+        }
+    }
+
+    @Override
+    public void visitMultiCatchTypes(final GroovySourceAST t, final int visit) {
+    }
+
     // visitNls
     //   new lines are used by parser, but are not created on the AST,
     //   they can be implied by the source code line/column information
Index: src/main/org/codehaus/groovy/antlr/AntlrParserPlugin.java
===================================================================
--- src/main/org/codehaus/groovy/antlr/AntlrParserPlugin.java	(revision 21197)
+++ src/main/org/codehaus/groovy/antlr/AntlrParserPlugin.java	(revision )
@@ -1518,7 +1518,8 @@
         // let's do the catch nodes
         List<CatchStatement> catches = new ArrayList<CatchStatement>();
         for (; node != null && isType(LITERAL_catch, node); node = node.getNextSibling()) {
-            catches.add(catchStatement(node));
+            final List<CatchStatement> catchStatements = catchStatement(node);
+            catches.addAll(catchStatements);
         }
 
         if (isType(LITERAL_finally, node)) {
@@ -1538,18 +1539,38 @@
         return tryCatchStatement;
     }
 
-    protected CatchStatement catchStatement(AST catchNode) {
+    protected List<CatchStatement> catchStatement(AST catchNode) {
         AST node = catchNode.getFirstChild();
-        Parameter parameter = parameter(node);
-        ClassNode exceptionType = parameter.getType();
-        String variable = parameter.getName();
-        node = node.getNextSibling();
-        Statement code = statement(node);
+        List<CatchStatement> catches = new LinkedList<CatchStatement>();
+        Statement code = statement(node.getNextSibling());
+        if (MULTICATCH == node.getType()) {
+            AST variableNode = node.getNextSibling();
+            final AST multicatches = node.getFirstChild();
+            if (multicatches.getType()!=MULTICATCH_TYPES) {
+                // catch (e)
+                // catch (def e)
+                String variable = identifier(multicatches);
+                Parameter catchParameter = new Parameter(ClassHelper.DYNAMIC_TYPE, variable);
+                CatchStatement answer = new CatchStatement(catchParameter, code);
+                configureAST(answer, catchNode);
+                catches.add(answer);
+            } else {
+                // catch (Exception e)
+                // catch (Exception1 | Exception2 e)
+                AST exceptionNodes = multicatches.getFirstChild();
+                String variable = identifier(multicatches.getNextSibling());
+                while (exceptionNodes != null) {
+                    ClassNode exceptionType = buildName(exceptionNodes);
-        Parameter catchParameter = new Parameter(exceptionType, variable);
-        CatchStatement answer = new CatchStatement(catchParameter, code);
-        configureAST(answer, catchNode);
+                    Parameter catchParameter = new Parameter(exceptionType, variable);
+                    CatchStatement answer = new CatchStatement(catchParameter, code);
+                    configureAST(answer, catchNode);
-        return answer;
+                    catches.add(answer);
+                    exceptionNodes = exceptionNodes.getNextSibling();
-    }
+                }
+            }
+        }
+        return catches;
+    }
 
     protected Statement whileStatement(AST whileNode) {
         AST node = whileNode.getFirstChild();
Index: src/main/org/codehaus/groovy/antlr/treewalker/VisitorAdapter.java
===================================================================
--- src/main/org/codehaus/groovy/antlr/treewalker/VisitorAdapter.java	(revision 21223)
+++ src/main/org/codehaus/groovy/antlr/treewalker/VisitorAdapter.java	(revision )
@@ -168,6 +168,8 @@
     public void visitMod(GroovySourceAST t,int visit) {visitDefault(t,visit);}
     public void visitModifiers(GroovySourceAST t,int visit) {visitDefault(t,visit);}
     public void visitModAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitMultiCatch(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitMultiCatchTypes(GroovySourceAST t,int visit) {visitDefault(t,visit);}
     public void visitNls(GroovySourceAST t,int visit) {visitDefault(t,visit);}
     public void visitNotEqual(GroovySourceAST t,int visit) {visitDefault(t,visit);}
     public void visitNullTreeLookahead(GroovySourceAST t,int visit) {visitDefault(t,visit);}
Index: src/main/org/codehaus/groovy/antlr/treewalker/Visitor.java
===================================================================
--- src/main/org/codehaus/groovy/antlr/treewalker/Visitor.java	(revision 19543)
+++ src/main/org/codehaus/groovy/antlr/treewalker/Visitor.java	(revision )
@@ -170,6 +170,8 @@
     void visitMod(GroovySourceAST t, int visit);
     void visitModifiers(GroovySourceAST t, int visit);
     void visitModAssign(GroovySourceAST t, int visit);
+    void visitMultiCatch(GroovySourceAST t, int visit);
+    void visitMultiCatchTypes(GroovySourceAST t, int visit);
     void visitNls(GroovySourceAST t, int visit);
     void visitNotEqual(GroovySourceAST t, int visit);
     void visitNullTreeLookahead(GroovySourceAST t, int visit);
Index: src/main/org/codehaus/groovy/antlr/groovy.g
===================================================================
--- src/main/org/codehaus/groovy/antlr/groovy.g	(revision 21345)
+++ src/main/org/codehaus/groovy/antlr/groovy.g	(revision )
@@ -226,7 +226,7 @@
     STATIC_IMPORT; ENUM_DEF; ENUM_CONSTANT_DEF; FOR_EACH_CLAUSE; ANNOTATION_DEF; ANNOTATIONS;
     ANNOTATION; ANNOTATION_MEMBER_VALUE_PAIR; ANNOTATION_FIELD_DEF; ANNOTATION_ARRAY_INIT;
     TYPE_ARGUMENTS; TYPE_ARGUMENT; TYPE_PARAMETERS; TYPE_PARAMETER; WILDCARD_TYPE;
-    TYPE_UPPER_BOUNDS; TYPE_LOWER_BOUNDS; CLOSURE_LIST;
+    TYPE_UPPER_BOUNDS; TYPE_LOWER_BOUNDS; CLOSURE_LIST;MULTICATCH;MULTICATCH_TYPES;
 }
 
 {
@@ -1660,6 +1660,26 @@
         }
     ;
 
+multicatch_types
+{Token first = LT(1);}
+    :
+        nls!
+        classOrInterfaceType[false]
+        (
+            BOR! nls! classOrInterfaceType[false]
+        )*
+        
+        {#multicatch_types = #(create(MULTICATCH_TYPES, "MULTICATCH_TYPES",first,LT(1)), #multicatch_types);}
+    ;
+		    
+multicatch
+{Token first = LT(1);}
+    :    nls! ("def")? (m:multicatch_types)? id:IDENT!
+        {
+          #multicatch = #(create(MULTICATCH,"MULTICATCH",first, LT(1)),m,id);
+        }
+    ;
+
 /*OBS*
 variableLengthParameterDeclaration!  {Token first = LT(1);}
     :   pm:parameterModifier t:typeSpec[false] TRIPLE_DOT! id:IDENT
@@ -2175,7 +2195,7 @@
 
 // an exception handler
 handler {Token first = LT(1);}
-    :   "catch"! LPAREN! pd:parameterDeclaration! RPAREN! nlsWarn! handlerCs:compoundStatement!
+    :   "catch"! LPAREN! pd:multicatch! RPAREN! nlsWarn! handlerCs:compoundStatement!
         {#handler = #(create(LITERAL_catch,"catch",first,LT(1)),pd,handlerCs);}
     ;
 
