private void funcExtract() throws Exception {

        //Add each and every function contents to an ArrayList.
        //Replace #func[...] with @ + ArrayList index.
        //loopForAllHashes:
        while (exp.contains("#")) {
            //Function starts with a hash sign.
            int hashIndex = exp.indexOf("#");

            if (exp.indexOf('[') == -1 || exp.indexOf('[') < hashIndex) {
                throw new Exception("Cannot find arguments to the function");
            }

            //Using opened square braces count in case of nested functions.
            int openBracks = 0;

            //hashIndex + 2 because at least 1 letter for a function.
            //loopForAHash:
            for (int i = hashIndex + 2; i < exp.length(); i++) {

                //Opening [
                if (exp.charAt(i) == '[') {
                    openBracks++;

                    //Closing ]
                } else if (exp.charAt(i) == ']') {
                    openBracks--;

                    //All square braces closed.
                    if (openBracks == 0) {
                        //Add function to ArrayList.
                        func.add(exp.substring(hashIndex, i + 1));
                        //Replace function with ArrayList index coding. "@" + ix
                        //Regex again.(mona magulakda) Quote with \Q and \E,
                        //so square brackets are not misinterpreted.
                        exp = exp.replaceFirst(
                                "\\Q" + func.get(func.size() - 1) + "\\E",
                                "@" + (func.size() - 1)
                        );

                        break;
                    }
                }
            }

            //Every opened square bracket must be closed
            if (openBracks != 0) {
                throw new Exception("Cannot find matching "
                        + "closing square bracket or invalid function name: "
                        + exp.substring(hashIndex));
            }
        }

    }