//throws RecognitionException, TokenStreamException
        public void template(
            StringTemplateGroup g
            )
        {
            IToken  scope = null;
            IToken  region = null;
            IToken  name = null;
            IToken  t = null;
            IToken  bt = null;
            IToken  alias = null;
            IToken  target = null;

            StringTemplate st = null;
            string templateName=null;
            int line = LT(1).getLine();

            try {      // for error handling
            if ((LA(1)==ID||LA(1)==AT) && (LA(2)==ID||LA(2)==LPAREN))
            {
                {
                    switch ( LA(1) )
                    {
                    case AT:
                    {
                        match(AT);
                        scope = LT(1);
                        match(ID);
                        match(DOT);
                        region = LT(1);
                        match(ID);

                                    templateName=g.GetMangledRegionName(scope.getText(),region.getText());
                                    if ( g.IsDefinedInThisGroup(templateName) ) {
                                        g.Error("group "+g.Name+" line "+line+": redefinition of template region: @"+
                                            scope.getText()+"."+region.getText());
                                        st = new StringTemplate(); // create bogus template to fill in
                                    }
                                    else {
                                        bool err = false;
                                        // @template.region() ::= "..."
                                        StringTemplate scopeST = g.LookupTemplate(scope.getText());
                                        if ( scopeST==null ) {
                                            g.Error("group "+g.Name+" line "+line+": reference to region within undefined template: "+
                                                scope.getText());
                                            err=true;
                                        }
                                        if ( !scopeST.ContainsRegionName(region.getText()) ) {
                                            g.Error("group "+g.Name+" line "+line+": template "+scope.getText()+" has no region called "+
                                                region.getText());
                                            err=true;
                                        }
                                        if ( err ) {
                                            st = new StringTemplate();
                                        }
                                        else {
                                            st = g.DefineRegionTemplate(scope.getText(),
                                                                        region.getText(),
                                                                        null,
                                                                        StringTemplate.REGION_EXPLICIT);
                                        }
                                    }

                        break;
                    }
                    case ID:
                    {
                        name = LT(1);
                        match(ID);
                        templateName = name.getText();

                                if ( g.IsDefinedInThisGroup(templateName) ) {
                                    g.Error("redefinition of template: "+templateName);
                                    st = new StringTemplate(); // create bogus template to fill in
                                }
                                else {
                                    st = g.DefineTemplate(templateName, null);
                                }

                        break;
                    }
                    default:
                    {
                        throw new NoViableAltException(LT(1), getFilename());
                    }
                     }
                }
                if ( st!=null ) {st.GroupFileLine = line;}
                match(LPAREN);
                {
                    switch ( LA(1) )
                    {
                    case ID:
                    {
                        args(st);
                        break;
                    }
                    case RPAREN:
                    {
                        st.DefineEmptyFormalArgumentList();
                        break;
                    }
                    default:
                    {
                        throw new NoViableAltException(LT(1), getFilename());
                    }
                     }
                }
                match(RPAREN);
                match(DEFINED_TO_BE);
                {
                    switch ( LA(1) )
                    {
                    case STRING:
                    {
                        t = LT(1);
                        match(STRING);
                        st.Template = t.getText();
                        break;
                    }
                    case BIGSTRING:
                    {
                        bt = LT(1);
                        match(BIGSTRING);
                        st.Template = bt.getText();
                        break;
                    }
                    default:
                    {
                        throw new NoViableAltException(LT(1), getFilename());
                    }
                     }
                }
            }
            else if ((LA(1)==ID) && (LA(2)==DEFINED_TO_BE)) {
                alias = LT(1);
                match(ID);
                match(DEFINED_TO_BE);
                target = LT(1);
                match(ID);
                g.DefineTemplateAlias(alias.getText(), target.getText());
            }
            else
            {
                throw new NoViableAltException(LT(1), getFilename());
            }

            }
            catch (RecognitionException ex)
            {
            reportError(ex);
            recover(ex,tokenSet_1_);
            }
        }