private LN parseInnerNode() {
		skipWhitespace();

		// expect + consume '('
		if (inputA[ptr] != '(') {
			throw new RuntimeException(
					"parse error: parseInnerNode expects '(' at " + ptr);
		}
		ptr++;

		// parse left node + branch length
		LN nl = parseNode();
		double l1 = parseBranchLength();
		String label1 = parseBranchLabel();

		skipWhitespace();

		// expect + consume ','
		if (inputA[ptr] != ',') {
			printLocation();
			throw new RuntimeException(
					"parse error: parseInnerNode expects ',' at " + ptr);
		}
		ptr++;

		// parse right node + branch length
		LN nr = parseNode();
		double l2 = parseBranchLength();
		String label2 = parseBranchLabel();

		skipWhitespace();

		nInnerNodes++;

		if (inputA[ptr] == ')') {
			// 'normal' inner node: two childs
			ptr++;

			final double support;
			String nodeLabel = null;
			//
			// while( inputA[ptr] != ':' && inputA[ptr] != ',' && inputA[ptr] !=
			// ')' && inputA[ptr] != ';' ) {
			//
			// ptr++;
			// }

			// the stuff between the closing ')' and the ':' of the branch
			// length (or a ',' or the terminating ';')
			// is interpreted as node-label. If the node label corresponds to a
			// float value
			// it is interpreted as branch support (or node support as a
			// rooted-trees-only-please biologist would say)
			int lend = findEndOfBranch(ptr);

			nodeLabel = substring(ptr, lend);
			ptr = lend;
			// System.out.printf( "node label: %s\n", nodeLabel);
			// if( inputA[ptr] == ';') {
			// // oh my god. a fucking rooted tree
			// double sup = Math.max( nl.data.getSupport(),
			// nr.data.getSupport());
			// //System.out.printf( "rooted shit: %s %s %f %f %f %f\n", label1,
			// label2, nl.data.getSupport(), nr.data.getSupport(), l1, l2);
			// twiddle( nl, nr, l1 + l2, label1, sup );
			//
			// return nl;
			// }

			boolean isDigit = nodeLabel.length() != 0;
			for (int i = 0; i < nodeLabel.length(); i++) {
				isDigit &= Character.isDigit(nodeLabel.charAt(i));

				if (i == 0) {
					isDigit &= (nodeLabel.charAt(i) != '0');
				}
			}

			if (isDigit) {
				try {
					support = Double.parseDouble(nodeLabel);
				} catch (NumberFormatException e) {
					printLocation();
					throw e;
				}
			} else {

				support = -1;
			}

			// int lend = findFloat(ptr);
			// if (lend == ptr) {
			// printLocation();
			// throw new RuntimeException("missing float number at " + ptr);
			// }
			//
			// support = Double.parseDouble(substring(ptr, lend));
			// ptr = lend;

			LN n = LN.create();
			n.data.setSupport(support);
			n.data.setNodeLabel(nodeLabel);

			twiddle(nl, n.next, l1, label1, nl.data.getSupport());
			twiddle(nr, n.next.next, l2, label2, nr.data.getSupport());

			return n;
		} else if (inputA[ptr] == ',') {
			// second comma found: three child nodes == pseudo root
			ptr++;

			LN nx = parseNode();

			double l3 = parseBranchLength();
			String label3 = parseBranchLabel();
			// System.out.printf( "l3: %s\n", nx.data.getTipName() );
			skipWhitespace();

			if (inputA[ptr] != ')') {
				printLocation();
				throw new RuntimeException(
						"parse error: parseInnerNode (at root) expects ') at "
								+ ptr);
			}
			ptr++;
			skipWhitespace();

			LN n = LN.create();

			twiddle(nl, n.next, l1, label1, nl.data.getSupport());
			twiddle(nr, n.next.next, l2, label2, nr.data.getSupport());
			twiddle(nx, n, l3, label3, nx.data.getSupport());

			// System.out.printf( "root: %f %f %f\n", nl.data.getSupport(),
			// nr.data.getSupport(), nx.data.getSupport() );
			// System.exit(0);
			return n;
		} else {
			printLocation();
			throw new RuntimeException(
					"parse error: parseInnerNode expects ')'or ',' at " + ptr);
		}

	}