1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-06-26 19:30:00 +00:00

VariableBuilder has replaced VariableBuilderContext.

This commit is contained in:
jespergravgaard 2019-12-22 22:04:30 +01:00
parent e103a783ce
commit 9811e48039
5 changed files with 68 additions and 189 deletions

View File

@ -15,6 +15,9 @@ import java.util.List;
*/
public class VariableBuilder {
/** The variable name. */
private String varName;
/** The scope of the variable. */
private Scope scope;
@ -30,12 +33,46 @@ public class VariableBuilder {
/** The directives of the variable declaration. */
private List<Directive> directives;
public VariableBuilder(Scope scope, boolean isParameter, SymbolType type, ArraySpec arraySpec, List<Directive> directives) {
/** The data segment. */
private String dataSegment;
public VariableBuilder(String varName, Scope scope, boolean isParameter, SymbolType type, ArraySpec arraySpec, List<Directive> directives, String dataSegment) {
this.varName = varName;
this.scope = scope;
this.isParameter = isParameter;
this.type = type;
this.arraySpec = arraySpec;
this.directives = directives;
this.dataSegment = dataSegment;
}
/**
* Build the variable with the properties derived from type, scope, directives and configuration.
* @return The variable
*/
public Variable build() {
Variable variable;
if(isConstant()) {
variable = Variable.createConstant(varName, type, scope, arraySpec, null, dataSegment);
} else if(this.isSingleStaticAssignment()) {
// Create single-static-assignment PHI-master variable
variable = Variable.createPhiMaster(varName, type, scope, getMemoryArea(), dataSegment);
} else {
// Create multiple-assignment variable
variable = Variable.createLoadStore(varName, type, scope, getMemoryArea(), dataSegment);
}
variable.setDeclaredConst(this.isConstant());
variable.setDeclaredVolatile(this.isVolatile());
variable.setDeclaredExport(this.isExport());
variable.setDeclaredAsRegister(this.isOptimize());
variable.setDeclaredRegister(this.getRegister());
if(variable.getDeclaredRegister() instanceof Registers.RegisterMainMem) {
((Registers.RegisterMainMem) variable.getDeclaredRegister()).setVariableRef(variable.getVariableRef());
}
variable.setMemoryArea(this.getMemoryArea());
variable.setDeclaredAlignment(this.getAlignment());
scope.add(variable);
return variable;
}
/**
@ -174,7 +211,8 @@ public class VariableBuilder {
return hasDirective(Directive.ToConst.class);
}
/** Declared as export (__export keyword)
/**
* Declared as export (__export keyword)
*
* @return true if declared as export
*/
@ -243,13 +281,14 @@ public class VariableBuilder {
/**
* Get any memory-alignment of the variables data
* @return
*
* @return The memory alignment
*/
public Integer getAlignment() {
Directive.Align alignDirective = findDirective(Directive.Align.class);
if(alignDirective != null) {
if(isArray()) {
return alignDirective.alignment;
return alignDirective.alignment;
} else {
// TODO: Add information about which variable (name) and the offending source line
throw new CompileError("Error! Cannot align variable that is not an array.");
@ -294,11 +333,10 @@ public class VariableBuilder {
* Examines whether a specific directive is present in the source
*
* @param directiveClass The class of the type to look for
* @param directives The list of directives to search
* @param <DirectiveClass> The class of the type to look for
* @return true if the directive if found. false otherwise.
*/
private <DirectiveClass extends Directive> boolean hasDirective(Class<DirectiveClass> directiveClass) {
public <DirectiveClass extends Directive> boolean hasDirective(Class<DirectiveClass> directiveClass) {
return findDirective(directiveClass) != null;
}
@ -306,7 +344,6 @@ public class VariableBuilder {
* Look for a specific directive type in a list of directives
*
* @param directiveClass The class of the type to look for
* @param directives The list of directives to search
* @param <DirectiveClass> The class of the type to look for
* @return The directive if found. null if not found.
*/

View File

@ -1,110 +0,0 @@
package dk.camelot64.kickc.model;
import dk.camelot64.kickc.model.statements.StatementSource;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.values.VariableRef;
import java.util.List;
/**
* Used for creating {@link Variable}s with the right properties based on all their directives
*/
public class VariableBuilderContext {
public VariableBuilderContext() {
}
/**
* Applies directives to a variable.
*
* @param lValue The variable to apply directives to
* @param sourceDirectives The directives found in the source code
* @param source The source line (for exceptions)
*/
public void applyDirectives(Variable lValue, boolean isParameter, boolean isArray, List<Directive> sourceDirectives, StatementSource source) {
if(hasDirective(Directive.Const.class, sourceDirectives))
lValue.setDeclaredConst(true);
if(isArray)
lValue.setDeclaredConst(true);
if(hasDirective(Directive.Volatile.class, sourceDirectives))
lValue.setDeclaredVolatile(true);
if(hasDirective(Directive.Export.class, sourceDirectives))
lValue.setDeclaredExport(true);
if(hasDirective(Directive.Register.class, sourceDirectives)) {
lValue.setMemoryArea(Variable.MemoryArea.ZEROPAGE_MEMORY);
lValue.setDeclaredAsRegister(true);
}
if(isArray)
lValue.setMemoryArea(Variable.MemoryArea.MAIN_MEMORY);
if(hasDirective(Directive.MemZp.class, sourceDirectives))
lValue.setMemoryArea(Variable.MemoryArea.ZEROPAGE_MEMORY);
if(hasDirective(Directive.MemMain.class, sourceDirectives))
lValue.setMemoryArea(Variable.MemoryArea.MAIN_MEMORY);
Directive.Address addressDirective = findDirective(Directive.Address.class, sourceDirectives);
if(addressDirective != null) {
Variable.MemoryArea memoryArea = (addressDirective.address < 0x100) ? Variable.MemoryArea.ZEROPAGE_MEMORY : Variable.MemoryArea.MAIN_MEMORY;
if(Variable.MemoryArea.ZEROPAGE_MEMORY.equals(memoryArea)) {
lValue.setMemoryArea(Variable.MemoryArea.ZEROPAGE_MEMORY);
Registers.Register register = new Registers.RegisterZpMem(addressDirective.address.intValue(), -1, true);
lValue.setDeclaredRegister(register);
} else {
lValue.setMemoryArea(Variable.MemoryArea.MAIN_MEMORY);
Registers.Register register = new Registers.RegisterMainMem((VariableRef) lValue.getRef(), -1, addressDirective.address);
lValue.setDeclaredRegister(register);
}
}
Directive.NamedRegister registerDirective = findDirective(Directive.NamedRegister.class, sourceDirectives);
if(registerDirective != null) {
lValue.setDeclaredAsRegister(true);
Registers.Register register = Registers.getRegister(registerDirective.name);
if(register == null) {
throw new CompileError("Error! Unknown register " + registerDirective.name, source);
}
lValue.setDeclaredRegister(register);
}
Directive.Align alignDirective = findDirective(Directive.Align.class, sourceDirectives);
if(alignDirective != null) {
if(isArray) {
lValue.setDeclaredAlignment(alignDirective.alignment);
} else {
throw new CompileError("Error! Cannot align variable that is not a string or an array " + lValue.toString(), source);
}
}
// TODO: Add strategy for selecting main memory for non-pointer local variables
}
/**
* Examines whether a specific directive is present in the source
*
* @param directiveClass The class of the type to look for
* @param directives The list of directives to search
* @param <DirectiveClass> The class of the type to look for
* @return true if the directive if found. false otherwise.
*/
private <DirectiveClass extends Directive> boolean hasDirective(Class<DirectiveClass> directiveClass, List<Directive> directives) {
return findDirective(directiveClass, directives) != null;
}
/**
* Look for a specific directive type in a list of directives
*
* @param directiveClass The class of the type to look for
* @param directives The list of directives to search
* @param <DirectiveClass> The class of the type to look for
* @return The directive if found. null if not found.
*/
private <DirectiveClass extends Directive> DirectiveClass findDirective(Class<DirectiveClass> directiveClass, List<Directive> directives) {
if(directives == null) return null;
for(Directive directive : directives) {
if(directiveClass.isInstance(directive)) {
return (DirectiveClass) directive;
}
}
// Not found!
return null;
}
}

View File

@ -103,7 +103,6 @@ public class Procedure extends Scope {
public void setParameters(List<Variable> parameters) {
this.parameterNames = new ArrayList<>();
for(Variable parameter : parameters) {
add(parameter);
parameterNames.add(parameter.getLocalName());
}
}

View File

@ -125,9 +125,9 @@ public class Variable implements Symbol {
this.type = type;
this.scope = scope;
this.arraySpec = arraySpec;
this.initValue = initValue;
this.dataSegment = dataSegment;
this.memoryArea = memoryArea;
this.initValue = initValue;
this.comments = new ArrayList<>();
setFullName();
}

View File

@ -47,8 +47,6 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
private Stack<Scope> scopeStack;
/** The memory area used by default for variables. */
private Variable.MemoryArea defaultMemoryArea;
/** Context used for adding directives to variables. */
private VariableBuilderContext directiveContext;
public Pass0GenerateStatementSequence(CParser cParser, KickCParser.FileContext fileCtx, Program program) {
this.cParser = cParser;
@ -57,7 +55,6 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
this.sequence = program.getStatementSequence();
this.scopeStack = new Stack<>();
this.defaultMemoryArea = Variable.MemoryArea.ZEROPAGE_MEMORY;
this.directiveContext = new VariableBuilderContext();
scopeStack.push(program.getScope());
}
@ -266,11 +263,12 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
@Override
public Object visitParameterDeclType(KickCParser.ParameterDeclTypeContext ctx) {
this.visitDeclTypes(ctx.declTypes());
SymbolType type = declVarType;
List<Directive> directives = declVarDirectives;
Variable param = Variable.createPhiMaster(ctx.NAME().getText(), type, getCurrentScope(), defaultMemoryArea, currentDataSegment);
// Add directives
directiveContext.applyDirectives(param, true, false, directives, new StatementSource(ctx));
String varName = ctx.NAME().getText();
VariableBuilder varBuilder = new VariableBuilder(varName, getCurrentScope(), true, declVarType, null, declVarDirectives, currentDataSegment);
// TODO: const parameter pointer should be no-modify!
if(varBuilder.hasDirective(Directive.Const.class))
throw new CompileError("Error! Const parameters not supported " + varName + " in " + getCurrentScope().getFullName() + "()");
Variable param = varBuilder.build();
exitDeclTypes();
return param;
}
@ -578,56 +576,18 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
PrePostModifierHandler.addPreModifiers(this, initializer, statementSource);
RValue initValue = (initializer == null) ? null : (RValue) visit(initializer);
initValue = Initializers.getInitValue(initValue, declVarType, declIsArray, declArraySize, program, statementSource);
VariableBuilder varBuilder = new VariableBuilder(getCurrentScope(), false, declVarType, arraySpec, declVarDirectives);
if(varBuilder.isConstant()) {
Scope scope = getCurrentScope();
VariableBuilder varBuilder = new VariableBuilder(varName, getCurrentScope(), false, declVarType, arraySpec, declVarDirectives, currentDataSegment);
Variable variable = varBuilder.build();
if(variable.isKindConstant()) {
// Set constant value
ConstantValue constInitValue = getConstInitValue(initValue, initializer, statementSource);
Variable constVar = Variable.createConstant(varName, declVarType, scope, arraySpec, constInitValue, currentDataSegment);
constVar.setDeclaredConst(varBuilder.isConstant());
constVar.setDeclaredVolatile(varBuilder.isVolatile());
constVar.setDeclaredExport(varBuilder.isExport());
constVar.setDeclaredAsRegister(varBuilder.isOptimize());
constVar.setDeclaredRegister(varBuilder.getRegister());
constVar.setMemoryArea(varBuilder.getMemoryArea());
constVar.setDeclaredAlignment(varBuilder.getAlignment());
scope.add(constVar);
variable.setInitValue(constInitValue);
// Add comments to constant
constVar.setComments(ensureUnusedComments(declVarComments));
} else if(varBuilder.isSingleStaticAssignment()) {
// Create SSA PHI-master variable
Variable lValue = Variable.createPhiMaster(varName, declVarType, getCurrentScope(), defaultMemoryArea, currentDataSegment);
lValue.setDeclaredConst(varBuilder.isConstant());
lValue.setDeclaredVolatile(varBuilder.isVolatile());
lValue.setDeclaredExport(varBuilder.isExport());
lValue.setDeclaredAsRegister(varBuilder.isOptimize());
lValue.setDeclaredRegister(varBuilder.getRegister());
if(lValue.getDeclaredRegister() instanceof Registers.RegisterMainMem) {
((Registers.RegisterMainMem) lValue.getDeclaredRegister()).setVariableRef(lValue.getVariableRef());
}
lValue.setMemoryArea(varBuilder.getMemoryArea());
lValue.setDeclaredAlignment(varBuilder.getAlignment());
getCurrentScope().add(lValue);
if(!declVarStructMember) {
Statement initStmt = new StatementAssignment(lValue.getVariableRef(), initValue, statementSource, ensureUnusedComments(declVarComments));
sequence.addStatement(initStmt);
}
} else {
Variable lValue = Variable.createLoadStore(varName, declVarType, getCurrentScope(), defaultMemoryArea, currentDataSegment);
lValue.setDeclaredConst(varBuilder.isConstant());
lValue.setDeclaredVolatile(varBuilder.isVolatile());
lValue.setDeclaredExport(varBuilder.isExport());
lValue.setDeclaredAsRegister(varBuilder.isOptimize());
lValue.setDeclaredRegister(varBuilder.getRegister());
if(lValue.getDeclaredRegister() instanceof Registers.RegisterMainMem) {
((Registers.RegisterMainMem) lValue.getDeclaredRegister()).setVariableRef(lValue.getVariableRef());
}
lValue.setMemoryArea(varBuilder.getMemoryArea());
lValue.setDeclaredAlignment(varBuilder.getAlignment());
getCurrentScope().add(lValue);
if(!declVarStructMember) {
Statement initStmt = new StatementAssignment(lValue.getVariableRef(), initValue, statementSource, ensureUnusedComments(declVarComments));
sequence.addStatement(initStmt);
}
variable.setComments(ensureUnusedComments(declVarComments));
}
if(!variable.isKindConstant() && !declVarStructMember) {
Statement initStmt = new StatementAssignment(variable.getVariableRef(), initValue, statementSource, ensureUnusedComments(declVarComments));
sequence.addStatement(initStmt);
}
if(initializer != null)
PrePostModifierHandler.addPostModifiers(this, initializer, statementSource);
@ -687,11 +647,12 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
}
// Add a constant variable
Scope scope = getCurrentScope();
Variable constVar = Variable.createConstant(varName, declVarType, scope, arraySpec, constantArrayKickAsm, currentDataSegment);
scope.add(constVar);
VariableBuilder varBuilder = new VariableBuilder(varName, scope, declIsArray, declVarType, arraySpec, declVarDirectives, currentDataSegment);
Variable variable = varBuilder.build();
// Set constant value
variable.setInitValue(getConstInitValue(constantArrayKickAsm, null, statementSource));
// Add comments to constant
constVar.setComments(ensureUnusedComments(declVarComments));
directiveContext.applyDirectives(constVar, false, declIsArray, declVarDirectives, statementSource);
variable.setComments(ensureUnusedComments(declVarComments));
return null;
}
@ -1171,25 +1132,17 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
BlockScope blockScope = getCurrentScope().addBlockScope();
scopeStack.push(blockScope);
loopStack.push(new Loop(blockScope, false));
StatementSource statementSource = StatementSource.forRanged(ctx);
// Create / find declared loop variable
if(ctx.declTypes() != null) {
this.visitDeclTypes(ctx.declTypes());
}
SymbolType varType = declVarType;
List<Directive> varDirectives = declVarDirectives;
String varName = ctx.NAME().getText();
Variable lValue;
if(varType != null) {
try {
lValue = getCurrentScope().add(Variable.createPhiMaster(varName, varType, getCurrentScope(), defaultMemoryArea, currentDataSegment));
} catch(CompileError e) {
throw new CompileError(e.getMessage(), statementSource);
}
// Add directives
directiveContext.applyDirectives(lValue, false, false, varDirectives, statementSource);
VariableBuilder varBuilder = new VariableBuilder(varName, blockScope, false, varType, null, declVarDirectives, currentDataSegment);
lValue = varBuilder.build();
} else {
lValue = getCurrentScope().getVariable(varName);
if(lValue == null) {