SpecialFunctionCallAnalyzer.java
package edu.udel.cis.vsl.abc.analysis.entity;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import edu.udel.cis.vsl.abc.ast.conversion.IF.ConversionFactory;
import edu.udel.cis.vsl.abc.ast.node.IF.SequenceNode;
import edu.udel.cis.vsl.abc.ast.node.IF.expression.ExpressionNode;
import edu.udel.cis.vsl.abc.ast.node.IF.expression.FunctionCallNode;
import edu.udel.cis.vsl.abc.ast.node.IF.expression.StringLiteralNode;
import edu.udel.cis.vsl.abc.ast.type.IF.ObjectType;
import edu.udel.cis.vsl.abc.ast.type.IF.TypeFactory;
import edu.udel.cis.vsl.abc.err.IF.ABCUnsupportedException;
import edu.udel.cis.vsl.abc.token.IF.SyntaxException;
/**
* This class maintains the hard-coded information of analyzes the variable
* parameters of some specific functions, like <code>scanf, fscanf</code>, whose
* variable arguments should all be of pointer type.
*
* @author Manchun Zheng
*
*/
public class SpecialFunctionCallAnalyzer {
// names of special functions handled in this class
private final static String SCANF = "scanf";
private final static String FSCANF = "fscanf";
private final static String PRINTF = "printf";
private final static String FPRINTF = "fprintf";
private EntityAnalyzer entityAnalyzer;
/** the type factory, for generating types. */
@SuppressWarnings("unused")
private TypeFactory typeFactory;
/** the void pointer type (void *) */
private ObjectType voidPointerType;
/**
* The names of functions handled by this analyzer
*/
private final Set<String> specialFunctioinNames = new HashSet<>(
Arrays.asList(SCANF, FSCANF));
/**
* Creates a new instance of special function call analyzer.
*
* @param typeFactory
* The type factory to be used.
*/
public SpecialFunctionCallAnalyzer(EntityAnalyzer entityAnalyzer,
TypeFactory typeFactory, ConversionFactory conversionFactory) {
this.typeFactory = typeFactory;
this.voidPointerType = typeFactory.pointerType(typeFactory.voidType());
this.entityAnalyzer = entityAnalyzer;
}
/**
* Is the given function handled in this analyzer?
*
* @param function
* Name of the function
* @return true iff the given function is in this analyzer
*/
boolean isSpecialFunction(String function) {
return this.specialFunctioinNames.contains(function);
}
/**
* checks if a fprintf/printf call has sufficient arguments as requested by
* the format string. An syntax exception is thrown if arguments are
* insufficient, otherwise, true is returned.
*
* @param call
* @param function
* @param arguments
* @return true if the function is not a printf/fprintf call or there are
* sufficient arguments.
* @throws SyntaxException
* if arguments are insufficient
*/
boolean hasSufficientArgumentsForPrintf(FunctionCallNode call,
String function, SequenceNode<ExpressionNode> arguments)
throws SyntaxException {
boolean isPrintf = false;
boolean isFprintf = false;
int formatIndex = 0;
int numArgsForPrint = arguments.numChildren() - 1;
ExpressionNode formatString;
if (function.equals(FPRINTF))
isFprintf = true;
else if (function.equals(PRINTF))
isPrintf = true;
if (!isPrintf && !isFprintf)
return true;
if (isFprintf) {
formatIndex++;
numArgsForPrint--;
}
formatString = arguments.getSequenceChild(formatIndex);
if (formatString instanceof StringLiteralNode) {
String format = ((StringLiteralNode) formatString)
.getStringRepresentation();
int numFormats;
String realFormat = format.replaceAll("%%", "");
String formatArgumentsString = "arguments";
String printArgumentsString = "are";
numFormats = realFormat.split("%", -1).length - 1;
if (numFormats == 1)
formatArgumentsString = "argument";
if (numArgsForPrint == 1)
printArgumentsString = "is";
if (numFormats > numArgsForPrint)
throw this.entityAnalyzer.error("insufficient arguments for "
+ function + ": the format string " + format
+ " is requring " + numFormats + " subsequent "
+ formatArgumentsString + " while only "
+ numArgsForPrint + " " + printArgumentsString
+ " provided.", call);
}
return true;
}
/**
* Returns the type of a variable parameter of a certain index of the given
* function.
* <p>
* Precondition: the given function is a special function handled in this
* analyzer and the index-th parameter is a variable one.
*
* @param function
* Name of the function
* @param index
* index of the parameter whose type is to be obtained
* @return
*/
ObjectType variableParameterType(String function, int index) {
assert this.isSpecialFunction(function);
switch (function) {
case SCANF :
return this.variableParameterTypeOfScanf(index);
case FSCANF :// fscanf has one more fixed parameter than scanf
return this.variableParameterTypeOfScanf(index - 1);
default :
throw new ABCUnsupportedException("The function " + function
+ " isn't a special function that needs "
+ "type checking of its variable parameters");
}
}
/**
* Returns the type of the parameter of the given index for
* <code>scanf</code>. <code>scanf</code> is expecting any parameter with
* index greater than 0 to be of pointer type, i.e.:
* <code>scanf(char*, (void*)+);</code>
*
* @param index
* The index of the parameter
* @return the type of the parameter of the given index for scanf, which is
* always void*.
*/
private ObjectType variableParameterTypeOfScanf(int index) {
assert index > 0;
return this.voidPointerType;
}
}