mirror of https://github.com/apache/poi.git
Bug 45041 - improved FormulaParser parse error messages
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@659452 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
c8c2d0139e
commit
71418f099d
|
@ -37,6 +37,7 @@
|
||||||
|
|
||||||
<!-- Don't forget to update status.xml too! -->
|
<!-- Don't forget to update status.xml too! -->
|
||||||
<release version="3.1-final" date="2008-06-??">
|
<release version="3.1-final" date="2008-06-??">
|
||||||
|
<action dev="POI-DEVELOPERS" type="add">45041 - improved FormulaParser parse error messages</action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">45046 - allowed EXTERNALBOOK(0x01AE) to be optional in the LinkTable</action>
|
<action dev="POI-DEVELOPERS" type="add">45046 - allowed EXTERNALBOOK(0x01AE) to be optional in the LinkTable</action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">45066 - fixed sheet encoding size mismatch problems</action>
|
<action dev="POI-DEVELOPERS" type="add">45066 - fixed sheet encoding size mismatch problems</action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">45003 - Support embeded HDGF visio documents</action>
|
<action dev="POI-DEVELOPERS" type="add">45003 - Support embeded HDGF visio documents</action>
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
<!-- Don't forget to update changes.xml too! -->
|
<!-- Don't forget to update changes.xml too! -->
|
||||||
<changes>
|
<changes>
|
||||||
<release version="3.1-final" date="2008-06-??">
|
<release version="3.1-final" date="2008-06-??">
|
||||||
|
<action dev="POI-DEVELOPERS" type="add">45041 - improved FormulaParser parse error messages</action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">45046 - allowed EXTERNALBOOK(0x01AE) to be optional in the LinkTable</action>
|
<action dev="POI-DEVELOPERS" type="add">45046 - allowed EXTERNALBOOK(0x01AE) to be optional in the LinkTable</action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">45066 - fixed sheet encoding size mismatch problems</action>
|
<action dev="POI-DEVELOPERS" type="add">45066 - fixed sheet encoding size mismatch problems</action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">45003 - Support embeded HDGF visio documents</action>
|
<action dev="POI-DEVELOPERS" type="add">45003 - Support embeded HDGF visio documents</action>
|
||||||
|
|
|
@ -55,7 +55,7 @@ public final class FormulaParser {
|
||||||
*/
|
*/
|
||||||
static final class FormulaParseException extends RuntimeException {
|
static final class FormulaParseException extends RuntimeException {
|
||||||
// This class was given package scope until it would become clear that it is useful to
|
// This class was given package scope until it would become clear that it is useful to
|
||||||
// general client code.
|
// general client code.
|
||||||
public FormulaParseException(String msg) {
|
public FormulaParseException(String msg) {
|
||||||
super(msg);
|
super(msg);
|
||||||
}
|
}
|
||||||
|
@ -127,14 +127,14 @@ public final class FormulaParser {
|
||||||
// Just return if so and reset 'look' to something to keep
|
// Just return if so and reset 'look' to something to keep
|
||||||
// SkipWhitespace from spinning
|
// SkipWhitespace from spinning
|
||||||
look = (char)0;
|
look = (char)0;
|
||||||
}
|
}
|
||||||
pointer++;
|
pointer++;
|
||||||
//System.out.println("Got char: "+ look);
|
//System.out.println("Got char: "+ look);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Report What Was Expected */
|
/** Report What Was Expected */
|
||||||
private RuntimeException expected(String s) {
|
private RuntimeException expected(String s) {
|
||||||
String msg = "Parse error near char " + (pointer-1) + "'" + look + "'"
|
String msg = "Parse error near char " + (pointer-1) + " '" + look + "'"
|
||||||
+ " in specified formula '" + formulaString + "'. Expected "
|
+ " in specified formula '" + formulaString + "'. Expected "
|
||||||
+ s;
|
+ s;
|
||||||
return new FormulaParseException(msg);
|
return new FormulaParseException(msg);
|
||||||
|
@ -178,7 +178,7 @@ public final class FormulaParser {
|
||||||
/**
|
/**
|
||||||
* Consumes the next input character if it is equal to the one specified otherwise throws an
|
* Consumes the next input character if it is equal to the one specified otherwise throws an
|
||||||
* unchecked exception. This method does <b>not</b> consume whitespace (before or after the
|
* unchecked exception. This method does <b>not</b> consume whitespace (before or after the
|
||||||
* matched character).
|
* matched character).
|
||||||
*/
|
*/
|
||||||
private void Match(char x) {
|
private void Match(char x) {
|
||||||
if (look != x) {
|
if (look != x) {
|
||||||
|
@ -281,18 +281,18 @@ public final class FormulaParser {
|
||||||
// This can be either a cell ref or a named range
|
// This can be either a cell ref or a named range
|
||||||
// Try to spot which it is
|
// Try to spot which it is
|
||||||
boolean cellRef = CELL_REFERENCE_PATTERN.matcher(name).matches();
|
boolean cellRef = CELL_REFERENCE_PATTERN.matcher(name).matches();
|
||||||
|
|
||||||
if (cellRef) {
|
if (cellRef) {
|
||||||
return new ReferencePtg(name);
|
return new ReferencePtg(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < book.getNumberOfNames(); i++) {
|
for(int i = 0; i < book.getNumberOfNames(); i++) {
|
||||||
// named range name matching is case insensitive
|
// named range name matching is case insensitive
|
||||||
if(book.getNameAt(i).getNameName().equalsIgnoreCase(name)) {
|
if(book.getNameAt(i).getNameName().equalsIgnoreCase(name)) {
|
||||||
return new NamePtg(name, book);
|
return new NamePtg(name, book);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new FormulaParseException("Found reference to named range \""
|
throw new FormulaParseException("Found reference to named range \""
|
||||||
+ name + "\", but that named range wasn't defined!");
|
+ name + "\", but that named range wasn't defined!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,19 +307,19 @@ public final class FormulaParser {
|
||||||
/**
|
/**
|
||||||
* Note - Excel function names are 'case aware but not case sensitive'. This method may end
|
* Note - Excel function names are 'case aware but not case sensitive'. This method may end
|
||||||
* up creating a defined name record in the workbook if the specified name is not an internal
|
* up creating a defined name record in the workbook if the specified name is not an internal
|
||||||
* Excel function, and has not been encountered before.
|
* Excel function, and has not been encountered before.
|
||||||
*
|
*
|
||||||
* @param name case preserved function name (as it was entered/appeared in the formula).
|
* @param name case preserved function name (as it was entered/appeared in the formula).
|
||||||
*/
|
*/
|
||||||
private Ptg function(String name) {
|
private Ptg function(String name) {
|
||||||
int numArgs =0 ;
|
int numArgs =0 ;
|
||||||
// Note regarding parameter -
|
// Note regarding parameter -
|
||||||
if(!AbstractFunctionPtg.isInternalFunctionName(name)) {
|
if(!AbstractFunctionPtg.isInternalFunctionName(name)) {
|
||||||
// external functions get a Name token which points to a defined name record
|
// external functions get a Name token which points to a defined name record
|
||||||
NamePtg nameToken = new NamePtg(name, this.book);
|
NamePtg nameToken = new NamePtg(name, this.book);
|
||||||
|
|
||||||
// in the token tree, the name is more or less the first argument
|
// in the token tree, the name is more or less the first argument
|
||||||
numArgs++;
|
numArgs++;
|
||||||
tokens.add(nameToken);
|
tokens.add(nameToken);
|
||||||
}
|
}
|
||||||
//average 2 args per function
|
//average 2 args per function
|
||||||
|
@ -477,26 +477,25 @@ public final class FormulaParser {
|
||||||
private static boolean isArgumentDelimiter(char ch) {
|
private static boolean isArgumentDelimiter(char ch) {
|
||||||
return ch == ',' || ch == ')';
|
return ch == ',' || ch == ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
/** get arguments to a function */
|
/** get arguments to a function */
|
||||||
private int Arguments(List argumentPointers) {
|
private int Arguments(List argumentPointers) {
|
||||||
SkipWhite();
|
SkipWhite();
|
||||||
if(look == ')') {
|
if(look == ')') {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean missedPrevArg = true;
|
boolean missedPrevArg = true;
|
||||||
|
|
||||||
int numArgs = 0;
|
int numArgs = 0;
|
||||||
while(true) {
|
while (true) {
|
||||||
SkipWhite();
|
SkipWhite();
|
||||||
if(isArgumentDelimiter(look)) {
|
if (isArgumentDelimiter(look)) {
|
||||||
if(missedPrevArg) {
|
if (missedPrevArg) {
|
||||||
tokens.add(new MissingArgPtg());
|
tokens.add(new MissingArgPtg());
|
||||||
addArgumentPointer(argumentPointers);
|
addArgumentPointer(argumentPointers);
|
||||||
numArgs++;
|
numArgs++;
|
||||||
}
|
}
|
||||||
if(look == ')') {
|
if (look == ')') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Match(',');
|
Match(',');
|
||||||
|
@ -507,6 +506,10 @@ public final class FormulaParser {
|
||||||
addArgumentPointer(argumentPointers);
|
addArgumentPointer(argumentPointers);
|
||||||
numArgs++;
|
numArgs++;
|
||||||
missedPrevArg = false;
|
missedPrevArg = false;
|
||||||
|
SkipWhite();
|
||||||
|
if (!isArgumentDelimiter(look)) {
|
||||||
|
throw expected("',' or ')'");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return numArgs;
|
return numArgs;
|
||||||
}
|
}
|
||||||
|
@ -524,7 +527,7 @@ public final class FormulaParser {
|
||||||
tokens.add(new PowerPtg());
|
tokens.add(new PowerPtg());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void percentFactor() {
|
private void percentFactor() {
|
||||||
tokens.add(parseSimpleFactor());
|
tokens.add(parseSimpleFactor());
|
||||||
while(true) {
|
while(true) {
|
||||||
|
@ -536,8 +539,8 @@ public final class FormulaParser {
|
||||||
tokens.add(new PercentPtg());
|
tokens.add(new PercentPtg());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* factors (without ^ or % )
|
* factors (without ^ or % )
|
||||||
*/
|
*/
|
||||||
|
@ -710,7 +713,7 @@ public final class FormulaParser {
|
||||||
private StringPtg parseStringLiteral()
|
private StringPtg parseStringLiteral()
|
||||||
{
|
{
|
||||||
Match('"');
|
Match('"');
|
||||||
|
|
||||||
StringBuffer token = new StringBuffer();
|
StringBuffer token = new StringBuffer();
|
||||||
while (true) {
|
while (true) {
|
||||||
if (look == '"') {
|
if (look == '"') {
|
||||||
|
@ -745,7 +748,7 @@ public final class FormulaParser {
|
||||||
return; // finished with Term
|
return; // finished with Term
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void comparisonExpression() {
|
private void comparisonExpression() {
|
||||||
concatExpression();
|
concatExpression();
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -787,7 +790,7 @@ public final class FormulaParser {
|
||||||
}
|
}
|
||||||
return new LessThanPtg();
|
return new LessThanPtg();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void concatExpression() {
|
private void concatExpression() {
|
||||||
additiveExpression();
|
additiveExpression();
|
||||||
|
@ -801,7 +804,7 @@ public final class FormulaParser {
|
||||||
tokens.add(new ConcatPtg());
|
tokens.add(new ConcatPtg());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Parse and Translate an Expression */
|
/** Parse and Translate an Expression */
|
||||||
private void additiveExpression() {
|
private void additiveExpression() {
|
||||||
|
@ -847,8 +850,8 @@ end;
|
||||||
comparisonExpression();
|
comparisonExpression();
|
||||||
|
|
||||||
if(pointer <= formulaLength) {
|
if(pointer <= formulaLength) {
|
||||||
String msg = "Unused input [" + formulaString.substring(pointer-1)
|
String msg = "Unused input [" + formulaString.substring(pointer-1)
|
||||||
+ "] after attempting to parse the formula [" + formulaString + "]";
|
+ "] after attempting to parse the formula [" + formulaString + "]";
|
||||||
throw new FormulaParseException(msg);
|
throw new FormulaParseException(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1011,7 +1014,7 @@ end;
|
||||||
continue;
|
continue;
|
||||||
// but if it ever did, care must be taken:
|
// but if it ever did, care must be taken:
|
||||||
// tAttrSpace comes *before* the operand it applies to, which may be consistent
|
// tAttrSpace comes *before* the operand it applies to, which may be consistent
|
||||||
// with how the formula text appears but is against the RPN ordering assumed here
|
// with how the formula text appears but is against the RPN ordering assumed here
|
||||||
}
|
}
|
||||||
if (attrPtg.isSemiVolatile()) {
|
if (attrPtg.isSemiVolatile()) {
|
||||||
// similar to tAttrSpace - RPN is violated
|
// similar to tAttrSpace - RPN is violated
|
||||||
|
@ -1038,7 +1041,7 @@ end;
|
||||||
stack.push(o.toFormulaString(operands));
|
stack.push(o.toFormulaString(operands));
|
||||||
}
|
}
|
||||||
if(stack.isEmpty()) {
|
if(stack.isEmpty()) {
|
||||||
// inspection of the code above reveals that every stack.pop() is followed by a
|
// inspection of the code above reveals that every stack.pop() is followed by a
|
||||||
// stack.push(). So this is either an internal error or impossible.
|
// stack.push(). So this is either an internal error or impossible.
|
||||||
throw new IllegalStateException("Stack underflow");
|
throw new IllegalStateException("Stack underflow");
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue