private <V> TreeNode<V> atom(
		final Parser<T> parser,
		final TokenConverter<? super T, ? extends V> mapper
	) {
		final var token = parser.LT(1);

		if (_identifiers.test(token)) {
			parser.consume();
			return TreeNode.of(mapper.convert(token, TokenType.IDENTIFIER));
		} else if (token == null) {
			throw new ParsingException("Unexpected end of input.");
		} else {
			throw new ParsingException(
				"Unexpected symbol found: %s.".formatted(parser.LT(1))
			);
		}
	}
Creates a new general expression parser object. The parser is not bound
to a specific source and target type or concrete token types.

@param lparen the token type specifying the left parentheses, '('
@param rparen the token type specifying the right parentheses, ')'
@param separator the token type specifying the function parameter
       separator, ','
@param bops the list of binary operators, according its
       precedence. The first list element contains the operations with
       the lowest precedence, and the last list element contains the
       operations with the highest precedence.
@param uops the token types representing the unary operations
@param identifiers the token type representing identifier, like variable
       names, constants or numbers
@param functions predicate which tests whether a given identifier value
       represents a known function name
jenetics.ext/src/main/java/io/jenetics/ext/internal/util/FormulaParser.java