in poi/src/main/java/org/apache/poi/ss/formula/FormulaParser.java [466:584]
private ParseNode parseRangeable() {
skipWhite();
int savePointer = _pointer;
SheetIdentifier sheetIden = parseSheetName(false);
if (sheetIden == null) {
resetPointer(savePointer);
} else {
skipWhite();
savePointer = _pointer;
}
SimpleRangePart part1 = parseSimpleRangePart();
if (part1 == null) {
if (sheetIden != null) {
if(look == '#'){ // error ref like MySheet!#REF!
return new ParseNode(ErrPtg.valueOf(parseErrorLiteral()));
} else {
// Is it a named range?
String name = parseAsName();
if (name.length() == 0) {
throw new FormulaParseException("Cell reference or Named Range "
+ "expected after sheet name at index " + _pointer + ".");
}
Ptg nameXPtg = _book.getNameXPtg(name, sheetIden);
if (nameXPtg == null) {
throw new FormulaParseException("Specified name '" + name +
"' for sheet " + sheetIden.asFormulaString() + " not found");
}
return new ParseNode(nameXPtg);
}
}
return parseNonRange(savePointer);
}
boolean whiteAfterPart1 = isWhite(look);
if (whiteAfterPart1) {
skipWhite();
}
if (look == ':') {
int colonPos = _pointer;
nextChar();
skipWhite();
SimpleRangePart part2 = parseSimpleRangePart();
if (part2 != null && !part1.isCompatibleForArea(part2)) {
// second part is not compatible with an area ref e.g. S!A1:S!B2
// where S might be a sheet name (that looks like a column name)
part2 = null;
}
if (part2 == null) {
// second part is not compatible with an area ref e.g. A1:OFFSET(B2, 1, 2)
// reset and let caller use explicit range operator
resetPointer(colonPos);
if (!part1.isCell()) {
String prefix = "";
if (sheetIden != null) {
prefix = "'" + sheetIden.getSheetIdentifier().getName() + '!';
}
throw new FormulaParseException(prefix + part1.getRep() + "' is not a proper reference.");
}
}
return createAreaRefParseNode(sheetIden, part1, part2);
}
if (look == '.') {
nextChar();
int dotCount = 1;
while (look =='.') {
dotCount ++;
nextChar();
}
boolean whiteBeforePart2 = isWhite(look);
skipWhite();
SimpleRangePart part2 = parseSimpleRangePart();
String part1And2 = _formulaString.substring(savePointer-1, _pointer-1);
if (part2 == null) {
if (sheetIden != null) {
throw new FormulaParseException("Complete area reference expected after sheet name at index "
+ _pointer + ".");
}
return parseNonRange(savePointer);
}
if (whiteAfterPart1 || whiteBeforePart2) {
if (part1.isRowOrColumn() || part2.isRowOrColumn()) {
// "A .. B" not valid syntax for "A:B"
// and there's no other valid expression that fits this grammar
throw new FormulaParseException("Dotted range (full row or column) expression '"
+ part1And2 + "' must not contain whitespace.");
}
return createAreaRefParseNode(sheetIden, part1, part2);
}
if (dotCount == 1 && part1.isRow() && part2.isRow()) {
// actually, this is looking more like a number
return parseNonRange(savePointer);
}
if (part1.isRowOrColumn() || part2.isRowOrColumn()) {
if (dotCount != 2) {
throw new FormulaParseException("Dotted range (full row or column) expression '" + part1And2
+ "' must have exactly 2 dots.");
}
}
return createAreaRefParseNode(sheetIden, part1, part2);
}
if (part1.isCell() && isValidCellReference(part1.getRep())) {
return createAreaRefParseNode(sheetIden, part1, null);
}
if (sheetIden != null) {
throw new FormulaParseException("Second part of cell reference expected after sheet name at index "
+ _pointer + ".");
}
return parseNonRange(savePointer);
}