private ParserImpl parseFunctionDeclaration(final IScope scope) throws IOException
    {
        return new ParserImpl() {

            @Override
            public String toString()
            {
                return "parseFunctionDeclaration";
            }

            @Override
            protected ASTNode doParse() throws Exception
            {
                boolean isExtern = false;

                ITextRegion region = new TextRegion(lexer.peek());
                if ( lexer.peek(TokenType.EXTERN ) ) 
                {
                    region.merge( lexer.read() );
                    isExtern = true;
                }

                // parse return type
                DataType returnType = parseDataType( scope , region );

                if ( lexer.peek(TokenType.ANGLE_BRACKETS_OPEN ) ) {
                    region.merge(lexer.read());
                    region.merge(lexer.read(TokenType.ANGLE_BRACKETS_CLOSE ) );
                    returnType = DataType.getDataType( returnType.getIdentifier() , true , returnType.getPtrCount() );
                }				

                // parse function name
                Token tok = lexer.read(TokenType.IDENTIFIER);

                final Identifier functionName = new Identifier( tok );

                if ( scope.isFunctionDefined( functionName) ) {
                    throw new ParseException("Function already defined" , tok.getOffset() );
                }                

                FunctionDeclarationNode result = new FunctionDeclarationNode( scope , functionName , isExtern, returnType , tok.getTextRegion() );

                // parse function parameters
                lexer.read(TokenType.PARENS_OPEN);

                if ( ! lexer.peek( TokenType.PARENS_CLOSE ) ) 
                {
                    do 
                    {
                        if ( ! parseFunctionParameter( result.getScope() ).parse() ) 
                        {
                            throw new ParseException("Expected parameter declaration",lexer.currentOffset());
                        }
                        ParameterDeclaration decl = (ParameterDeclaration) lastResult;
                        result.getScope().defineVariable( decl );

                        result.addChild( lastResult );

                        if ( ! lexer.peek( TokenType.COMMA ) ) {
                            break;
                        } 
                        lexer.read(TokenType.COMMA);
                    } while(true);
                }

                lexer.read(TokenType.PARENS_CLOSE);

                lexer.read(TokenType.SEMICOLON);
                result.addChild( lastResult );
                return result;
            }
        };
    }