mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-02-07 20:31:32 +00:00
Fixed exception when using a return value from a VOID function. Added proper error message when printf() is missing parameters referenced in the format string.
This commit is contained in:
parent
dbbde914c7
commit
f7f9ef4a6c
@ -322,6 +322,7 @@ public class Compiler {
|
||||
getLog().append(program.getProcedureModifiedVars().toString(program));
|
||||
}
|
||||
|
||||
new Pass1CallVoidReturns(program).execute();
|
||||
new Pass1CallStack(program).execute();
|
||||
new Pass1CallPhiParameters(program).execute();
|
||||
//getLog().append("PROCEDURE PARAMETERS");
|
||||
|
@ -0,0 +1,65 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.VariableReferenceInfos;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementCall;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
import dk.camelot64.kickc.model.symbols.Variable;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.values.LValue;
|
||||
import dk.camelot64.kickc.model.values.ProcedureRef;
|
||||
import dk.camelot64.kickc.model.values.VariableRef;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/** Remove temporary variables assigned any void return value */
|
||||
public class Pass1CallVoidReturns extends Pass2SsaOptimization {
|
||||
|
||||
public Pass1CallVoidReturns(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean step() {
|
||||
new PassNStatementIndices(getProgram()).execute();
|
||||
getProgram().clearVariableReferenceInfos();
|
||||
VariableReferenceInfos referenceInfos = getProgram().getVariableReferenceInfos();
|
||||
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementCall) {
|
||||
final ProcedureRef procedureRef = ((StatementCall) statement).getProcedure();
|
||||
final Procedure procedure = getScope().getProcedure(procedureRef);
|
||||
if(SymbolType.VOID.equals(procedure.getReturnType())) {
|
||||
// Found a call to a VOID returning procedure
|
||||
final LValue lValue = ((StatementCall) statement).getlValue();
|
||||
if(lValue instanceof VariableRef) {
|
||||
VariableRef tmpVar = (VariableRef) lValue;
|
||||
final Collection<Integer> usages = referenceInfos.getVarUseStatements(tmpVar);
|
||||
if(usages.size() > 0) {
|
||||
final Integer usageIdx = usages.iterator().next();
|
||||
final Statement usage = getProgram().getStatementInfos().getStatement(usageIdx);
|
||||
throw new CompileError("Error! Function " + procedure.getLocalName() + " does not return a value! ", usage);
|
||||
} else {
|
||||
// Delete the temporary variable
|
||||
final Variable var = getScope().getVar(tmpVar);
|
||||
var.getScope().remove(var);
|
||||
// And remove the lValue
|
||||
((StatementCall) statement).setlValue(null);
|
||||
if(getLog().isVerbosePass1CreateSsa())
|
||||
getLog().append("Removing LValue from call to function returning void");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
getProgram().clearStatementIndices();
|
||||
getProgram().clearVariableReferenceInfos();
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -62,7 +62,7 @@ public class Pass1PrintfIntrinsicRewrite extends Pass2SsaOptimization {
|
||||
if(statement instanceof StatementCall && ((StatementCall) statement).getProcedureName().equals(INTRINSIC_PRINTF_NAME)) {
|
||||
StatementCall printfCall = (StatementCall) statement;
|
||||
final List<RValue> parameters = printfCall.getParameters();
|
||||
final RValue formatParameter = parameters.get(0);
|
||||
final RValue formatParameter = getParameterValue(parameters, 0, printfCall);
|
||||
if(!(formatParameter instanceof ConstantValue))
|
||||
throw new CompileError("Error! Only constant printf() format parameter supported!", statement);
|
||||
final ConstantLiteral formatLiteral = ((ConstantValue) formatParameter).calculateLiteral(getProgram().getScope());
|
||||
@ -138,7 +138,7 @@ public class Pass1PrintfIntrinsicRewrite extends Pass2SsaOptimization {
|
||||
new ConstantInteger(width, SymbolType.BYTE),
|
||||
new ConstantInteger(leftJustify, SymbolType.BYTE)
|
||||
));
|
||||
addPrintfCall(PRINTF_STRING, Arrays.asList(parameters.get(paramIdx), format_string_struct), stmtIt, printfCall);
|
||||
addPrintfCall(PRINTF_STRING, Arrays.asList(getParameterValue(parameters, paramIdx, printfCall), format_string_struct), stmtIt, printfCall);
|
||||
paramIdx++;
|
||||
} else if("diuxXo".contains(typeField)) {
|
||||
// A formatted integer
|
||||
@ -174,7 +174,7 @@ public class Pass1PrintfIntrinsicRewrite extends Pass2SsaOptimization {
|
||||
|
||||
if(lengthField == null) {
|
||||
// Check if the parameter type is 8-bit or 32-bit
|
||||
RValue paramValue = parameters.get(paramIdx);
|
||||
RValue paramValue = getParameterValue(parameters, paramIdx, printfCall);
|
||||
SymbolType paramType = SymbolTypeInference.inferType(getScope(), paramValue);
|
||||
if(SymbolType.BYTE.equals(paramType) || SymbolType.SBYTE.equals(paramType)) {
|
||||
// Integer (8bit)
|
||||
@ -214,11 +214,11 @@ public class Pass1PrintfIntrinsicRewrite extends Pass2SsaOptimization {
|
||||
new ConstantInteger(upperCase, SymbolType.BYTE),
|
||||
radix
|
||||
));
|
||||
addPrintfCall(printf_number_procedure, Arrays.asList(parameters.get(paramIdx), format_number_struct), stmtIt, printfCall);
|
||||
addPrintfCall(printf_number_procedure, Arrays.asList(getParameterValue(parameters, paramIdx, printfCall), format_number_struct), stmtIt, printfCall);
|
||||
paramIdx++;
|
||||
} else if(typeField.equals("c")) {
|
||||
// Print char
|
||||
addPrintfCall(PRINTF_CHAR, Arrays.asList(parameters.get(paramIdx)), stmtIt, printfCall);
|
||||
addPrintfCall(PRINTF_CHAR, Arrays.asList(getParameterValue(parameters, paramIdx, printfCall)), stmtIt, printfCall);
|
||||
paramIdx++;
|
||||
} else if(typeField.equals("p")) {
|
||||
// Print a pointer
|
||||
@ -231,7 +231,7 @@ public class Pass1PrintfIntrinsicRewrite extends Pass2SsaOptimization {
|
||||
new ConstantInteger(upperCase, SymbolType.BYTE),
|
||||
getScope().getLocalConstant(HEXADECIMAL).getRef()
|
||||
));
|
||||
addPrintfCall(PRINTF_UINT, Arrays.asList(new CastValue(SymbolType.WORD, parameters.get(paramIdx)), format_number_struct), stmtIt, printfCall);
|
||||
addPrintfCall(PRINTF_UINT, Arrays.asList(new CastValue(SymbolType.WORD, getParameterValue(parameters, paramIdx, printfCall)), format_number_struct), stmtIt, printfCall);
|
||||
paramIdx++;
|
||||
}
|
||||
}
|
||||
@ -245,6 +245,21 @@ public class Pass1PrintfIntrinsicRewrite extends Pass2SsaOptimization {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific parameter value.
|
||||
* @param parameters The list of parameters
|
||||
* @param paramIdx The index of the parameter to get
|
||||
* @param printfCall The printf call statement used for errors
|
||||
* @return The parameter value.
|
||||
*
|
||||
* @throws CompileError if the parameter is not present
|
||||
*/
|
||||
private RValue getParameterValue(List<RValue> parameters, int paramIdx, StatementCall printfCall) {
|
||||
if(parameters.size()<=paramIdx)
|
||||
throw new CompileError("Error! printf missing parameter with index "+paramIdx, printfCall);
|
||||
return parameters.get(paramIdx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a call to a PRINTF sub-function.
|
||||
*
|
||||
|
@ -57,6 +57,11 @@ public class TestPrograms {
|
||||
compileAndCompare("multiply-1.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoubleCallProblem() throws IOException, URISyntaxException {
|
||||
assertError("double-call-problem.c", "Error! Function clrscr does not return a value! ");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStructPointerToMember2() throws IOException, URISyntaxException {
|
||||
compileAndCompare("struct-pointer-to-member-2.c");
|
||||
@ -97,6 +102,11 @@ public class TestPrograms {
|
||||
compileAndCompare("toupper-1.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrintfError6() throws IOException, URISyntaxException {
|
||||
assertError("printf-error-6.c", "Error! printf missing parameter with index 1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrintfError5() throws IOException, URISyntaxException {
|
||||
assertError("printf-error-5.c", "Error! printf() format parameter must be a string!");
|
||||
|
10
src/test/kc/double-call-problem.c
Normal file
10
src/test/kc/double-call-problem.c
Normal file
@ -0,0 +1,10 @@
|
||||
// Demonstrates problem with a double call not being detected as a type error
|
||||
|
||||
void main() {
|
||||
clrscr()();
|
||||
}
|
||||
|
||||
void clrscr(void) {
|
||||
char * const SCREEN = 0x0400;
|
||||
SCREEN[0] = '@';
|
||||
}
|
9
src/test/kc/printf-error-6.c
Normal file
9
src/test/kc/printf-error-6.c
Normal file
@ -0,0 +1,9 @@
|
||||
// Tests printf function call rewriting
|
||||
// To few parameters
|
||||
|
||||
#include <printf.h>
|
||||
|
||||
void main() {
|
||||
printf("%d");
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user