mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-02-17 10:30:43 +00:00
Moved variable directive handling to separate file. Default implementation identical to existing features.
This commit is contained in:
parent
8f274f18a6
commit
b82a4277e1
388
src/main/java/dk/camelot64/kickc/model/Directive.java
Normal file
388
src/main/java/dk/camelot64/kickc/model/Directive.java
Normal file
@ -0,0 +1,388 @@
|
|||||||
|
package dk.camelot64.kickc.model;
|
||||||
|
|
||||||
|
import dk.camelot64.kickc.model.statements.StatementSource;
|
||||||
|
import dk.camelot64.kickc.model.symbols.*;
|
||||||
|
import dk.camelot64.kickc.model.types.SymbolType;
|
||||||
|
import dk.camelot64.kickc.model.types.SymbolTypeArray;
|
||||||
|
import dk.camelot64.kickc.model.types.SymbolTypePointer;
|
||||||
|
import dk.camelot64.kickc.model.types.SymbolTypeStruct;
|
||||||
|
import dk.camelot64.kickc.model.values.ScopeRef;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/** A declaration directive. */
|
||||||
|
public interface Directive {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The parser directive context is used for determining which directives to apply to a variable.
|
||||||
|
* It keeps track of values for the #pragmas that control default directives for variables.
|
||||||
|
* Uses the following priority
|
||||||
|
* <ol>
|
||||||
|
* <li>If the directive is present in source - use that.
|
||||||
|
* <li>If the register keyword present in source - Look in #pragma variables_register_implies for setting (register in #pragma variables_xxx does not trigger this)
|
||||||
|
* <li>Look in #pragma variables_<i>scope</i>_<i>type</i> for setting (<i>scope</i> is global/local/parameter <i>type</i> is integer/pointer/array)
|
||||||
|
* <li>Look in #pragma variables_<i>type</i> for setting (<i>type</i> is integer/pointer/array)
|
||||||
|
* <li>Look in #pragma variables_<i>scope</i> for setting (<i>scope</i> is global/local/parameter)
|
||||||
|
* <li>Look in #pragma variables_default for setting
|
||||||
|
* <li>Use compiler default for the setting (__notconst __notregister _notalign __notvolatile __zp __initcode)
|
||||||
|
* </ol>
|
||||||
|
*/
|
||||||
|
class ParserContext {
|
||||||
|
|
||||||
|
/** The different scopes deciding directive defaults. */
|
||||||
|
public enum DirectiveScope {
|
||||||
|
GLOBAL, LOCAL, PARAMETER, STRUCT_MEMBER;
|
||||||
|
|
||||||
|
public static DirectiveScope getFor(SymbolVariable lValue, boolean isParameter) {
|
||||||
|
if(isParameter) {
|
||||||
|
return PARAMETER;
|
||||||
|
}
|
||||||
|
Scope scope = lValue.getScope();
|
||||||
|
return getFor(scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DirectiveScope getFor(Scope scope) {
|
||||||
|
if(ScopeRef.ROOT.equals(scope.getRef())) {
|
||||||
|
return GLOBAL;
|
||||||
|
} else if(scope instanceof Procedure) {
|
||||||
|
return LOCAL;
|
||||||
|
} else if(scope instanceof StructDefinition) {
|
||||||
|
return STRUCT_MEMBER;
|
||||||
|
} else if(scope instanceof BlockScope) {
|
||||||
|
return getFor(scope.getScope());
|
||||||
|
} else {
|
||||||
|
throw new InternalError("Scope type not handled " + scope);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The different types deciding directive defaults. */
|
||||||
|
public enum DirectiveType {
|
||||||
|
INTEGER, POINTER, ARRAY, STRUCT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a directive type from a variable type.
|
||||||
|
*
|
||||||
|
* @param type The variable type
|
||||||
|
* @return The directive type
|
||||||
|
*/
|
||||||
|
public static DirectiveType getFor(SymbolType type) {
|
||||||
|
if(SymbolType.isInteger(type)) {
|
||||||
|
return INTEGER;
|
||||||
|
} else if(SymbolType.BOOLEAN.equals(type)) {
|
||||||
|
return INTEGER;
|
||||||
|
} else if(SymbolType.STRING.equals(type)) {
|
||||||
|
return ARRAY;
|
||||||
|
} else if(type instanceof SymbolTypeArray) {
|
||||||
|
return ARRAY;
|
||||||
|
} else if(type instanceof SymbolTypePointer) {
|
||||||
|
return POINTER;
|
||||||
|
} else if(type instanceof SymbolTypeStruct) {
|
||||||
|
return STRUCT;
|
||||||
|
} else {
|
||||||
|
throw new InternalError("Variable type not handled " + type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Combination of a scope and type deciding directive defaults. */
|
||||||
|
public static class DirectiveScopeType {
|
||||||
|
DirectiveScope directiveScope;
|
||||||
|
DirectiveType directiveType;
|
||||||
|
|
||||||
|
public DirectiveScopeType(DirectiveScope directiveScope, DirectiveType directiveType) {
|
||||||
|
this.directiveScope = directiveScope;
|
||||||
|
this.directiveType = directiveType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if(this == o) return true;
|
||||||
|
if(o == null || getClass() != o.getClass()) return false;
|
||||||
|
DirectiveScopeType that = (DirectiveScopeType) o;
|
||||||
|
return directiveScope == that.directiveScope &&
|
||||||
|
directiveType == that.directiveType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(directiveScope, directiveType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Directives of a specific statement. Only non-null if this is a stored copy of the context for later resolution. */
|
||||||
|
List<Directive> statementDirectives;
|
||||||
|
|
||||||
|
/** Directives implied by the 'register' keyword. */
|
||||||
|
List<Directive> registerImpliesDirectives;
|
||||||
|
|
||||||
|
/** Default directives for a specific scope/type combination. */
|
||||||
|
Map<DirectiveScopeType, List<Directive>> scopeTypeDirectives;
|
||||||
|
|
||||||
|
/** Default directives for a specific scope. */
|
||||||
|
Map<DirectiveScope, List<Directive>> scopeDirectives;
|
||||||
|
|
||||||
|
/** Default directives for a specific type. */
|
||||||
|
Map<DirectiveType, List<Directive>> typeDirectives;
|
||||||
|
|
||||||
|
/** Default directives. */
|
||||||
|
List<Directive> defaultDirectives;
|
||||||
|
|
||||||
|
public ParserContext() {
|
||||||
|
this.statementDirectives = null;
|
||||||
|
// Setup default directives
|
||||||
|
this.defaultDirectives = new ArrayList<>();
|
||||||
|
//this.defaultDirectives.add(new MemoryArea(SymbolVariable.MemoryArea.ZEROPAGE_MEMORY, null));
|
||||||
|
//this.defaultDirectives.add(new Register(true, null));
|
||||||
|
this.registerImpliesDirectives = new ArrayList<>();
|
||||||
|
this.typeDirectives = new HashMap<>();
|
||||||
|
//this.typeDirectives.put(DirectiveType.ARRAY, Arrays.asList(new MemoryArea(SymbolVariable.MemoryArea.MAIN_MEMORY, null), new Register(false, null)));
|
||||||
|
this.scopeDirectives = new HashMap<>();
|
||||||
|
this.scopeTypeDirectives = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies directives to a variable. Applies directives using the correct priority.
|
||||||
|
*
|
||||||
|
* @param lValue The variable to apply directives to
|
||||||
|
* @param sourceDirectives The directives found in the source code
|
||||||
|
* @param source The source line.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public void applyDirectives(SymbolVariable lValue, boolean isParameter, List<Directive> sourceDirectives, StatementSource source) {
|
||||||
|
DirectiveType directiveType = DirectiveType.getFor(lValue.getType());
|
||||||
|
DirectiveScope directiveScope = DirectiveScope.getFor(lValue, isParameter);
|
||||||
|
|
||||||
|
Const constDirective = findDirective(Const.class, sourceDirectives, directiveScope, directiveType);
|
||||||
|
if(constDirective != null) {
|
||||||
|
lValue.setDeclaredConstant(true);
|
||||||
|
lValue.setStorageStrategy(SymbolVariable.StorageStrategy.CONSTANT);
|
||||||
|
if(!(lValue.getType() instanceof SymbolTypePointer))
|
||||||
|
lValue.setMemoryArea(SymbolVariable.MemoryArea.MAIN_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
Volatile volatileDirective = findDirective(Volatile.class, sourceDirectives, directiveScope, directiveType);
|
||||||
|
if(volatileDirective != null) {
|
||||||
|
lValue.setDeclaredVolatile(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Export exportDirective = findDirective(Export.class, sourceDirectives, directiveScope, directiveType);
|
||||||
|
if(exportDirective != null) {
|
||||||
|
lValue.setDeclaredExport(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Align alignDirective = findDirective(Align.class, sourceDirectives, directiveScope, directiveType);
|
||||||
|
if(alignDirective != null) {
|
||||||
|
SymbolType type = lValue.getType();
|
||||||
|
if(type instanceof SymbolTypeArray || type.equals(SymbolType.STRING)) {
|
||||||
|
lValue.setDeclaredAlignment(alignDirective.alignment);
|
||||||
|
} else {
|
||||||
|
throw new CompileError("Error! Cannot align variable that is not a string or an array " + lValue.toString(), source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryArea memoryAreaDirective = findDirective(MemoryArea.class, sourceDirectives, directiveScope, directiveType);
|
||||||
|
if(memoryAreaDirective != null) {
|
||||||
|
lValue.setMemoryArea(memoryAreaDirective.memoryArea);
|
||||||
|
if(memoryAreaDirective.address != null) {
|
||||||
|
if(SymbolVariable.MemoryArea.ZEROPAGE_MEMORY.equals(memoryAreaDirective.memoryArea)) {
|
||||||
|
// Allocate to specific address
|
||||||
|
if(memoryAreaDirective.address > 255) {
|
||||||
|
throw new CompileError("Error! Address not on zeropage " + memoryAreaDirective.address, source);
|
||||||
|
}
|
||||||
|
Registers.Register register = new Registers.RegisterZpMem(memoryAreaDirective.address.intValue(), -1, true);
|
||||||
|
lValue.setDeclaredRegister(register);
|
||||||
|
} else {
|
||||||
|
lValue.setDeclaredMemoryAddress(memoryAreaDirective.address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Register registerDirective = findDirective(Register.class, sourceDirectives, directiveScope, directiveType);
|
||||||
|
if(registerDirective != null) {
|
||||||
|
if(registerDirective.isRegister) {
|
||||||
|
lValue.setDeclaredAsRegister(true);
|
||||||
|
lValue.setStorageStrategy(SymbolVariable.StorageStrategy.PHI_MASTER);
|
||||||
|
if(registerDirective.name != null) {
|
||||||
|
// Ignore register directive without parameter (all variables are placed on ZP and attempted register uplift anyways)
|
||||||
|
Registers.Register register = Registers.getRegister(registerDirective.name);
|
||||||
|
if(register == null) {
|
||||||
|
throw new CompileError("Error! Unknown register " + registerDirective.name, source);
|
||||||
|
}
|
||||||
|
lValue.setDeclaredRegister(register);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lValue.setDeclaredNotRegister(true);
|
||||||
|
lValue.setStorageStrategy(SymbolVariable.StorageStrategy.LOAD_STORE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private <DirectiveClass extends Directive> DirectiveClass findDirective(Class<DirectiveClass> directiveClass, List<Directive> sourceDirectives, DirectiveScope directiveScope, DirectiveType directiveType) {
|
||||||
|
// Look in source directives
|
||||||
|
{
|
||||||
|
DirectiveClass directive = findDirective(directiveClass, sourceDirectives);
|
||||||
|
if(directive != null) return directive;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Look in register implies - if register directive is present in source
|
||||||
|
if(isRegister(sourceDirectives)) {
|
||||||
|
// Look in source directives
|
||||||
|
DirectiveClass directive = findDirective(directiveClass, registerImpliesDirectives);
|
||||||
|
if(directive != null) return directive;
|
||||||
|
}
|
||||||
|
// Look in #pragma setting for scope/type combination
|
||||||
|
{
|
||||||
|
List<Directive> directives = scopeTypeDirectives.get(new DirectiveScopeType(directiveScope, directiveType));
|
||||||
|
DirectiveClass directive = findDirective(directiveClass, directives);
|
||||||
|
if(directive != null) return directive;
|
||||||
|
}
|
||||||
|
// Look in #pragma setting for type
|
||||||
|
{
|
||||||
|
List<Directive> directives = typeDirectives.get(directiveType);
|
||||||
|
DirectiveClass directive = findDirective(directiveClass, directives);
|
||||||
|
if(directive != null) return directive;
|
||||||
|
}
|
||||||
|
// Look in #pragma setting for scope
|
||||||
|
{
|
||||||
|
List<Directive> directives = scopeDirectives.get(directiveScope);
|
||||||
|
DirectiveClass directive = findDirective(directiveClass, directives);
|
||||||
|
if(directive != null) return directive;
|
||||||
|
}
|
||||||
|
// Look in #pragma setting for default
|
||||||
|
{
|
||||||
|
DirectiveClass directive = findDirective(directiveClass, defaultDirectives);
|
||||||
|
if(directive != null) return directive;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// Not found!
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the register directive is present in the source directives.
|
||||||
|
*
|
||||||
|
* @param sourceDirectives The source directives
|
||||||
|
* @return true if the register keyword is present
|
||||||
|
*/
|
||||||
|
private boolean isRegister(List<Directive> sourceDirectives) {
|
||||||
|
Register registerDirective = findDirective(Register.class, sourceDirectives);
|
||||||
|
return registerDirective != null && registerDirective.isRegister;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Variable declared constant. */
|
||||||
|
class Const implements Directive {
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Function with specific declared calling convention. */
|
||||||
|
class CallingConvention implements Directive {
|
||||||
|
|
||||||
|
public Procedure.CallingConvension callingConvension;
|
||||||
|
|
||||||
|
public CallingConvention(Procedure.CallingConvension callingConvension) {
|
||||||
|
this.callingConvension = callingConvension;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Function declared inline. */
|
||||||
|
class Inline implements Directive {
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Variable declared volatile. */
|
||||||
|
class Volatile implements Directive {
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Variable declared as export. */
|
||||||
|
class Export implements Directive {
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Function declared interrupt. */
|
||||||
|
class Interrupt implements Directive {
|
||||||
|
public Procedure.InterruptType interruptType;
|
||||||
|
|
||||||
|
public Interrupt(Procedure.InterruptType interruptType) {
|
||||||
|
this.interruptType = interruptType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Variable memory alignment. */
|
||||||
|
class Align implements Directive {
|
||||||
|
|
||||||
|
int alignment;
|
||||||
|
|
||||||
|
public Align(int alignment) {
|
||||||
|
this.alignment = alignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Variable register or __notregister directive . */
|
||||||
|
class Register implements Directive {
|
||||||
|
|
||||||
|
/** true if the directive is a register directive. false if it is a notregister directive. */
|
||||||
|
boolean isRegister;
|
||||||
|
|
||||||
|
/** Name of register to use for the variable (if named) */
|
||||||
|
public String name;
|
||||||
|
|
||||||
|
public Register(boolean isRegister, String name) {
|
||||||
|
this.isRegister = isRegister;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Variable memory area declaration. */
|
||||||
|
class MemoryArea implements Directive {
|
||||||
|
|
||||||
|
/** The memory area. */
|
||||||
|
SymbolVariable.MemoryArea memoryArea;
|
||||||
|
|
||||||
|
/** Optional hard-coded address to use for storing the variable. */
|
||||||
|
public Long address;
|
||||||
|
|
||||||
|
public MemoryArea(SymbolVariable.MemoryArea memoryArea, Long address) {
|
||||||
|
this.memoryArea = memoryArea;
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Reservation of zero-page addresses */
|
||||||
|
class ReserveZp implements Directive {
|
||||||
|
public List<Integer> reservedZp;
|
||||||
|
|
||||||
|
public ReserveZp(List<Integer> reservedZp) {
|
||||||
|
this.reservedZp = reservedZp;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -45,6 +45,8 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
private Stack<Scope> scopeStack;
|
private Stack<Scope> scopeStack;
|
||||||
/** The memory area used by default for variables. */
|
/** The memory area used by default for variables. */
|
||||||
private SymbolVariable.MemoryArea defaultMemoryArea;
|
private SymbolVariable.MemoryArea defaultMemoryArea;
|
||||||
|
/** Context used for adding directives to variables. */
|
||||||
|
private Directive.ParserContext directiveContext;
|
||||||
|
|
||||||
public Pass0GenerateStatementSequence(CParser cParser, KickCParser.FileContext fileCtx, Program program) {
|
public Pass0GenerateStatementSequence(CParser cParser, KickCParser.FileContext fileCtx, Program program) {
|
||||||
this.cParser = cParser;
|
this.cParser = cParser;
|
||||||
@ -53,6 +55,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
this.sequence = program.getStatementSequence();
|
this.sequence = program.getStatementSequence();
|
||||||
this.scopeStack = new Stack<>();
|
this.scopeStack = new Stack<>();
|
||||||
this.defaultMemoryArea = SymbolVariable.MemoryArea.ZEROPAGE_MEMORY;
|
this.defaultMemoryArea = SymbolVariable.MemoryArea.ZEROPAGE_MEMORY;
|
||||||
|
this.directiveContext = new Directive.ParserContext();
|
||||||
scopeStack.push(program.getScope());
|
scopeStack.push(program.getScope());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,7 +268,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
List<Directive> directives = declVarDirectives;
|
List<Directive> directives = declVarDirectives;
|
||||||
Variable param = new Variable(ctx.NAME().getText(), getCurrentScope(), type, currentDataSegment, SymbolVariable.StorageStrategy.PHI_MASTER, defaultMemoryArea);
|
Variable param = new Variable(ctx.NAME().getText(), getCurrentScope(), type, currentDataSegment, SymbolVariable.StorageStrategy.PHI_MASTER, defaultMemoryArea);
|
||||||
// Add directives
|
// Add directives
|
||||||
addDirectives(param, type, directives, new StatementSource(ctx));
|
addDirectives(param, true, directives, new StatementSource(ctx));
|
||||||
exitDeclTypes();
|
exitDeclTypes();
|
||||||
return param;
|
return param;
|
||||||
}
|
}
|
||||||
@ -620,7 +623,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
throw new CompileError(e.getMessage(), new StatementSource(ctx));
|
throw new CompileError(e.getMessage(), new StatementSource(ctx));
|
||||||
}
|
}
|
||||||
// Add directives
|
// Add directives
|
||||||
addDirectives(lValue, type, directives, new StatementSource(ctx));
|
addDirectives(lValue, false, directives, new StatementSource(ctx));
|
||||||
// Array / String variables are implicitly constant
|
// Array / String variables are implicitly constant
|
||||||
if(type instanceof SymbolTypeArray || type.equals(SymbolType.STRING)) {
|
if(type instanceof SymbolTypeArray || type.equals(SymbolType.STRING)) {
|
||||||
lValue.setDeclaredConstant(true);
|
lValue.setDeclaredConstant(true);
|
||||||
@ -676,62 +679,11 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
* Add declared directives to an lValue (typically a variable).
|
* Add declared directives to an lValue (typically a variable).
|
||||||
*
|
*
|
||||||
* @param lValue The lValue
|
* @param lValue The lValue
|
||||||
* @param type The type of the lValue
|
* @param isParameter True if the lValue is a parameter
|
||||||
* @param directives The directives to add
|
* @param directives The directives to add
|
||||||
*/
|
*/
|
||||||
private void addDirectives(SymbolVariable lValue, SymbolType type, List<Directive> directives, StatementSource source) {
|
private void addDirectives(SymbolVariable lValue, boolean isParameter, List<Directive> directives, StatementSource source) {
|
||||||
for(Directive directive : directives) {
|
directiveContext.applyDirectives(lValue, isParameter, directives, source);
|
||||||
if(directive instanceof DirectiveConst) {
|
|
||||||
lValue.setDeclaredConstant(true);
|
|
||||||
lValue.setStorageStrategy(SymbolVariable.StorageStrategy.CONSTANT);
|
|
||||||
if(!(lValue.getType() instanceof SymbolTypePointer))
|
|
||||||
lValue.setMemoryArea(SymbolVariable.MemoryArea.MAIN_MEMORY);
|
|
||||||
} else if(directive instanceof DirectiveVolatile) {
|
|
||||||
lValue.setDeclaredVolatile(true);
|
|
||||||
} else if(directive instanceof DirectiveExport) {
|
|
||||||
lValue.setDeclaredExport(true);
|
|
||||||
} else if(directive instanceof DirectiveAlign) {
|
|
||||||
if(type instanceof SymbolTypeArray || type.equals(SymbolType.STRING)) {
|
|
||||||
lValue.setDeclaredAlignment(((DirectiveAlign) directive).alignment);
|
|
||||||
} else {
|
|
||||||
throw new CompileError("Error! Cannot align variable that is not a string or an array " + lValue.toString(program), source);
|
|
||||||
}
|
|
||||||
} else if(directive instanceof DirectiveMemoryArea) {
|
|
||||||
DirectiveMemoryArea directiveMemoryArea = (DirectiveMemoryArea) directive;
|
|
||||||
lValue.setMemoryArea(directiveMemoryArea.memoryArea);
|
|
||||||
if(directiveMemoryArea.address!=null) {
|
|
||||||
if(SymbolVariable.MemoryArea.ZEROPAGE_MEMORY.equals(directiveMemoryArea.memoryArea)) {
|
|
||||||
// Allocate to specific address
|
|
||||||
if(directiveMemoryArea.address > 255) {
|
|
||||||
throw new CompileError("Error! Address not on zeropage " + directiveMemoryArea.address, source);
|
|
||||||
}
|
|
||||||
Registers.Register register = new Registers.RegisterZpMem(directiveMemoryArea.address.intValue(), -1, true);
|
|
||||||
lValue.setDeclaredRegister(register);
|
|
||||||
} else {
|
|
||||||
lValue.setDeclaredMemoryAddress(directiveMemoryArea.address);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if(directive instanceof DirectiveRegister) {
|
|
||||||
DirectiveRegister directiveRegister = (DirectiveRegister) directive;
|
|
||||||
if(directiveRegister.isRegister) {
|
|
||||||
lValue.setDeclaredAsRegister(true);
|
|
||||||
lValue.setStorageStrategy(SymbolVariable.StorageStrategy.PHI_MASTER);
|
|
||||||
if(directiveRegister.name != null) {
|
|
||||||
// Ignore register directive without parameter (all variables are placed on ZP and attempted register uplift anyways)
|
|
||||||
Registers.Register register = Registers.getRegister(directiveRegister.name);
|
|
||||||
if(register == null) {
|
|
||||||
throw new CompileError("Error! Unknown register " + directiveRegister.name, source);
|
|
||||||
}
|
|
||||||
lValue.setDeclaredRegister(register);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lValue.setDeclaredNotRegister(true);
|
|
||||||
lValue.setStorageStrategy(SymbolVariable.StorageStrategy.LOAD_STORE);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new CompileError("Unsupported variable directive " + directive, source);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -756,14 +708,14 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
*/
|
*/
|
||||||
private void addDirectives(Procedure procedure, List<Directive> directives, StatementSource source) {
|
private void addDirectives(Procedure procedure, List<Directive> directives, StatementSource source) {
|
||||||
for(Directive directive : directives) {
|
for(Directive directive : directives) {
|
||||||
if(directive instanceof DirectiveInline) {
|
if(directive instanceof Directive.Inline) {
|
||||||
procedure.setDeclaredInline(true);
|
procedure.setDeclaredInline(true);
|
||||||
} else if(directive instanceof DirectiveCallingConvention) {
|
} else if(directive instanceof Directive.CallingConvention) {
|
||||||
procedure.setCallingConvension(((DirectiveCallingConvention) directive).callingConvension);
|
procedure.setCallingConvension(((Directive.CallingConvention) directive).callingConvension);
|
||||||
} else if(directive instanceof DirectiveInterrupt) {
|
} else if(directive instanceof Directive.Interrupt) {
|
||||||
procedure.setInterruptType(((DirectiveInterrupt) directive).interruptType);
|
procedure.setInterruptType(((Directive.Interrupt) directive).interruptType);
|
||||||
} else if(directive instanceof DirectiveReserveZp) {
|
} else if(directive instanceof Directive.ReserveZp) {
|
||||||
procedure.setReservedZps(((DirectiveReserveZp) directive).reservedZp);
|
procedure.setReservedZps(((Directive.ReserveZp) directive).reservedZp);
|
||||||
} else {
|
} else {
|
||||||
throw new CompileError("Unsupported function directive " + directive, source);
|
throw new CompileError("Unsupported function directive " + directive, source);
|
||||||
}
|
}
|
||||||
@ -780,7 +732,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
List<Directive> directives = getDirectives(directivesCtx);
|
List<Directive> directives = getDirectives(directivesCtx);
|
||||||
for(Directive directive : directives) {
|
for(Directive directive : directives) {
|
||||||
StatementSource source = new StatementSource(directivesCtx.get(0));
|
StatementSource source = new StatementSource(directivesCtx.get(0));
|
||||||
if(directive instanceof DirectiveInline) {
|
if(directive instanceof Directive.Inline) {
|
||||||
conditional.setDeclaredUnroll(true);
|
conditional.setDeclaredUnroll(true);
|
||||||
} else {
|
} else {
|
||||||
throw new CompileError("Unsupported loop directive " + directive, source);
|
throw new CompileError("Unsupported loop directive " + directive, source);
|
||||||
@ -790,12 +742,12 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Directive visitDirectiveConst(KickCParser.DirectiveConstContext ctx) {
|
public Directive visitDirectiveConst(KickCParser.DirectiveConstContext ctx) {
|
||||||
return new DirectiveConst();
|
return new Directive.Const();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitDirectiveInline(KickCParser.DirectiveInlineContext ctx) {
|
public Object visitDirectiveInline(KickCParser.DirectiveInlineContext ctx) {
|
||||||
return new DirectiveInline();
|
return new Directive.Inline();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -808,19 +760,19 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
interruptType = Procedure.InterruptType.DEFAULT.name();
|
interruptType = Procedure.InterruptType.DEFAULT.name();
|
||||||
}
|
}
|
||||||
Procedure.InterruptType type = Procedure.InterruptType.valueOf(interruptType);
|
Procedure.InterruptType type = Procedure.InterruptType.valueOf(interruptType);
|
||||||
return new DirectiveInterrupt(type);
|
return new Directive.Interrupt(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Directive visitDirectiveCallingConvention(KickCParser.DirectiveCallingConventionContext ctx) {
|
public Directive visitDirectiveCallingConvention(KickCParser.DirectiveCallingConventionContext ctx) {
|
||||||
Procedure.CallingConvension callingConvension = Procedure.CallingConvension.getCallingConvension(ctx.getText());
|
Procedure.CallingConvension callingConvension = Procedure.CallingConvension.getCallingConvension(ctx.getText());
|
||||||
return new DirectiveCallingConvention(callingConvension);
|
return new Directive.CallingConvention(callingConvension);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Directive visitDirectiveAlign(KickCParser.DirectiveAlignContext ctx) {
|
public Directive visitDirectiveAlign(KickCParser.DirectiveAlignContext ctx) {
|
||||||
Number alignment = NumberParser.parseLiteral(ctx.NUMBER().getText());
|
Number alignment = NumberParser.parseLiteral(ctx.NUMBER().getText());
|
||||||
return new DirectiveAlign(alignment.intValue());
|
return new Directive.Align(alignment.intValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -829,22 +781,22 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
if(ctx.NAME() != null) {
|
if(ctx.NAME() != null) {
|
||||||
name = ctx.NAME().getText();
|
name = ctx.NAME().getText();
|
||||||
}
|
}
|
||||||
return new DirectiveRegister(true, name);
|
return new Directive.Register(true, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitDirectiveNotRegister(KickCParser.DirectiveNotRegisterContext ctx) {
|
public Object visitDirectiveNotRegister(KickCParser.DirectiveNotRegisterContext ctx) {
|
||||||
return new DirectiveRegister(false, null);
|
return new Directive.Register(false, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitDirectiveMemoryAreaZp(KickCParser.DirectiveMemoryAreaZpContext ctx) {
|
public Object visitDirectiveMemoryAreaZp(KickCParser.DirectiveMemoryAreaZpContext ctx) {
|
||||||
return new DirectiveMemoryArea(SymbolVariable.MemoryArea.ZEROPAGE_MEMORY, null);
|
return new Directive.MemoryArea(SymbolVariable.MemoryArea.ZEROPAGE_MEMORY, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitDirectiveMemoryAreaMain(KickCParser.DirectiveMemoryAreaMainContext ctx) {
|
public Object visitDirectiveMemoryAreaMain(KickCParser.DirectiveMemoryAreaMainContext ctx) {
|
||||||
return new DirectiveMemoryArea(SymbolVariable.MemoryArea.MAIN_MEMORY, null);
|
return new Directive.MemoryArea(SymbolVariable.MemoryArea.MAIN_MEMORY, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -853,7 +805,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
ConstantInteger memoryAddress = NumberParser.parseIntegerLiteral(ctx.NUMBER().getText());
|
ConstantInteger memoryAddress = NumberParser.parseIntegerLiteral(ctx.NUMBER().getText());
|
||||||
Long address = memoryAddress.getInteger();
|
Long address = memoryAddress.getInteger();
|
||||||
SymbolVariable.MemoryArea memoryArea = (address<0x100)? SymbolVariable.MemoryArea.ZEROPAGE_MEMORY : SymbolVariable.MemoryArea.MAIN_MEMORY;
|
SymbolVariable.MemoryArea memoryArea = (address<0x100)? SymbolVariable.MemoryArea.ZEROPAGE_MEMORY : SymbolVariable.MemoryArea.MAIN_MEMORY;
|
||||||
return new DirectiveMemoryArea(memoryArea, address);
|
return new Directive.MemoryArea(memoryArea, address);
|
||||||
} catch(NumberFormatException e) {
|
} catch(NumberFormatException e) {
|
||||||
throw new CompileError(e.getMessage(), new StatementSource(ctx));
|
throw new CompileError(e.getMessage(), new StatementSource(ctx));
|
||||||
}
|
}
|
||||||
@ -861,12 +813,12 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Directive visitDirectiveVolatile(KickCParser.DirectiveVolatileContext ctx) {
|
public Directive visitDirectiveVolatile(KickCParser.DirectiveVolatileContext ctx) {
|
||||||
return new DirectiveVolatile();
|
return new Directive.Volatile();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitDirectiveExport(KickCParser.DirectiveExportContext ctx) {
|
public Object visitDirectiveExport(KickCParser.DirectiveExportContext ctx) {
|
||||||
return new DirectiveExport();
|
return new Directive.Export();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -876,7 +828,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
int reservedZp = NumberParser.parseLiteral(reservedNum.getText()).intValue();
|
int reservedZp = NumberParser.parseLiteral(reservedNum.getText()).intValue();
|
||||||
reservedZps.add(reservedZp);
|
reservedZps.add(reservedZp);
|
||||||
}
|
}
|
||||||
return new DirectiveReserveZp(reservedZps);
|
return new Directive.ReserveZp(reservedZps);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1220,7 +1172,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
throw new CompileError(e.getMessage(), statementSource);
|
throw new CompileError(e.getMessage(), statementSource);
|
||||||
}
|
}
|
||||||
// Add directives
|
// Add directives
|
||||||
addDirectives(lValue, varType, varDirectives, statementSource);
|
addDirectives(lValue, false, varDirectives, statementSource);
|
||||||
} else {
|
} else {
|
||||||
lValue = getCurrentScope().getVariable(varName);
|
lValue = getCurrentScope().getVariable(varName);
|
||||||
if(lValue == null) {
|
if(lValue == null) {
|
||||||
@ -2199,98 +2151,6 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
return commentBlocks.get(commentBlocks.size() - 1);
|
return commentBlocks.get(commentBlocks.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A declaration directive. */
|
|
||||||
private interface Directive {
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Variable declared constant. */
|
|
||||||
private static class DirectiveConst implements Directive {
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Function with specific declared calling convention. */
|
|
||||||
private static class DirectiveCallingConvention implements Directive {
|
|
||||||
private Procedure.CallingConvension callingConvension;
|
|
||||||
|
|
||||||
DirectiveCallingConvention(Procedure.CallingConvension callingConvension) {
|
|
||||||
this.callingConvension = callingConvension;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Function declared inline. */
|
|
||||||
private static class DirectiveInline implements Directive {
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Variable declared volatile. */
|
|
||||||
private static class DirectiveVolatile implements Directive {
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Variable declared as export. */
|
|
||||||
private static class DirectiveExport implements Directive {
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Function declared interrupt. */
|
|
||||||
private static class DirectiveInterrupt implements Directive {
|
|
||||||
Procedure.InterruptType interruptType;
|
|
||||||
|
|
||||||
DirectiveInterrupt(Procedure.InterruptType interruptType) {
|
|
||||||
this.interruptType = interruptType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Variable memory alignment. */
|
|
||||||
private static class DirectiveAlign implements Directive {
|
|
||||||
|
|
||||||
private int alignment;
|
|
||||||
|
|
||||||
private DirectiveAlign(int alignment) {
|
|
||||||
this.alignment = alignment;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Variable register or __notregister directive . */
|
|
||||||
private static class DirectiveRegister implements Directive {
|
|
||||||
|
|
||||||
/** true if the directive is a register directive. false if it is a notregister directive. */
|
|
||||||
private boolean isRegister;
|
|
||||||
|
|
||||||
/** Name of register to use for the variable (if named) */
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
DirectiveRegister(boolean isRegister, String name) {
|
|
||||||
this.isRegister = isRegister;
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Variable memory area declaration. */
|
|
||||||
private static class DirectiveMemoryArea implements Directive {
|
|
||||||
|
|
||||||
/** The memory area. */
|
|
||||||
SymbolVariable.MemoryArea memoryArea;
|
|
||||||
|
|
||||||
/** Optional hard-coded address to use for storing the variable. */
|
|
||||||
private Long address;
|
|
||||||
|
|
||||||
DirectiveMemoryArea(SymbolVariable.MemoryArea memoryArea, Long address) {
|
|
||||||
this.memoryArea = memoryArea;
|
|
||||||
this.address = address;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Reservation of zero-page addresses */
|
|
||||||
private static class DirectiveReserveZp implements Directive {
|
|
||||||
List<Integer> reservedZp;
|
|
||||||
|
|
||||||
DirectiveReserveZp(List<Integer> reservedZp) {
|
|
||||||
this.reservedZp = reservedZp;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static class PrePostModifierHandler extends KickCParserBaseVisitor<Void> {
|
private static class PrePostModifierHandler extends KickCParserBaseVisitor<Void> {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user