mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-28 11:25:35 +02:00
Patch for John Camelon:
- added quickParse heuristic to Scanner for handling #if conditionals to avoid throwing ScannerExceptions on undefined preprocessor symbols - added minimal enum support to Parser (though not to DOM or CModel)
This commit is contained in:
parent
a4732cccb3
commit
640ec6e2e6
4 changed files with 134 additions and 43 deletions
|
@ -10,6 +10,7 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package org.eclipse.cdt.internal.core.parser;
|
package org.eclipse.cdt.internal.core.parser;
|
||||||
|
|
||||||
|
import java.util.EmptyStackException;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
|
||||||
public class ExpressionEvaluator extends NullParserCallback {
|
public class ExpressionEvaluator extends NullParserCallback {
|
||||||
|
@ -104,7 +105,7 @@ public class ExpressionEvaluator extends NullParserCallback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getResult() {
|
public Object getResult() throws EmptyStackException {
|
||||||
return stack.peek();
|
return stack.peek();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -341,7 +341,7 @@ c, quick);
|
||||||
classSpecifier(decl);
|
classSpecifier(decl);
|
||||||
return;
|
return;
|
||||||
case Token.t_enum:
|
case Token.t_enum:
|
||||||
// enumSpecifier();
|
enumSpecifier(decl);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break declSpecifiers;
|
break declSpecifiers;
|
||||||
|
@ -465,9 +465,6 @@ c, quick);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
callback.declaratorEnd( declarator );
|
callback.declaratorEnd( declarator );
|
||||||
|
@ -590,6 +587,46 @@ c, quick);
|
||||||
throw backtrack;
|
throw backtrack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enumSpecifier
|
||||||
|
* "enum" (name)? "{" (enumerator-list) "}"
|
||||||
|
*/
|
||||||
|
public void enumSpecifier( Object owner ) throws Exception
|
||||||
|
{
|
||||||
|
if( LT(1) != Token.t_enum )
|
||||||
|
throw backtrack;
|
||||||
|
consume();
|
||||||
|
|
||||||
|
// insert beginEnum callback here
|
||||||
|
|
||||||
|
if( LT(1) == Token.tIDENTIFIER )
|
||||||
|
consume();
|
||||||
|
|
||||||
|
|
||||||
|
if( LT(1) == Token.tLBRACE )
|
||||||
|
{
|
||||||
|
consume();
|
||||||
|
// for the time being to get the CModel working ignore the enumerator list
|
||||||
|
int depth = 1;
|
||||||
|
while (depth > 0) {
|
||||||
|
switch (consume().getType()) {
|
||||||
|
case Token.tRBRACE:
|
||||||
|
--depth;
|
||||||
|
break;
|
||||||
|
case Token.tLBRACE:
|
||||||
|
++depth;
|
||||||
|
break;
|
||||||
|
case Token.tEOF:
|
||||||
|
// Oops, no match
|
||||||
|
throw backtrack;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert endEnum callback here
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* classSpecifier
|
* classSpecifier
|
||||||
* : classKey name (baseClause)? "{" (memberSpecification)* "}"
|
* : classKey name (baseClause)? "{" (memberSpecification)* "}"
|
||||||
|
@ -1232,7 +1269,8 @@ c, quick);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void primaryExpression() throws Exception {
|
public void primaryExpression() throws Exception {
|
||||||
switch (LT(1)) {
|
int type = LT(1);
|
||||||
|
switch (type) {
|
||||||
// TO DO: we need more literals...
|
// TO DO: we need more literals...
|
||||||
case Token.tINTEGER:
|
case Token.tINTEGER:
|
||||||
callback.expressionTerminal(consume());
|
callback.expressionTerminal(consume());
|
||||||
|
@ -1240,6 +1278,9 @@ c, quick);
|
||||||
case Token.tSTRING:
|
case Token.tSTRING:
|
||||||
callback.expressionTerminal(consume());
|
callback.expressionTerminal(consume());
|
||||||
return;
|
return;
|
||||||
|
case Token.tIDENTIFIER:
|
||||||
|
callback.expressionTerminal(consume());
|
||||||
|
return;
|
||||||
case Token.t_this:
|
case Token.t_this:
|
||||||
consume();
|
consume();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -526,14 +526,14 @@ public class Scanner implements IScanner {
|
||||||
case PreprocessorDirectives.IF :
|
case PreprocessorDirectives.IF :
|
||||||
// get the rest of the line
|
// get the rest of the line
|
||||||
String expression = getRestOfPreprocessorLine();
|
String expression = getRestOfPreprocessorLine();
|
||||||
|
|
||||||
boolean expressionEvalResult =
|
|
||||||
evaluateExpression(expression);
|
|
||||||
|
|
||||||
|
boolean expressionEvalResult = evaluateExpression(expression);
|
||||||
passOnToClient = branches.poundif( expressionEvalResult );
|
passOnToClient = branches.poundif( expressionEvalResult );
|
||||||
c = getChar();
|
c = getChar();
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
case PreprocessorDirectives.IFDEF :
|
case PreprocessorDirectives.IFDEF :
|
||||||
skipOverWhitespace();
|
skipOverWhitespace();
|
||||||
String definition = getNextIdentifier();
|
String definition = getNextIdentifier();
|
||||||
|
@ -588,7 +588,7 @@ public class Scanner implements IScanner {
|
||||||
throw new ScannerException("Malformed #elsif clause");
|
throw new ScannerException("Malformed #elsif clause");
|
||||||
|
|
||||||
boolean elsifResult =
|
boolean elsifResult =
|
||||||
evaluateExpression(elsifExpression);
|
evaluateExpression(elsifExpression );
|
||||||
|
|
||||||
passOnToClient = branches.poundelif( elsifResult );
|
passOnToClient = branches.poundelif( elsifResult );
|
||||||
c = getChar();
|
c = getChar();
|
||||||
|
@ -1089,42 +1089,59 @@ public class Scanner implements IScanner {
|
||||||
return branches.getDepth();
|
return branches.getDepth();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean evaluateExpression(String expression)
|
protected boolean evaluateExpression(String expression )
|
||||||
throws ScannerException {
|
throws ScannerException {
|
||||||
Object expressionEvalResult = null;
|
|
||||||
try {
|
if( quickScan )
|
||||||
ExpressionEvaluator evaluator = new ExpressionEvaluator();
|
{
|
||||||
Scanner trial =
|
if( expression.trim().equals( "0" ) )
|
||||||
new Scanner(
|
return false;
|
||||||
new StringReader(expression),
|
return true;
|
||||||
EXPRESSION,
|
|
||||||
definitions);
|
|
||||||
Parser parser = new Parser(trial, evaluator);
|
|
||||||
parser.expression();
|
|
||||||
expressionEvalResult = evaluator.getResult();
|
|
||||||
} catch (Exception e) {
|
|
||||||
System.out.println("Exception from Parser : " + e.toString());
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (expressionEvalResult == null)
|
{
|
||||||
throw new ScannerException(
|
Object expressionEvalResult = null;
|
||||||
"Expression "
|
try {
|
||||||
+ expression
|
ExpressionEvaluator evaluator = new ExpressionEvaluator();
|
||||||
+ " evaluates to an undefined value");
|
Scanner trial =
|
||||||
|
new Scanner(
|
||||||
if (expressionEvalResult.getClass() == java.lang.Integer.class) {
|
new StringReader(expression),
|
||||||
int i = ((Integer) expressionEvalResult).intValue();
|
EXPRESSION,
|
||||||
if (i == 0) {
|
definitions);
|
||||||
return false;
|
Parser parser = new Parser(trial, evaluator);
|
||||||
|
parser.expression();
|
||||||
|
|
||||||
|
expressionEvalResult = evaluator.getResult();
|
||||||
|
|
||||||
|
} catch (Exception e ) {
|
||||||
|
throw new ScannerException(
|
||||||
|
"Expression "
|
||||||
|
+ expression
|
||||||
|
+ " evaluates to an undefined value");
|
||||||
|
} finally
|
||||||
|
{
|
||||||
|
if (expressionEvalResult == null)
|
||||||
|
throw new ScannerException(
|
||||||
|
"Expression "
|
||||||
|
+ expression
|
||||||
|
+ " evaluates to an undefined value");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (expressionEvalResult.getClass() == java.lang.Integer.class) {
|
||||||
|
int i = ((Integer) expressionEvalResult).intValue();
|
||||||
|
if (i == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else if (
|
||||||
|
expressionEvalResult.getClass() == java.lang.Boolean.class) {
|
||||||
|
return ((Boolean) expressionEvalResult).booleanValue();
|
||||||
|
} else {
|
||||||
|
throw new ScannerException(
|
||||||
|
"Unexpected expression type - we do not expect "
|
||||||
|
+ expressionEvalResult.getClass().getName());
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
} else if (
|
|
||||||
expressionEvalResult.getClass() == java.lang.Boolean.class) {
|
|
||||||
return ((Boolean) expressionEvalResult).booleanValue();
|
|
||||||
} else {
|
|
||||||
throw new ScannerException(
|
|
||||||
"Unexpected expression type - we do not expect "
|
|
||||||
+ expressionEvalResult.getClass().getName());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -811,6 +811,38 @@ public class ScannerTestCase extends TestCase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testQuickScan()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
initializeScanner( "#if X + 5 < 7\n int found = 1;\n#endif" );
|
||||||
|
scanner.setQuickScan( true );
|
||||||
|
validateToken( Token.t_int );
|
||||||
|
validateIdentifier( "found" );
|
||||||
|
validateToken( Token.tASSIGN );
|
||||||
|
validateInteger( "1");
|
||||||
|
validateToken( Token.tSEMI );
|
||||||
|
validateEOF();
|
||||||
|
|
||||||
|
}
|
||||||
|
catch( ScannerException se )
|
||||||
|
{
|
||||||
|
fail( EXCEPTION_THROWN + se.getMessage() );
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
initializeScanner( "#if 0\n int error = 666;\n#endif" );
|
||||||
|
scanner.setQuickScan( true );
|
||||||
|
validateEOF();
|
||||||
|
}
|
||||||
|
catch( ScannerException se )
|
||||||
|
{
|
||||||
|
fail( EXCEPTION_THROWN + se.getMessage() );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public void testInclusions()
|
public void testInclusions()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
Loading…
Add table
Reference in a new issue