mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-02-17 10:30:43 +00:00
Implemented framework for number type conversion - the BinaryExpressionIterator. Added first case (type match) in new PassNAddNumberTybeConversions.
This commit is contained in:
parent
35ec65ce94
commit
d0d5b5715b
@ -192,7 +192,7 @@ public class CompileLog {
|
||||
return verboseSSAOptimize;
|
||||
}
|
||||
|
||||
public CompileLog setVerboseSSAOptimize() {
|
||||
public CompileLog verboseSSAOptimize() {
|
||||
setVerboseSSAOptimize(true);
|
||||
return this;
|
||||
}
|
||||
|
@ -233,6 +233,7 @@ public class Compiler {
|
||||
List<Pass2SsaOptimization> optimizations = new ArrayList<>();
|
||||
optimizations.add(new PassNTypeInference(program));
|
||||
optimizations.add(new PassNAddTypeConversions(program));
|
||||
optimizations.add(new PassNAddNumberTypeConversions(program));
|
||||
optimizations.add(new Pass2CullEmptyBlocks(program));
|
||||
optimizations.add(new PassNStatementIndices(program));
|
||||
optimizations.add(new PassNVariableReferenceInfos(program));
|
||||
@ -247,7 +248,7 @@ public class Compiler {
|
||||
optimizations.add(new Pass2ConstantIdentification(program));
|
||||
optimizations.add(new PassNStatementIndices(program));
|
||||
optimizations.add(new PassNVariableReferenceInfos(program));
|
||||
optimizations.add(new Pass2ConstantAdditionElimination(program));
|
||||
//optimizations.add(new Pass2ConstantAdditionElimination(program));
|
||||
optimizations.add(new Pass2ConstantIfs(program));
|
||||
optimizations.add(new Pass2ConstantStringConsolidation(program));
|
||||
optimizations.add(new Pass2FixInlineConstructors(program));
|
||||
@ -356,7 +357,9 @@ public class Compiler {
|
||||
}
|
||||
|
||||
private void pass3Analysis() {
|
||||
new Pass3AssertNoTypeId(program).check();
|
||||
new Pass3AssertRValues(program).check();
|
||||
new Pass3AssertNoNumbers(program).check();
|
||||
new Pass3AssertConstants(program).check();
|
||||
new Pass3AssertArrayLengths(program).check();
|
||||
new Pass3AssertNoMulDivMod(program).check();
|
||||
|
@ -0,0 +1,166 @@
|
||||
package dk.camelot64.kickc.model.iterator;
|
||||
|
||||
import dk.camelot64.kickc.model.operators.OperatorBinary;
|
||||
import dk.camelot64.kickc.model.operators.Operators;
|
||||
import dk.camelot64.kickc.model.statements.StatementAssignment;
|
||||
import dk.camelot64.kickc.model.statements.StatementConditionalJump;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.values.*;
|
||||
|
||||
/**
|
||||
* A binary expression in the program being iterated by {@link BinaryExpressionIterator}
|
||||
*/
|
||||
public interface BinaryExpression {
|
||||
|
||||
/**
|
||||
* Get the left operand
|
||||
*
|
||||
* @return The left operand
|
||||
*/
|
||||
RValue getLeft();
|
||||
|
||||
/**
|
||||
* Get the binary operator
|
||||
*
|
||||
* @return the operator
|
||||
*/
|
||||
OperatorBinary getOperator();
|
||||
|
||||
/**
|
||||
* Get the right operand
|
||||
*
|
||||
* @return The right operand
|
||||
*/
|
||||
RValue getRight();
|
||||
|
||||
/**
|
||||
* Adds a cast to the right operand
|
||||
* @param toType The toType to cast to
|
||||
*/
|
||||
void addRightCast(SymbolType toType);
|
||||
|
||||
/** Binary expression assignment rvalue. */
|
||||
class BinaryExpressionAssignmentRValue implements BinaryExpression {
|
||||
private final StatementAssignment assignment;
|
||||
|
||||
BinaryExpressionAssignmentRValue(StatementAssignment assignment) {
|
||||
this.assignment = assignment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue getLeft() {
|
||||
return assignment.getrValue1();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OperatorBinary getOperator() {
|
||||
return (OperatorBinary) assignment.getOperator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue getRight() {
|
||||
return assignment.getrValue2();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRightCast(SymbolType toType) {
|
||||
if(assignment.getrValue2() instanceof ConstantValue) {
|
||||
assignment.setrValue2(new ConstantCastValue(toType, (ConstantValue) assignment.getrValue2()));
|
||||
} else {
|
||||
throw new InternalError("Not implemented!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Binary expression - assignment lvalue and the "total" rvalue. */
|
||||
class BinaryExpressionAssignmentLValue implements BinaryExpression {
|
||||
private final StatementAssignment assignment;
|
||||
|
||||
BinaryExpressionAssignmentLValue(StatementAssignment assignment) {
|
||||
this.assignment = assignment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue getLeft() {
|
||||
return assignment.getlValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OperatorBinary getOperator() {
|
||||
return Operators.ASSIGNMENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue getRight() {
|
||||
return new AssignmentRValue(assignment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRightCast(SymbolType toType) {
|
||||
throw new InternalError("Not implemented!");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** Binary expression conditional jump. */
|
||||
class BinaryExpressionConditionalJump implements BinaryExpression {
|
||||
private final StatementConditionalJump conditionalJump;
|
||||
|
||||
BinaryExpressionConditionalJump(StatementConditionalJump assignment) {
|
||||
this.conditionalJump = assignment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue getLeft() {
|
||||
return conditionalJump.getrValue1();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OperatorBinary getOperator() {
|
||||
return (OperatorBinary) conditionalJump.getOperator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue getRight() {
|
||||
return conditionalJump.getrValue2();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRightCast(SymbolType toType) {
|
||||
throw new InternalError("Not implemented!");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/** Binary expression as part of a constant expression. */
|
||||
class BinaryExpressionConstant implements BinaryExpression {
|
||||
private ConstantBinary constantBinary;
|
||||
|
||||
BinaryExpressionConstant(ConstantBinary constantBinary) {
|
||||
this.constantBinary = constantBinary;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue getLeft() {
|
||||
return constantBinary.getLeft();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OperatorBinary getOperator() {
|
||||
return constantBinary.getOperator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue getRight() {
|
||||
return constantBinary.getRight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRightCast(SymbolType toType) {
|
||||
constantBinary.setRight(new ConstantCastValue(toType, constantBinary.getRight()));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package dk.camelot64.kickc.model.iterator;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
|
||||
import java.util.ListIterator;
|
||||
|
||||
/** A handler that performs some action for binary expressions in the program.
|
||||
* A {@link BinaryExpressionIterator} can be used to iterate all binary expressions in a part of the program.
|
||||
* The Handler then receives all binary expressions one at a time. The Handler has the option of modifying the binary expression. After the handler is executed all sub-values are recursed.
|
||||
* The execute() method furthermore receives some extra parameters with information about the context of the passed value.
|
||||
*/
|
||||
public interface BinaryExpressionHandler {
|
||||
|
||||
/**
|
||||
* Handle a single binary expression
|
||||
*
|
||||
* @param binaryExpression The binary expression
|
||||
* @param currentStmt The statement iterator - just past the current statement that the value is a part of. Current statment can be retrieved by calling
|
||||
* @param stmtIt The statement iterator - just past the current statement. Can be used for modifying the control flow block.
|
||||
* @param currentBlock The current block that the value is a part of
|
||||
*/
|
||||
void execute(BinaryExpression binaryExpression, Statement currentStmt, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock);
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package dk.camelot64.kickc.model.iterator;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementAssignment;
|
||||
import dk.camelot64.kickc.model.statements.StatementConditionalJump;
|
||||
import dk.camelot64.kickc.model.values.ConstantBinary;
|
||||
|
||||
import java.util.ListIterator;
|
||||
|
||||
/**
|
||||
* Capable of iterating the different structures of a Program (graph, block, statement, symboltable, symbol).
|
||||
* Creates appropriate BinaryExpressions and passes them to a BinaryExpressionHandler.
|
||||
* Iteration might be guided (eg. filtering some types of the structure to iterate at call-time)
|
||||
*/
|
||||
public class BinaryExpressionIterator {
|
||||
|
||||
/**
|
||||
* Execute a handler on all values in the entire program (both in the control flow graph and the symbol table.)
|
||||
*
|
||||
* @param program The program
|
||||
* @param handler The handler to execute
|
||||
*/
|
||||
public static void execute(Program program, BinaryExpressionHandler handler) {
|
||||
// Iterate all symbols
|
||||
ProgramValueIterator.execute(program.getScope(), (programValue, currentStmt, stmtIt, currentBlock) -> {
|
||||
if(programValue.get() instanceof ConstantBinary) {
|
||||
ConstantBinary constantBinary = (ConstantBinary) programValue.get();
|
||||
handler.execute( new BinaryExpression.BinaryExpressionConstant(constantBinary), null, null, null);
|
||||
}
|
||||
});
|
||||
|
||||
// Iterate all blocks/statements
|
||||
for(ControlFlowBlock block : program.getGraph().getAllBlocks()) {
|
||||
ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
||||
while(stmtIt.hasNext()) {
|
||||
Statement stmt = stmtIt.next();
|
||||
if(stmt instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) stmt;
|
||||
if(assignment.getrValue1() != null && assignment.getOperator()!=null &&assignment.getrValue2() != null) {
|
||||
handler.execute( new BinaryExpression.BinaryExpressionAssignmentRValue(assignment), stmt, stmtIt, block);
|
||||
}
|
||||
handler.execute( new BinaryExpression.BinaryExpressionAssignmentLValue(assignment), stmt, stmtIt, block);
|
||||
} else if(stmt instanceof StatementConditionalJump) {
|
||||
StatementConditionalJump condJump = (StatementConditionalJump) stmt;
|
||||
if(condJump.getrValue1()!=null && condJump.getOperator()!=null && condJump.getrValue2()!=null) {
|
||||
handler.execute( new BinaryExpression.BinaryExpressionConditionalJump(condJump), stmt, stmtIt, block);
|
||||
}
|
||||
}
|
||||
// Iterate all statement values
|
||||
ProgramValueIterator.execute(stmt, (programValue, currentStmt, stmtIt1, currentBlock) -> {
|
||||
if(programValue.get() instanceof ConstantBinary) {
|
||||
ConstantBinary constantBinary = (ConstantBinary) programValue.get();
|
||||
handler.execute( new BinaryExpression.BinaryExpressionConstant(constantBinary), stmt, stmtIt, block);
|
||||
}
|
||||
}, stmtIt, block);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package dk.camelot64.kickc.model.operators;
|
||||
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeSimple;
|
||||
import dk.camelot64.kickc.model.values.ConstantBool;
|
||||
import dk.camelot64.kickc.model.values.ConstantLiteral;
|
||||
|
||||
/** Binary assignment operator ( x = y ) */
|
||||
public class OperatorAssignment extends OperatorBinary {
|
||||
|
||||
public OperatorAssignment(int precedence) {
|
||||
super("=", "_assign_", precedence);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConstantLiteral calculateLiteral(ConstantLiteral left, ConstantLiteral right) {
|
||||
throw new CompileError("Calculation not implemented " + left + " " + getOperator() + " " + right);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SymbolType inferType(SymbolTypeSimple left, SymbolTypeSimple right) {
|
||||
return left;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -48,6 +48,7 @@ public class Operators {
|
||||
public static final OperatorBinary BOOL_OR = new OperatorBitwiseOr(11);
|
||||
public static final OperatorBinary LOGIC_AND = new OperatorLogicAnd(12);
|
||||
public static final OperatorBinary LOGIC_OR = new OperatorLogicOr(13);
|
||||
public static final OperatorBinary ASSIGNMENT = new OperatorAssignment(14);
|
||||
|
||||
public static Operator getBinary(String op) {
|
||||
switch(op) {
|
||||
|
@ -20,7 +20,7 @@ public interface SymbolType {
|
||||
SymbolTypeIntegerFixed DWORD = new SymbolTypeIntegerFixed("dword", 0, 4_294_967_296L, false, 32);
|
||||
/** Signed double word (4 bytes, 32 bits). */
|
||||
SymbolTypeIntegerFixed SDWORD = new SymbolTypeIntegerFixed("signed dword", -2_147_483_648, 2_147_483_647, true, 32);
|
||||
/** Integer with unknown size. */
|
||||
/** Integer with unknown size (used for constant expressions). */
|
||||
SymbolTypeIntegerAuto NUMBER = new SymbolTypeIntegerAuto("number");
|
||||
/** String value (treated like byte* ). */
|
||||
SymbolTypeNamed STRING = new SymbolTypeNamed("string", 99);
|
||||
|
@ -126,6 +126,8 @@ public class SymbolTypeInference {
|
||||
} else if(rValue instanceof ProcedureRef) {
|
||||
Procedure procedure = symbols.getProcedure((ProcedureRef) rValue);
|
||||
return procedure.getType();
|
||||
} else if(rValue instanceof AssignmentRValue) {
|
||||
return inferTypeRValue(symbols, ((AssignmentRValue) rValue).getAssignment());
|
||||
}
|
||||
if(type == null) {
|
||||
throw new RuntimeException("Cannot infer type for " + rValue.toString());
|
||||
|
@ -0,0 +1,28 @@
|
||||
package dk.camelot64.kickc.model.values;
|
||||
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.StatementAssignment;
|
||||
|
||||
/** The "total" RValue of an assigment. */
|
||||
public class AssignmentRValue implements RValue {
|
||||
|
||||
private StatementAssignment assignment;
|
||||
|
||||
public AssignmentRValue(StatementAssignment assignment) {
|
||||
this.assignment = assignment;
|
||||
}
|
||||
|
||||
public StatementAssignment getAssignment() {
|
||||
return assignment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(Program program) {
|
||||
return
|
||||
(assignment.getrValue1() == null ? "" : assignment.getrValue1().toString(program) + " ") +
|
||||
(assignment.getOperator() == null ? "" : assignment.getOperator() + " ") +
|
||||
assignment.getrValue2().toString(program)
|
||||
;
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.InternalError;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.operators.OperatorTypeId;
|
||||
import dk.camelot64.kickc.model.operators.Operators;
|
||||
@ -8,9 +9,15 @@ import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementAssignment;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeInference;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeIntegerFixed;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeNumberInference;
|
||||
import dk.camelot64.kickc.model.values.ConstantLiteral;
|
||||
import dk.camelot64.kickc.model.values.ConstantRef;
|
||||
import dk.camelot64.kickc.model.values.ConstantValue;
|
||||
import dk.camelot64.kickc.model.values.RValue;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Converts typeid() operators to constants
|
||||
*/
|
||||
@ -30,11 +37,18 @@ public class Pass1TypeIdSimplification extends Pass1Base {
|
||||
if(Operators.TYPEID.equals(assignment.getOperator())) {
|
||||
RValue rValue = assignment.getrValue2();
|
||||
SymbolType symbolType = SymbolTypeInference.inferType(getScope(), rValue);
|
||||
getLog().append("Resolving typeid() " + assignment.toString(getProgram(), false));
|
||||
ConstantRef typeIDConstantVar = OperatorTypeId.getTypeIdConstantVar(getScope(), symbolType);
|
||||
assignment.setrValue2(typeIDConstantVar);
|
||||
assignment.setOperator(null);
|
||||
modified = true;
|
||||
if(SymbolType.NUMBER.equals(symbolType)) {
|
||||
if(rValue instanceof ConstantValue) {
|
||||
List<SymbolTypeIntegerFixed> fixedTypes = SymbolTypeNumberInference.inferTypes(getScope(), (ConstantLiteral) rValue);
|
||||
throw new InternalError("TODO: Implement typeof(const)!");
|
||||
}
|
||||
} else {
|
||||
getLog().append("Resolving typeid() " + assignment.toString(getProgram(), false));
|
||||
ConstantRef typeIDConstantVar = OperatorTypeId.getTypeIdConstantVar(getScope(), symbolType);
|
||||
assignment.setrValue2(typeIDConstantVar);
|
||||
assignment.setOperator(null);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,63 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.InternalError;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementAssignment;
|
||||
import dk.camelot64.kickc.model.statements.StatementConditionalJump;
|
||||
import dk.camelot64.kickc.model.statements.StatementPhiBlock;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeInference;
|
||||
import dk.camelot64.kickc.model.values.RValue;
|
||||
|
||||
/**
|
||||
* Assert that all values with type number have been resolved to fixed size in pass 2.
|
||||
*/
|
||||
public class Pass3AssertNoNumbers extends Pass2SsaAssertion {
|
||||
|
||||
public Pass3AssertNoNumbers(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void check() throws AssertionFailed {
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementAssignment) {
|
||||
checkValue(((StatementAssignment) statement).getlValue(), statement);
|
||||
checkValue(((StatementAssignment) statement).getrValue1(), statement);
|
||||
checkValue(((StatementAssignment) statement).getrValue2(), statement);
|
||||
} else if(statement instanceof StatementPhiBlock) {
|
||||
for(StatementPhiBlock.PhiVariable phiVariable : ((StatementPhiBlock) statement).getPhiVariables()) {
|
||||
for(StatementPhiBlock.PhiRValue value : phiVariable.getValues()) {
|
||||
checkValue(value.getrValue(), statement);
|
||||
}
|
||||
}
|
||||
} else if(statement instanceof StatementConditionalJump) {
|
||||
checkValue(((StatementConditionalJump) statement).getrValue1(), statement);
|
||||
checkValue(((StatementConditionalJump) statement).getrValue2(), statement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a value to ensure it is does not have the {@link SymbolType#NUMBER}.
|
||||
*
|
||||
* @param rValue The value to check
|
||||
* @param statement The statement containing the value
|
||||
*/
|
||||
public void checkValue(RValue rValue, Statement statement) {
|
||||
if(rValue == null) return;
|
||||
SymbolType symbolType = SymbolTypeInference.inferType(getScope(), rValue);
|
||||
if(SymbolType.NUMBER.equals(symbolType)) {
|
||||
throw new InternalError(
|
||||
"Error! Number integer type not resolved to fixed size integer type " +
|
||||
"\n value: " + rValue.toString(getProgram()) +
|
||||
"\n statement: " + statement.toString(getProgram(), false)
|
||||
, statement.getSource()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.InternalError;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
|
||||
import dk.camelot64.kickc.model.operators.Operators;
|
||||
import dk.camelot64.kickc.model.values.ConstantUnary;
|
||||
import dk.camelot64.kickc.model.values.Value;
|
||||
|
||||
/**
|
||||
* Assert that no typeid() expressions exist in the code anymore (they must have been resolved to constants in phase 1-2)
|
||||
*/
|
||||
public class Pass3AssertNoTypeId extends Pass2SsaAssertion {
|
||||
|
||||
public Pass3AssertNoTypeId(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void check() throws AssertionFailed {
|
||||
ProgramValueIterator.execute(getProgram(), (programValue, currentStmt, stmtIt, currentBlock) -> {
|
||||
Value value = programValue.get();
|
||||
if(value instanceof ConstantUnary) {
|
||||
if(Operators.TYPEID.equals(((ConstantUnary) value).getOperator())) {
|
||||
throw new InternalError(
|
||||
"Error! Typeid() not resolved during compile. " +
|
||||
"\n statement: " + currentStmt.toString(getProgram(), false)
|
||||
, currentStmt.getSource()
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.InternalError;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
|
||||
import dk.camelot64.kickc.model.values.RangeValue;
|
||||
@ -24,7 +24,7 @@ public class Pass3AssertRValues extends Pass2SsaAssertion {
|
||||
ProgramValueIterator.execute(getGraph(), (programValue, currentStmt, stmtIt, currentBlock) -> {
|
||||
Value value = programValue.get();
|
||||
if(value instanceof ValueList) {
|
||||
throw new CompileError(
|
||||
throw new InternalError(
|
||||
"Error! Value list not resolved to word constructor or array initializer" +
|
||||
"\n value list: " + value.toString(getProgram()) +
|
||||
"\n statement: " + currentStmt.toString(getProgram(), false)
|
||||
@ -32,7 +32,7 @@ public class Pass3AssertRValues extends Pass2SsaAssertion {
|
||||
);
|
||||
}
|
||||
if(value instanceof RangeValue) {
|
||||
throw new CompileError(
|
||||
throw new InternalError(
|
||||
"Error! Ranged for() not resolved to constants" +
|
||||
"\n Range: " + value.toString(getProgram()) +
|
||||
"\n statement: " + currentStmt.toString(getProgram(), false)
|
||||
|
@ -0,0 +1,59 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.InternalError;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.iterator.BinaryExpressionIterator;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeInference;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeIntegerFixed;
|
||||
import dk.camelot64.kickc.model.values.*;
|
||||
|
||||
/**
|
||||
* Add casts to {@link SymbolType#NUMBER} expressions that meet a typed value in a binary expression (including assignment)
|
||||
*/
|
||||
public class PassNAddNumberTypeConversions extends Pass2SsaOptimization {
|
||||
|
||||
public PassNAddNumberTypeConversions(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean step() {
|
||||
BinaryExpressionIterator.execute(getProgram(), (binaryExpression, currentStmt, stmtIt, currentBlock) -> {
|
||||
RValue left = binaryExpression.getLeft();
|
||||
RValue right = binaryExpression.getRight();
|
||||
|
||||
SymbolType leftType = SymbolTypeInference.inferType(getScope(), left);
|
||||
SymbolType rightType = SymbolTypeInference.inferType(getScope(), right);
|
||||
if(SymbolType.isInteger(leftType) && !SymbolType.NUMBER.equals(leftType) && SymbolType.NUMBER.equals(rightType)) {
|
||||
SymbolTypeIntegerFixed leftIntType = (SymbolTypeIntegerFixed) leftType;
|
||||
// Attempt to find number conversion!
|
||||
if(right instanceof ConstantValue) {
|
||||
ConstantLiteral constantLiteral = ((ConstantValue) right).calculateLiteral(getProgram().getScope());
|
||||
if(constantLiteral instanceof ConstantInteger) {
|
||||
ConstantInteger constantInteger = (ConstantInteger) constantLiteral;
|
||||
if(SymbolType.NUMBER.equals(constantInteger.getType())) {
|
||||
Long value = constantInteger.getValue();
|
||||
if(leftIntType.getMinValue()<=value && leftIntType.getMaxValue()>=value) {
|
||||
// The value matches the left type!
|
||||
getLog().append("Adding number conversion cast ("+leftIntType+") "+binaryExpression.getRight().toString()+" in "+currentStmt.toString(getProgram(), false));
|
||||
binaryExpression.addRightCast(leftIntType);
|
||||
} else {
|
||||
throw new InternalError("TODO: Implement number conversion for non-equal types "+right.toString(), currentStmt);
|
||||
}
|
||||
} else {
|
||||
throw new InternalError("Non-number constant has type number "+right.toString(), currentStmt);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Postpone til later!
|
||||
// Maybe handle AssignmentRValue separately!
|
||||
getLog().append("Postponed number conversion " + right.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,15 +1,19 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.Comment;
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.operators.Operators;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementAssignment;
|
||||
import dk.camelot64.kickc.model.symbols.Scope;
|
||||
import dk.camelot64.kickc.model.symbols.VariableIntermediate;
|
||||
import dk.camelot64.kickc.model.types.*;
|
||||
import dk.camelot64.kickc.model.values.ConstantInteger;
|
||||
import dk.camelot64.kickc.model.values.LValue;
|
||||
import dk.camelot64.kickc.model.values.RValue;
|
||||
import dk.camelot64.kickc.model.values.ScopeRef;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
@ -31,7 +35,7 @@ public class PassNAddTypeConversions extends Pass2SsaOptimization {
|
||||
while(stmtIt.hasNext()) {
|
||||
Statement statement = stmtIt.next();
|
||||
if(statement instanceof StatementAssignment) {
|
||||
doConversionAssignment((StatementAssignment) statement, stmtIt);
|
||||
doConversionAssignment((StatementAssignment) statement, stmtIt, block);
|
||||
}
|
||||
// TODO: Implement conversion for calls
|
||||
}
|
||||
@ -48,7 +52,7 @@ public class PassNAddTypeConversions extends Pass2SsaOptimization {
|
||||
* @param assignment The assignment to examine
|
||||
* @param stmtIt Iterator allowing the method to add a tmp-var-assignment.
|
||||
*/
|
||||
private void doConversionAssignment(StatementAssignment assignment, ListIterator<Statement> stmtIt) {
|
||||
private void doConversionAssignment(StatementAssignment assignment, ListIterator<Statement> stmtIt, ControlFlowBlock block) {
|
||||
LValue lValue = assignment.getlValue();
|
||||
SymbolType lValueType = SymbolTypeInference.inferType(getScope(), lValue);
|
||||
SymbolType rValueType = SymbolTypeInference.inferTypeRValue(getScope(), assignment);
|
||||
@ -64,14 +68,14 @@ public class PassNAddTypeConversions extends Pass2SsaOptimization {
|
||||
}
|
||||
for(SymbolTypeIntegerFixed potentialType : potentialTypes) {
|
||||
if(lValueType.equals(potentialType) || canConvert(lValueType, potentialType)) {
|
||||
addConversionCast(assignment, lValueType, rValueType);
|
||||
addConversionCast(assignment, stmtIt, block, lValueType, rValueType);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No direct type match - attempt conversion
|
||||
if(canConvert(lValueType, rValueType)) {
|
||||
addConversionCast(assignment, lValueType, rValueType);
|
||||
addConversionCast(assignment, stmtIt, block, lValueType, rValueType);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -90,7 +94,7 @@ public class PassNAddTypeConversions extends Pass2SsaOptimization {
|
||||
* @param lValueType The type of the lValue
|
||||
* @param rValueType The type of the rValue
|
||||
*/
|
||||
private void addConversionCast(StatementAssignment assignment, SymbolType lValueType, SymbolType rValueType) {
|
||||
private void addConversionCast(StatementAssignment assignment, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock, SymbolType lValueType, SymbolType rValueType) {
|
||||
// Promotion possible - add tmp-var and a cast
|
||||
if(assignment.getOperator() == null) {
|
||||
// No operator - add cast directly!
|
||||
@ -100,11 +104,16 @@ public class PassNAddTypeConversions extends Pass2SsaOptimization {
|
||||
} else {
|
||||
assignment.setOperator(Operators.getCastUnary(lValueType));
|
||||
}
|
||||
if(getLog().isVerbosePass1CreateSsa()) {
|
||||
getLog().append("Converting " + rValueType + " to " + lValueType + " in " + assignment);
|
||||
}
|
||||
getLog().append("Converting " + rValueType + " to " + lValueType + " in " + assignment);
|
||||
} else {
|
||||
throw new RuntimeException("Tmp-var conversion not implemented yet " + assignment);
|
||||
ScopeRef currentScope = currentBlock.getScope();
|
||||
Scope blockScope = getScope().getScope(currentScope);
|
||||
VariableIntermediate tmpVar = blockScope.addVariableIntermediate();
|
||||
tmpVar.setType(rValueType);
|
||||
StatementAssignment newAssignment = new StatementAssignment(assignment.getlValue(), Operators.getCastUnary(lValueType), tmpVar.getRef(), assignment.getSource(), Comment.NO_COMMENTS);
|
||||
getLog().append("Converting " + rValueType + " to " + lValueType + " in " + assignment + " adding "+tmpVar);
|
||||
assignment.setlValue(tmpVar.getRef());
|
||||
stmtIt.add(newAssignment);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,8 +33,18 @@ public class TestPrograms {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntegerLiteralsMin() throws IOException, URISyntaxException {
|
||||
compileAndCompare("int-literals-min");
|
||||
public void testNumberConversion() throws IOException, URISyntaxException {
|
||||
compileAndCompare("number-conversion", log());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNumberType() throws IOException, URISyntaxException {
|
||||
compileAndCompare("number-type");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntegerConversion() throws IOException, URISyntaxException {
|
||||
compileAndCompare("int-conversion");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -42,11 +52,6 @@ public class TestPrograms {
|
||||
compileAndCompare("int-literals");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNumberType() throws IOException, URISyntaxException {
|
||||
compileAndCompare("number-type", log());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleLoop() throws IOException, URISyntaxException {
|
||||
compileAndCompare("simple-loop");
|
||||
@ -59,7 +64,7 @@ public class TestPrograms {
|
||||
|
||||
@Test
|
||||
public void testPaulNelsenSandboxTernaryError() throws IOException, URISyntaxException {
|
||||
compileAndCompare("sandbox-ternary-error", log().verboseParse().verboseCreateSsa().setVerboseSSAOptimize().verboseStatementSequence());
|
||||
compileAndCompare("sandbox-ternary-error");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -75,7 +80,7 @@ public class TestPrograms {
|
||||
|
||||
@Test
|
||||
public void testTypeIdPlusByteProblem() throws IOException, URISyntaxException {
|
||||
compileAndCompare("typeid-plus-byte-problem", log());
|
||||
compileAndCompare("typeid-plus-byte-problem");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
90
src/test/kc/int-conversion.kc
Normal file
90
src/test/kc/int-conversion.kc
Normal file
@ -0,0 +1,90 @@
|
||||
// Tests different integer literal types
|
||||
|
||||
const byte RED = 2ub;
|
||||
const byte GREEN = 5ub;
|
||||
|
||||
const byte* SCREEN = $0400uw;
|
||||
const byte* COLS = $d800uw;
|
||||
byte idx = 0ub;
|
||||
|
||||
void main() {
|
||||
for(byte* s=SCREEN;s<SCREEN+1000uw;s++) *s = ' ';
|
||||
testUnaryOperator();
|
||||
testBinaryOperator();
|
||||
}
|
||||
|
||||
void testUnaryOperator() {
|
||||
idx = 00ub;
|
||||
// Unary Operations
|
||||
assertType(typeid(-12ub), typeid(unsigned byte));
|
||||
assertType(typeid(-12sb), typeid(signed byte));
|
||||
assertType(typeid(-12uw), typeid(unsigned word));
|
||||
assertType(typeid(-12sw), typeid(signed word));
|
||||
assertType(typeid(-12ud), typeid(unsigned dword));
|
||||
assertType(typeid(-12sd), typeid(signed dword));
|
||||
}
|
||||
|
||||
void testBinaryOperator() {
|
||||
idx = 40ub;
|
||||
// Binary Operations between unsigned byte & other types
|
||||
assertType(typeid(12ub+12ub), typeid(unsigned byte));
|
||||
assertType(typeid(12ub+12sb), typeid(unsigned byte));
|
||||
assertType(typeid(12ub+12uw), typeid(unsigned word));
|
||||
assertType(typeid(12ub+12sw), typeid(signed word));
|
||||
assertType(typeid(12ub+12ud), typeid(unsigned dword));
|
||||
assertType(typeid(12ub+12sd), typeid(signed dword));
|
||||
idx++;
|
||||
// Binary Operations between signed byte & other types
|
||||
assertType(typeid(12sb+12ub), typeid(unsigned byte));
|
||||
assertType(typeid(12sb+12sb), typeid(signed byte));
|
||||
assertType(typeid(12sb+12uw), typeid(unsigned word));
|
||||
assertType(typeid(12sb+12sw), typeid(signed word));
|
||||
assertType(typeid(12sb+12ud), typeid(unsigned dword));
|
||||
assertType(typeid(12sb+12sd), typeid(signed dword));
|
||||
idx++;
|
||||
// Binary Operations between unsigned word & other types
|
||||
assertType(typeid(12uw+12ub), typeid(unsigned word));
|
||||
assertType(typeid(12uw+12sb), typeid(unsigned word));
|
||||
assertType(typeid(12uw+12uw), typeid(unsigned word));
|
||||
assertType(typeid(12uw+12sw), typeid(unsigned word));
|
||||
assertType(typeid(12uw+12ud), typeid(unsigned dword));
|
||||
assertType(typeid(12uw+12sd), typeid(signed dword));
|
||||
idx = 80ub;
|
||||
// Binary Operations between signed word & other types
|
||||
assertType(typeid(12sw+12ub), typeid(signed word));
|
||||
assertType(typeid(12sw+12sb), typeid(signed word));
|
||||
assertType(typeid(12sw+12uw), typeid(unsigned word));
|
||||
assertType(typeid(12sw+12sw), typeid(signed word));
|
||||
assertType(typeid(12sw+12ud), typeid(unsigned dword));
|
||||
assertType(typeid(12sw+12sd), typeid(signed dword));
|
||||
idx++;
|
||||
// Binary Operations between unsigned dword & other types
|
||||
assertType(typeid(12ud+12ub), typeid(unsigned dword));
|
||||
assertType(typeid(12ud+12sb), typeid(unsigned dword));
|
||||
assertType(typeid(12ud+12uw), typeid(unsigned dword));
|
||||
assertType(typeid(12ud+12sw), typeid(unsigned dword));
|
||||
assertType(typeid(12ud+12ud), typeid(unsigned dword));
|
||||
assertType(typeid(12ud+12sd), typeid(unsigned dword));
|
||||
idx++;
|
||||
// Binary Operations between signed dword & other types
|
||||
assertType(typeid(12sd+12ub), typeid(signed dword));
|
||||
assertType(typeid(12sd+12sb), typeid(signed dword));
|
||||
assertType(typeid(12sd+12uw), typeid(signed dword));
|
||||
assertType(typeid(12sd+12sw), typeid(signed dword));
|
||||
assertType(typeid(12sd+12ud), typeid(unsigned dword));
|
||||
assertType(typeid(12sd+12sd), typeid(signed dword));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Check that the two passed type IDs are equal.
|
||||
// Shows a letter symbolizing t1
|
||||
// If they are equal the letter is green - if not it is red.
|
||||
void assertType(byte t1, byte t2) {
|
||||
if(t1==t2) {
|
||||
COLS[idx] = GREEN;
|
||||
} else {
|
||||
COLS[idx] = RED;
|
||||
}
|
||||
SCREEN[idx++] = t1;
|
||||
}
|
@ -10,8 +10,6 @@ byte idx = 0ub;
|
||||
void main() {
|
||||
for(byte* s=SCREEN;s<SCREEN+1000uw;s++) *s = ' ';
|
||||
testSimpleTypes();
|
||||
testUnaryOperator();
|
||||
testBinaryOperator();
|
||||
}
|
||||
|
||||
void testSimpleTypes() {
|
||||
@ -34,70 +32,6 @@ void testSimpleTypes() {
|
||||
assertType(typeid(12l), typeid(signed dword));
|
||||
}
|
||||
|
||||
void testUnaryOperator() {
|
||||
idx = 40ub;
|
||||
// Unary Operations
|
||||
assertType(typeid(-12ub), typeid(unsigned byte));
|
||||
assertType(typeid(-12sb), typeid(signed byte));
|
||||
assertType(typeid(-12uw), typeid(unsigned word));
|
||||
assertType(typeid(-12sw), typeid(signed word));
|
||||
assertType(typeid(-12ud), typeid(unsigned dword));
|
||||
assertType(typeid(-12sd), typeid(signed dword));
|
||||
}
|
||||
|
||||
void testBinaryOperator() {
|
||||
idx = 80ub;
|
||||
// Binary Operations between unsigned byte & other types
|
||||
assertType(typeid(12ub+12ub), typeid(unsigned byte));
|
||||
assertType(typeid(12ub+12sb), typeid(unsigned byte));
|
||||
assertType(typeid(12ub+12uw), typeid(unsigned word));
|
||||
assertType(typeid(12ub+12sw), typeid(signed word));
|
||||
assertType(typeid(12ub+12ud), typeid(unsigned dword));
|
||||
assertType(typeid(12ub+12sd), typeid(signed dword));
|
||||
idx++;
|
||||
// Binary Operations between signed byte & other types
|
||||
assertType(typeid(12sb+12ub), typeid(unsigned byte));
|
||||
assertType(typeid(12sb+12sb), typeid(signed byte));
|
||||
assertType(typeid(12sb+12uw), typeid(unsigned word));
|
||||
assertType(typeid(12sb+12sw), typeid(signed word));
|
||||
assertType(typeid(12sb+12ud), typeid(unsigned dword));
|
||||
assertType(typeid(12sb+12sd), typeid(signed dword));
|
||||
idx++;
|
||||
// Binary Operations between unsigned word & other types
|
||||
assertType(typeid(12uw+12ub), typeid(unsigned word));
|
||||
assertType(typeid(12uw+12sb), typeid(unsigned word));
|
||||
assertType(typeid(12uw+12uw), typeid(unsigned word));
|
||||
assertType(typeid(12uw+12sw), typeid(unsigned word));
|
||||
assertType(typeid(12uw+12ud), typeid(unsigned dword));
|
||||
assertType(typeid(12uw+12sd), typeid(signed dword));
|
||||
idx = 120ub;
|
||||
// Binary Operations between signed word & other types
|
||||
assertType(typeid(12sw+12ub), typeid(signed word));
|
||||
assertType(typeid(12sw+12sb), typeid(signed word));
|
||||
assertType(typeid(12sw+12uw), typeid(unsigned word));
|
||||
assertType(typeid(12sw+12sw), typeid(signed word));
|
||||
assertType(typeid(12sw+12ud), typeid(unsigned dword));
|
||||
assertType(typeid(12sw+12sd), typeid(signed dword));
|
||||
idx++;
|
||||
// Binary Operations between unsigned dword & other types
|
||||
assertType(typeid(12ud+12ub), typeid(unsigned dword));
|
||||
assertType(typeid(12ud+12sb), typeid(unsigned dword));
|
||||
assertType(typeid(12ud+12uw), typeid(unsigned dword));
|
||||
assertType(typeid(12ud+12sw), typeid(unsigned dword));
|
||||
assertType(typeid(12ud+12ud), typeid(unsigned dword));
|
||||
assertType(typeid(12ud+12sd), typeid(unsigned dword));
|
||||
idx++;
|
||||
// Binary Operations between signed dword & other types
|
||||
assertType(typeid(12sd+12ub), typeid(signed dword));
|
||||
assertType(typeid(12sd+12sb), typeid(signed dword));
|
||||
assertType(typeid(12sd+12uw), typeid(signed dword));
|
||||
assertType(typeid(12sd+12sw), typeid(signed dword));
|
||||
assertType(typeid(12sd+12ud), typeid(unsigned dword));
|
||||
assertType(typeid(12sd+12sd), typeid(signed dword));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Check that the two passed type IDs are equal.
|
||||
// Shows a letter symbolizing t1
|
||||
// If they are equal the letter is green - if not it is red.
|
||||
|
83
src/test/kc/number-conversion.kc
Normal file
83
src/test/kc/number-conversion.kc
Normal file
@ -0,0 +1,83 @@
|
||||
// Tests conversion of numbers to correct int types
|
||||
// See https://gitlab.com/camelot/kickc/issues/181
|
||||
|
||||
void main() {
|
||||
|
||||
// Signed type and number
|
||||
// a) If one operand is a signed type and the other a number.
|
||||
// The number becomes the smallest signed type that can hold its value (if one exists).
|
||||
// The two operands are then converted normally (using 2a or 2b).
|
||||
idx = 0ub;
|
||||
assertType(typeid(12sb+12), typeid(signed byte));
|
||||
assertType(typeid(12sb+130), typeid(signed word));
|
||||
assertType(typeid(12sb+32000), typeid(signed dword));
|
||||
assertType(typeid(12sw+12), typeid(signed word));
|
||||
assertType(typeid(12sw+130), typeid(signed word));
|
||||
assertType(typeid(12sw+100000), typeid(signed dword));
|
||||
assertType(typeid(12sd+12), typeid(signed dword));
|
||||
assertType(typeid(12sd+130), typeid(signed dword));
|
||||
assertType(typeid(12sd+100000), typeid(signed dword));
|
||||
// Test number larger than largest signed type
|
||||
assertType(typeid(12sb+3000000000), typeid(unsigned dword));
|
||||
|
||||
// Unsigned type and positive number
|
||||
// b) If one operand is an unsigned type and the other a positive number.
|
||||
// The number is converted to the smallest unsigned type that can hold the value.
|
||||
// The two operands are then converted normally (using 2a or 2b).
|
||||
idx = 40ub;
|
||||
assertType(typeid(12ub+12), typeid(unsigned byte));
|
||||
assertType(typeid(12ub+250), typeid(unsigned byte));
|
||||
assertType(typeid(12ub+300), typeid(unsigned word));
|
||||
assertType(typeid(12ub+65534), typeid(unsigned word));
|
||||
assertType(typeid(12ub+66000), typeid(unsigned dword));
|
||||
assertType(typeid(12uw+12), typeid(unsigned word));
|
||||
assertType(typeid(12uw+130), typeid(unsigned word));
|
||||
assertType(typeid(12uw+66000), typeid(unsigned dword));
|
||||
assertType(typeid(12ud+12), typeid(unsigned dword));
|
||||
assertType(typeid(12ud+130), typeid(unsigned dword));
|
||||
assertType(typeid(12ud+66000), typeid(unsigned dword));
|
||||
assertType(typeid(12sb+3000000000), typeid(unsigned dword));
|
||||
|
||||
// Unsigned type and negative number
|
||||
// If one operand is an unsigned type and the other a negative number.
|
||||
// The number is first converted to the smallest signed type that can hold its value (if one exits).
|
||||
// If the signed type is smaller than the unsigned type it is converted up to the size of the unsigned type.
|
||||
// The signed type is finally converted to unsigned.
|
||||
// The two unsigned operands are then finally converted to the size of the largest type (using 2b).
|
||||
idx = 80ub;
|
||||
assertType(typeid(12ub+-12), typeid(unsigned byte));
|
||||
assertType(typeid(12ub+-120), typeid(unsigned byte));
|
||||
assertType(typeid(12ub+-250), typeid(unsigned word));
|
||||
assertType(typeid(12ub+-32000), typeid(unsigned dword));
|
||||
assertType(typeid(12ub+-66000), typeid(unsigned dword));
|
||||
assertType(typeid(12uw+-12), typeid(unsigned word));
|
||||
assertType(typeid(12uw+-130), typeid(unsigned word));
|
||||
assertType(typeid(12uw+-32000), typeid(unsigned dword));
|
||||
assertType(typeid(12ud+-12), typeid(unsigned dword));
|
||||
assertType(typeid(12ud+-130), typeid(unsigned dword));
|
||||
assertType(typeid(12ud+-66000), typeid(unsigned dword));
|
||||
assertType(typeid(12sb+-3000000000), typeid(unsigned dword));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const byte RED = 2ub;
|
||||
const byte GREEN = 5ub;
|
||||
|
||||
const byte* SCREEN = $0400uw;
|
||||
const byte* COLS = $d800uw;
|
||||
byte idx = 0ub;
|
||||
|
||||
// Check that the two passed type IDs are equal.
|
||||
// Shows a letter symbolizing t1
|
||||
// If they are equal the letter is green - if not it is red.
|
||||
void assertType(byte t1, byte t2) {
|
||||
if(t1==t2) {
|
||||
COLS[idx] = GREEN;
|
||||
} else {
|
||||
COLS[idx] = RED;
|
||||
}
|
||||
SCREEN[idx++] = t1;
|
||||
}
|
@ -1,23 +1,44 @@
|
||||
// Tests the number type used for constant expressions
|
||||
|
||||
const byte* SCREENB = 0x0400;
|
||||
|
||||
void main() {
|
||||
// Constant values resolvable to bytes
|
||||
byte idx = 0;
|
||||
SCREENB[idx++] = 12;
|
||||
SCREENB[idx++] = 6+6;
|
||||
SCREENB[idx++] = 18-6;
|
||||
SCREENB[idx++] = 1812-1800;
|
||||
SCREENB[idx++] = 1+2+3+6;
|
||||
SCREENB[idx++] = 2*6;
|
||||
SCREENB[idx++] = 3<<2;
|
||||
SCREENB[idx++] = 24>>1;
|
||||
SCREENB[idx++] = 15&28;
|
||||
SCREENB[idx++] = 4|8;
|
||||
SCREENB[idx++] = 5^9;
|
||||
SCREENB[idx++] = (2+2)*(15/5);
|
||||
SCREENB[idx++] = (byte)(4096+12);
|
||||
testBytes();
|
||||
testSBytes();
|
||||
}
|
||||
|
||||
void testBytes() {
|
||||
// Constant values resolvable to bytes
|
||||
const byte* SCREEN = 0x0400;
|
||||
byte idx = 0;
|
||||
SCREEN[idx++] = 12;
|
||||
SCREEN[idx++] = 6+6;
|
||||
SCREEN[idx++] = 18-6;
|
||||
SCREEN[idx++] = 1812-1800;
|
||||
SCREEN[idx++] = 1+2+3+6;
|
||||
SCREEN[idx++] = 2*6;
|
||||
SCREEN[idx++] = 3<<2;
|
||||
SCREEN[idx++] = 24>>1;
|
||||
SCREEN[idx++] = 15&28;
|
||||
SCREEN[idx++] = 4|8;
|
||||
SCREEN[idx++] = 5^9;
|
||||
SCREEN[idx++] = (2+2)*(15/5);
|
||||
SCREEN[idx++] = (byte)(4096+12);
|
||||
}
|
||||
|
||||
void testSBytes() {
|
||||
// Constant values resolvable to signed bytes
|
||||
const signed byte* SCREEN = 0x0428;
|
||||
byte idx = 0;
|
||||
SCREEN[idx++] = -12;
|
||||
SCREEN[idx++] = -6-6;
|
||||
SCREEN[idx++] = -18+6;
|
||||
SCREEN[idx++] = -1812+1800;
|
||||
SCREEN[idx++] = -1-2-3-6;
|
||||
SCREEN[idx++] = -2*6;
|
||||
SCREEN[idx++] = -3<<2;
|
||||
SCREEN[idx++] = -24>>1;
|
||||
SCREEN[idx++] = -4&-9;
|
||||
SCREEN[idx++] = -0x10|-0xfc;
|
||||
SCREEN[idx++] = (-2-2)*(15/5);
|
||||
SCREEN[idx++] = (signed byte)(4096-12);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user