public final AntlrPilarParser.procedureDeclaration_return procedureDeclaration()
      throws RecognitionException {
    AntlrPilarParser.procedureDeclaration_return retval = new AntlrPilarParser.procedureDeclaration_return();
    retval.start = input.LT(1);
    int procedureDeclaration_StartIndex = input.index();
    Object root_0 = null;

    Token t = null;
    Token p = null;
    Token char_literal120 = null;
    Token char_literal123 = null;
    Token char_literal125 = null;
    AntlrPilarParser.typeVarTuple_return typeVarTuple118 = null;

    AntlrPilarParser.type_return type119 = null;

    AntlrPilarParser.paramVariable_return paramVariable121 = null;

    AntlrPilarParser.paramList_return paramList122 = null;

    AntlrPilarParser.paramVariable_return paramVariable124 = null;

    AntlrPilarParser.annotationList_return annotationList126 = null;

    AntlrPilarParser.body_return body127 = null;

    Object t_tree = null;
    Object p_tree = null;
    Object char_literal120_tree = null;
    Object char_literal123_tree = null;
    Object char_literal125_tree = null;
    RewriteRuleTokenStream stream_170 = new RewriteRuleTokenStream(adaptor,
        "token 170");
    RewriteRuleTokenStream stream_184 = new RewriteRuleTokenStream(adaptor,
        "token 184");
    RewriteRuleTokenStream stream_172 = new RewriteRuleTokenStream(adaptor,
        "token 172");
    RewriteRuleTokenStream stream_ID = new RewriteRuleTokenStream(adaptor,
        "token ID");
    RewriteRuleTokenStream stream_169 = new RewriteRuleTokenStream(adaptor,
        "token 169");
    RewriteRuleSubtreeStream stream_body = new RewriteRuleSubtreeStream(
        adaptor, "rule body");
    RewriteRuleSubtreeStream stream_annotationList = new RewriteRuleSubtreeStream(
        adaptor, "rule annotationList");
    RewriteRuleSubtreeStream stream_paramList = new RewriteRuleSubtreeStream(
        adaptor, "rule paramList");
    RewriteRuleSubtreeStream stream_paramVariable = new RewriteRuleSubtreeStream(
        adaptor, "rule paramVariable");
    RewriteRuleSubtreeStream stream_typeVarTuple = new RewriteRuleSubtreeStream(
        adaptor, "rule typeVarTuple");
    RewriteRuleSubtreeStream stream_type = new RewriteRuleSubtreeStream(
        adaptor, "rule type");
    try {
      if (state.backtracking > 0 && alreadyParsedRule(input, 36)) {
        return retval;
      }
      // /Users/robby/Repositories/sireum-parser/sireum-parser/src/main/java/org/sireum/pilar/parser/AntlrPilar.g:336:2: (t= 'procedure' ( typeVarTuple )? ( type )? p= ID ( '(' ( paramVariable | ( paramList ( ',' paramVariable )? )? ) ')' )? annotationList body -> ^( PROCEDURE[$t] ^( OPTION ( typeVarTuple )? ) ^( OPTION ( type )? ) $p ^( LIST ( paramList )? ( paramVariable )? ) annotationList body ) )
      // /Users/robby/Repositories/sireum-parser/sireum-parser/src/main/java/org/sireum/pilar/parser/AntlrPilar.g:336:4: t= 'procedure' ( typeVarTuple )? ( type )? p= ID ( '(' ( paramVariable | ( paramList ( ',' paramVariable )? )? ) ')' )? annotationList body
      {
        t = (Token) match(input, 184, FOLLOW_184_in_procedureDeclaration2644);
        if (state.failed) return retval;
        if (state.backtracking == 0) stream_184.add(t);

        // /Users/robby/Repositories/sireum-parser/sireum-parser/src/main/java/org/sireum/pilar/parser/AntlrPilar.g:336:18: ( typeVarTuple )?
        int alt32 = 2;
        int LA32_0 = input.LA(1);

        if ((LA32_0 == 167)) {
          alt32 = 1;
        }
        switch (alt32) {
          case 1:
          // /Users/robby/Repositories/sireum-parser/sireum-parser/src/main/java/org/sireum/pilar/parser/AntlrPilar.g:0:0: typeVarTuple
          {
            pushFollow(FOLLOW_typeVarTuple_in_procedureDeclaration2646);
            typeVarTuple118 = typeVarTuple();

            state._fsp--;
            if (state.failed) return retval;
            if (state.backtracking == 0)
              stream_typeVarTuple.add(typeVarTuple118.getTree());

          }
            break;

        }

        // /Users/robby/Repositories/sireum-parser/sireum-parser/src/main/java/org/sireum/pilar/parser/AntlrPilar.g:337:4: ( type )?
        int alt33 = 2;
        int LA33_0 = input.LA(1);

        if ((LA33_0 == TYPEVARID || LA33_0 == 169 || LA33_0 == 177)) {
          alt33 = 1;
        } else if ((LA33_0 == ID)) {
          int LA33_2 = input.LA(2);

          if ((LA33_2 == ID || LA33_2 == 167 || LA33_2 == 202
              || (LA33_2 >= 215 && LA33_2 <= 216) || LA33_2 == 225)) {
            alt33 = 1;
          } else if ((LA33_2 == 177)) {
            int LA33_3 = input.LA(3);

            if ((LA33_3 == 178)) {
              alt33 = 1;
            }
          }
        }
        switch (alt33) {
          case 1:
          // /Users/robby/Repositories/sireum-parser/sireum-parser/src/main/java/org/sireum/pilar/parser/AntlrPilar.g:0:0: type
          {
            pushFollow(FOLLOW_type_in_procedureDeclaration2652);
            type119 = type();

            state._fsp--;
            if (state.failed) return retval;
            if (state.backtracking == 0) stream_type.add(type119.getTree());

          }
            break;

        }

        p = (Token) match(input, ID, FOLLOW_ID_in_procedureDeclaration2661);
        if (state.failed) return retval;
        if (state.backtracking == 0) stream_ID.add(p);

        // /Users/robby/Repositories/sireum-parser/sireum-parser/src/main/java/org/sireum/pilar/parser/AntlrPilar.g:339:4: ( '(' ( paramVariable | ( paramList ( ',' paramVariable )? )? ) ')' )?
        int alt37 = 2;
        int LA37_0 = input.LA(1);

        if ((LA37_0 == 169)) {
          alt37 = 1;
        }
        switch (alt37) {
          case 1:
          // /Users/robby/Repositories/sireum-parser/sireum-parser/src/main/java/org/sireum/pilar/parser/AntlrPilar.g:339:6: '(' ( paramVariable | ( paramList ( ',' paramVariable )? )? ) ')'
          {
            char_literal120 = (Token) match(
                input,
                169,
                FOLLOW_169_in_procedureDeclaration2668);
            if (state.failed) return retval;
            if (state.backtracking == 0) stream_169.add(char_literal120);

            // /Users/robby/Repositories/sireum-parser/sireum-parser/src/main/java/org/sireum/pilar/parser/AntlrPilar.g:340:6: ( paramVariable | ( paramList ( ',' paramVariable )? )? )
            int alt36 = 2;
            switch (input.LA(1)) {
              case TYPEVARID: {
                int LA36_1 = input.LA(2);

                if ((synpred42_AntlrPilar())) {
                  alt36 = 1;
                } else if ((true)) {
                  alt36 = 2;
                } else {
                  if (state.backtracking > 0) {
                    state.failed = true;
                    return retval;
                  }
                  NoViableAltException nvae = new NoViableAltException("", 36,
                      1, input);

                  throw nvae;
                }
              }
                break;
              case ID: {
                int LA36_2 = input.LA(2);

                if ((synpred42_AntlrPilar())) {
                  alt36 = 1;
                } else if ((true)) {
                  alt36 = 2;
                } else {
                  if (state.backtracking > 0) {
                    state.failed = true;
                    return retval;
                  }
                  NoViableAltException nvae = new NoViableAltException("", 36,
                      2, input);

                  throw nvae;
                }
              }
                break;
              case 169: {
                int LA36_3 = input.LA(2);

                if ((synpred42_AntlrPilar())) {
                  alt36 = 1;
                } else if ((true)) {
                  alt36 = 2;
                } else {
                  if (state.backtracking > 0) {
                    state.failed = true;
                    return retval;
                  }
                  NoViableAltException nvae = new NoViableAltException("", 36,
                      3, input);

                  throw nvae;
                }
              }
                break;
              case 177: {
                int LA36_4 = input.LA(2);

                if ((synpred42_AntlrPilar())) {
                  alt36 = 1;
                } else if ((true)) {
                  alt36 = 2;
                } else {
                  if (state.backtracking > 0) {
                    state.failed = true;
                    return retval;
                  }
                  NoViableAltException nvae = new NoViableAltException("", 36,
                      4, input);

                  throw nvae;
                }
              }
                break;
              case 170: {
                alt36 = 2;
              }
                break;
              default:
                if (state.backtracking > 0) {
                  state.failed = true;
                  return retval;
                }
                NoViableAltException nvae = new NoViableAltException("", 36, 0,
                    input);

                throw nvae;
            }

            switch (alt36) {
              case 1:
              // /Users/robby/Repositories/sireum-parser/sireum-parser/src/main/java/org/sireum/pilar/parser/AntlrPilar.g:340:8: paramVariable
              {
                pushFollow(FOLLOW_paramVariable_in_procedureDeclaration2678);
                paramVariable121 = paramVariable();

                state._fsp--;
                if (state.failed) return retval;
                if (state.backtracking == 0)
                  stream_paramVariable.add(paramVariable121.getTree());

              }
                break;
              case 2:
              // /Users/robby/Repositories/sireum-parser/sireum-parser/src/main/java/org/sireum/pilar/parser/AntlrPilar.g:341:8: ( paramList ( ',' paramVariable )? )?
              {
                // /Users/robby/Repositories/sireum-parser/sireum-parser/src/main/java/org/sireum/pilar/parser/AntlrPilar.g:341:8: ( paramList ( ',' paramVariable )? )?
                int alt35 = 2;
                int LA35_0 = input.LA(1);

                if (((LA35_0 >= ID && LA35_0 <= TYPEVARID) || LA35_0 == 169 || LA35_0 == 177)) {
                  alt35 = 1;
                }
                switch (alt35) {
                  case 1:
                  // /Users/robby/Repositories/sireum-parser/sireum-parser/src/main/java/org/sireum/pilar/parser/AntlrPilar.g:341:10: paramList ( ',' paramVariable )?
                  {
                    pushFollow(FOLLOW_paramList_in_procedureDeclaration2689);
                    paramList122 = paramList();

                    state._fsp--;
                    if (state.failed) return retval;
                    if (state.backtracking == 0)
                      stream_paramList.add(paramList122.getTree());
                    // /Users/robby/Repositories/sireum-parser/sireum-parser/src/main/java/org/sireum/pilar/parser/AntlrPilar.g:342:12: ( ',' paramVariable )?
                    int alt34 = 2;
                    int LA34_0 = input.LA(1);

                    if ((LA34_0 == 172)) {
                      alt34 = 1;
                    }
                    switch (alt34) {
                      case 1:
                      // /Users/robby/Repositories/sireum-parser/sireum-parser/src/main/java/org/sireum/pilar/parser/AntlrPilar.g:342:14: ',' paramVariable
                      {
                        char_literal123 = (Token) match(
                            input,
                            172,
                            FOLLOW_172_in_procedureDeclaration2705);
                        if (state.failed) return retval;
                        if (state.backtracking == 0)
                          stream_172.add(char_literal123);

                        pushFollow(FOLLOW_paramVariable_in_procedureDeclaration2707);
                        paramVariable124 = paramVariable();

                        state._fsp--;
                        if (state.failed) return retval;
                        if (state.backtracking == 0)
                          stream_paramVariable.add(paramVariable124.getTree());

                      }
                        break;

                    }

                  }
                    break;

                }

              }
                break;

            }

            char_literal125 = (Token) match(
                input,
                170,
                FOLLOW_170_in_procedureDeclaration2727);
            if (state.failed) return retval;
            if (state.backtracking == 0) stream_170.add(char_literal125);

          }
            break;

        }

        pushFollow(FOLLOW_annotationList_in_procedureDeclaration2736);
        annotationList126 = annotationList();

        state._fsp--;
        if (state.failed) return retval;
        if (state.backtracking == 0)
          stream_annotationList.add(annotationList126.getTree());
        pushFollow(FOLLOW_body_in_procedureDeclaration2741);
        body127 = body();

        state._fsp--;
        if (state.failed) return retval;
        if (state.backtracking == 0) stream_body.add(body127.getTree());

        // AST REWRITE
        // elements: paramList, type, body, p, paramVariable, typeVarTuple, annotationList
        // token labels: p
        // rule labels: retval
        // token list labels: 
        // rule list labels: 
        // wildcard labels: 
        if (state.backtracking == 0) {
          retval.tree = root_0;
          RewriteRuleTokenStream stream_p = new RewriteRuleTokenStream(adaptor,
              "token p", p);
          RewriteRuleSubtreeStream stream_retval = new RewriteRuleSubtreeStream(
              adaptor, "rule retval", retval != null ? retval.tree : null);

          root_0 = (Object) adaptor.nil();
          // 346:41: -> ^( PROCEDURE[$t] ^( OPTION ( typeVarTuple )? ) ^( OPTION ( type )? ) $p ^( LIST ( paramList )? ( paramVariable )? ) annotationList body )
          {
            // /Users/robby/Repositories/sireum-parser/sireum-parser/src/main/java/org/sireum/pilar/parser/AntlrPilar.g:346:44: ^( PROCEDURE[$t] ^( OPTION ( typeVarTuple )? ) ^( OPTION ( type )? ) $p ^( LIST ( paramList )? ( paramVariable )? ) annotationList body )
            {
              Object root_1 = (Object) adaptor.nil();
              root_1 = (Object) adaptor.becomeRoot(
                  (Object) adaptor.create(PROCEDURE, t),
                  root_1);

              // /Users/robby/Repositories/sireum-parser/sireum-parser/src/main/java/org/sireum/pilar/parser/AntlrPilar.g:346:60: ^( OPTION ( typeVarTuple )? )
              {
                Object root_2 = (Object) adaptor.nil();
                root_2 = (Object) adaptor.becomeRoot(
                    (Object) adaptor.create(OPTION, "OPTION"),
                    root_2);

                // /Users/robby/Repositories/sireum-parser/sireum-parser/src/main/java/org/sireum/pilar/parser/AntlrPilar.g:346:69: ( typeVarTuple )?
                if (stream_typeVarTuple.hasNext()) {
                  adaptor.addChild(root_2, stream_typeVarTuple.nextTree());

                }
                stream_typeVarTuple.reset();

                adaptor.addChild(root_1, root_2);
              }
              // /Users/robby/Repositories/sireum-parser/sireum-parser/src/main/java/org/sireum/pilar/parser/AntlrPilar.g:346:84: ^( OPTION ( type )? )
              {
                Object root_2 = (Object) adaptor.nil();
                root_2 = (Object) adaptor.becomeRoot(
                    (Object) adaptor.create(OPTION, "OPTION"),
                    root_2);

                // /Users/robby/Repositories/sireum-parser/sireum-parser/src/main/java/org/sireum/pilar/parser/AntlrPilar.g:346:93: ( type )?
                if (stream_type.hasNext()) {
                  adaptor.addChild(root_2, stream_type.nextTree());

                }
                stream_type.reset();

                adaptor.addChild(root_1, root_2);
              }
              adaptor.addChild(root_1, stream_p.nextNode());
              // /Users/robby/Repositories/sireum-parser/sireum-parser/src/main/java/org/sireum/pilar/parser/AntlrPilar.g:346:103: ^( LIST ( paramList )? ( paramVariable )? )
              {
                Object root_2 = (Object) adaptor.nil();
                root_2 = (Object) adaptor.becomeRoot(
                    (Object) adaptor.create(LIST, "LIST"),
                    root_2);

                // /Users/robby/Repositories/sireum-parser/sireum-parser/src/main/java/org/sireum/pilar/parser/AntlrPilar.g:346:110: ( paramList )?
                if (stream_paramList.hasNext()) {
                  adaptor.addChild(root_2, stream_paramList.nextTree());

                }
                stream_paramList.reset();
                // /Users/robby/Repositories/sireum-parser/sireum-parser/src/main/java/org/sireum/pilar/parser/AntlrPilar.g:346:121: ( paramVariable )?
                if (stream_paramVariable.hasNext()) {
                  adaptor.addChild(root_2, stream_paramVariable.nextTree());

                }
                stream_paramVariable.reset();

                adaptor.addChild(root_1, root_2);
              }
              adaptor.addChild(root_1, stream_annotationList.nextTree());
              adaptor.addChild(root_1, stream_body.nextTree());

              adaptor.addChild(root_0, root_1);
            }

          }

          retval.tree = root_0;
        }
      }

      retval.stop = input.LT(-1);

      if (state.backtracking == 0) {

        retval.tree = (Object) adaptor.rulePostProcessing(root_0);
        adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop);
      }
    } catch (RecognitionException re) {
      reportError(re);
      recover(input, re);
      retval.tree = (Object) adaptor.errorNode(
          input,
          retval.start,
          input.LT(-1),
          re);

    } finally {
      if (state.backtracking > 0) {
        memoize(input, 36, procedureDeclaration_StartIndex);
      }
    }
    return retval;
  }