mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-04-08 14:37:40 +00:00
Refactoring handling of variable directives.
This commit is contained in:
parent
c7d5be3962
commit
d9582d6b0f
@ -79,12 +79,12 @@ public class AsmFragmentTemplate {
|
||||
ProgramScope scope = new ProgramScope();
|
||||
LinkedHashMap<String, Value> bindings = new LinkedHashMap<>();
|
||||
{
|
||||
Variable v1 = new Variable( "z1", scope, SymbolType.BYTE, Variable.StorageStrategy.PHI_VERSION, Variable.MemoryArea.ZEROPAGE_MEMORY, null);
|
||||
Variable v2 = new Variable( "z2", scope, SymbolType.BYTE, Variable.StorageStrategy.PHI_VERSION, Variable.MemoryArea.ZEROPAGE_MEMORY, null);
|
||||
Variable v3 = new Variable( "z3", scope, SymbolType.BYTE, Variable.StorageStrategy.PHI_VERSION, Variable.MemoryArea.ZEROPAGE_MEMORY, null);
|
||||
Variable v4 = new Variable( "z4", scope, SymbolType.BYTE, Variable.StorageStrategy.PHI_VERSION, Variable.MemoryArea.ZEROPAGE_MEMORY, null);
|
||||
Variable v5 = new Variable( "z5", scope, SymbolType.BYTE, Variable.StorageStrategy.PHI_VERSION, Variable.MemoryArea.ZEROPAGE_MEMORY, null);
|
||||
Variable v6 = new Variable( "z6", scope, SymbolType.BYTE, Variable.StorageStrategy.PHI_VERSION, Variable.MemoryArea.ZEROPAGE_MEMORY, null);
|
||||
Variable v1 = new Variable( "z1", scope, SymbolType.BYTE, Variable.Kind.PHI_VERSION, Variable.MemoryArea.ZEROPAGE_MEMORY, null);
|
||||
Variable v2 = new Variable( "z2", scope, SymbolType.BYTE, Variable.Kind.PHI_VERSION, Variable.MemoryArea.ZEROPAGE_MEMORY, null);
|
||||
Variable v3 = new Variable( "z3", scope, SymbolType.BYTE, Variable.Kind.PHI_VERSION, Variable.MemoryArea.ZEROPAGE_MEMORY, null);
|
||||
Variable v4 = new Variable( "z4", scope, SymbolType.BYTE, Variable.Kind.PHI_VERSION, Variable.MemoryArea.ZEROPAGE_MEMORY, null);
|
||||
Variable v5 = new Variable( "z5", scope, SymbolType.BYTE, Variable.Kind.PHI_VERSION, Variable.MemoryArea.ZEROPAGE_MEMORY, null);
|
||||
Variable v6 = new Variable( "z6", scope, SymbolType.BYTE, Variable.Kind.PHI_VERSION, Variable.MemoryArea.ZEROPAGE_MEMORY, null);
|
||||
v1.setAllocation(new Registers.RegisterZpMem(2, 1));
|
||||
v2.setAllocation(new Registers.RegisterZpMem(4, 1));
|
||||
v3.setAllocation(new Registers.RegisterZpMem(6, 1));
|
||||
@ -99,12 +99,12 @@ public class AsmFragmentTemplate {
|
||||
if(signature.contains("z6")) bindings.put("z6", v6);
|
||||
}
|
||||
{
|
||||
Variable v1 = new Variable( "m1", scope, SymbolType.BYTE, Variable.StorageStrategy.LOAD_STORE, Variable.MemoryArea.MAIN_MEMORY, null);
|
||||
Variable v2 = new Variable( "m2", scope, SymbolType.BYTE, Variable.StorageStrategy.LOAD_STORE, Variable.MemoryArea.MAIN_MEMORY, null);
|
||||
Variable v3 = new Variable( "m3", scope, SymbolType.BYTE, Variable.StorageStrategy.LOAD_STORE, Variable.MemoryArea.MAIN_MEMORY, null);
|
||||
Variable v4 = new Variable( "m4", scope, SymbolType.BYTE, Variable.StorageStrategy.LOAD_STORE, Variable.MemoryArea.MAIN_MEMORY, null);
|
||||
Variable v5 = new Variable( "m5", scope, SymbolType.BYTE, Variable.StorageStrategy.LOAD_STORE, Variable.MemoryArea.MAIN_MEMORY, null);
|
||||
Variable v6 = new Variable( "m6", scope, SymbolType.BYTE, Variable.StorageStrategy.LOAD_STORE, Variable.MemoryArea.MAIN_MEMORY, null);
|
||||
Variable v1 = new Variable( "m1", scope, SymbolType.BYTE, Variable.Kind.LOAD_STORE, Variable.MemoryArea.MAIN_MEMORY, null);
|
||||
Variable v2 = new Variable( "m2", scope, SymbolType.BYTE, Variable.Kind.LOAD_STORE, Variable.MemoryArea.MAIN_MEMORY, null);
|
||||
Variable v3 = new Variable( "m3", scope, SymbolType.BYTE, Variable.Kind.LOAD_STORE, Variable.MemoryArea.MAIN_MEMORY, null);
|
||||
Variable v4 = new Variable( "m4", scope, SymbolType.BYTE, Variable.Kind.LOAD_STORE, Variable.MemoryArea.MAIN_MEMORY, null);
|
||||
Variable v5 = new Variable( "m5", scope, SymbolType.BYTE, Variable.Kind.LOAD_STORE, Variable.MemoryArea.MAIN_MEMORY, null);
|
||||
Variable v6 = new Variable( "m6", scope, SymbolType.BYTE, Variable.Kind.LOAD_STORE, Variable.MemoryArea.MAIN_MEMORY, null);
|
||||
v1.setAllocation(new Registers.RegisterMainMem(v1.getVariableRef(), 1, null));
|
||||
v2.setAllocation(new Registers.RegisterMainMem(v2.getVariableRef(), 1, null));
|
||||
v3.setAllocation(new Registers.RegisterMainMem(v3.getVariableRef(), 1, null));
|
||||
|
@ -1,24 +1,54 @@
|
||||
package dk.camelot64.kickc.model;
|
||||
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
import dk.camelot64.kickc.model.symbols.Variable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** A declaration directive. */
|
||||
public interface Directive {
|
||||
|
||||
|
||||
/** Variable declared const, __notconst or __maybeconst. */
|
||||
/** Variable declared const */
|
||||
class Const implements Directive {
|
||||
}
|
||||
|
||||
/** The const declaration. */
|
||||
Variable.ConstantDeclaration constantDeclaration;
|
||||
/** Variable declared volatile */
|
||||
class Volatile implements Directive {
|
||||
}
|
||||
|
||||
public Const(Variable.ConstantDeclaration constantDeclaration) {
|
||||
this.constantDeclaration = constantDeclaration;
|
||||
}
|
||||
/** Variable declared register. */
|
||||
class Register implements Directive {
|
||||
}
|
||||
|
||||
/** Function declared inline. */
|
||||
class Inline implements Directive {
|
||||
}
|
||||
|
||||
/** Variable declared as extern. */
|
||||
class Extern implements Directive {
|
||||
}
|
||||
|
||||
/** Variable declared as export. */
|
||||
class Export implements Directive {
|
||||
}
|
||||
|
||||
/** Variable declared __notconst */
|
||||
class NotConst implements Directive {
|
||||
}
|
||||
|
||||
/** Variable __ssa */
|
||||
class FormSsa implements Directive {
|
||||
}
|
||||
|
||||
/** Variable __ma */
|
||||
class FormMa implements Directive {
|
||||
}
|
||||
|
||||
/** Variable __zp */
|
||||
class MemZp implements Directive {
|
||||
}
|
||||
|
||||
/** Variable __mem */
|
||||
class MemMain implements Directive {
|
||||
}
|
||||
|
||||
/** Function with specific declared calling convention. */
|
||||
@ -32,39 +62,6 @@ public interface Directive {
|
||||
|
||||
}
|
||||
|
||||
/** Function declared inline. */
|
||||
class Inline implements Directive {
|
||||
}
|
||||
|
||||
/** Variable declared volatile or __notvolatile. */
|
||||
class Volatile implements Directive {
|
||||
|
||||
/** True if declared volatile, false if declared __notvolatile */
|
||||
boolean isVolatile;
|
||||
|
||||
public Volatile(boolean isVolatile) {
|
||||
this.isVolatile = isVolatile;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Variable declared as export. */
|
||||
class Export implements Directive {
|
||||
}
|
||||
|
||||
/** Variable declared SSA or not SSA . */
|
||||
class FormSsa implements Directive {
|
||||
|
||||
/** True if declared SSA false if declared NOT SSA */
|
||||
boolean ssa;
|
||||
|
||||
public FormSsa(boolean ssa) {
|
||||
this.ssa = ssa;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** Function declared interrupt. */
|
||||
class Interrupt implements Directive {
|
||||
public Procedure.InterruptType interruptType;
|
||||
@ -85,33 +82,25 @@ public interface Directive {
|
||||
|
||||
}
|
||||
|
||||
/** 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;
|
||||
/** Variable hardcoded register directive. */
|
||||
class NamedRegister implements Directive {
|
||||
|
||||
/** Name of register to use for the variable (if named) */
|
||||
public String name;
|
||||
|
||||
public Register(boolean isRegister, String name) {
|
||||
this.isRegister = isRegister;
|
||||
public NamedRegister(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Variable memory area declaration. */
|
||||
class MemoryArea implements Directive {
|
||||
|
||||
/** The memory area. */
|
||||
Variable.MemoryArea memoryArea;
|
||||
/** Variable hardcoded __address() directive */
|
||||
class Address implements Directive {
|
||||
|
||||
/** Optional hard-coded address to use for storing the variable. */
|
||||
public Long address;
|
||||
|
||||
public MemoryArea(Variable.MemoryArea memoryArea, Long address) {
|
||||
this.memoryArea = memoryArea;
|
||||
public Address(Long address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
@ -124,7 +113,6 @@ public interface Directive {
|
||||
public ReserveZp(List<Integer> reservedZp) {
|
||||
this.reservedZp = reservedZp;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -9,21 +9,10 @@ import dk.camelot64.kickc.model.types.SymbolTypeStruct;
|
||||
import dk.camelot64.kickc.model.values.ScopeRef;
|
||||
import dk.camelot64.kickc.model.values.VariableRef;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 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>
|
||||
*/
|
||||
public class DirectiveParserContext {
|
||||
|
||||
@ -31,15 +20,10 @@ public class DirectiveParserContext {
|
||||
public enum DirectiveScope {
|
||||
GLOBAL, LOCAL, PARAMETER, MEMBER;
|
||||
|
||||
public static DirectiveScope getFor(Variable lValue, boolean isParameter) {
|
||||
private static DirectiveScope getFor(Scope scope, 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) {
|
||||
@ -47,7 +31,7 @@ public class DirectiveParserContext {
|
||||
} else if(scope instanceof StructDefinition) {
|
||||
return MEMBER;
|
||||
} else if(scope instanceof BlockScope) {
|
||||
return getFor(scope.getScope());
|
||||
return getFor(scope.getScope(), false);
|
||||
} else {
|
||||
throw new InternalError("Scope type not handled " + scope);
|
||||
}
|
||||
@ -83,212 +67,122 @@ public class DirectiveParserContext {
|
||||
}
|
||||
}
|
||||
|
||||
/** 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 DirectiveParserContext() {
|
||||
this.statementDirectives = null;
|
||||
// Setup default directives
|
||||
this.defaultDirectives = Arrays.asList(
|
||||
new Directive.MemoryArea(Variable.MemoryArea.ZEROPAGE_MEMORY, null),
|
||||
new Directive.FormSsa(true),
|
||||
new Directive.Const(Variable.ConstantDeclaration.MAYBE_CONST)
|
||||
);
|
||||
this.registerImpliesDirectives = new ArrayList<>();
|
||||
this.typeDirectives = new HashMap<>();
|
||||
this.typeDirectives.put(DirectiveType.ARRAY, Arrays.asList(
|
||||
new Directive.Const(Variable.ConstantDeclaration.CONST),
|
||||
new Directive.MemoryArea(Variable.MemoryArea.MAIN_MEMORY, null)
|
||||
));
|
||||
this.typeDirectives.put(DirectiveType.POINTER, Arrays.asList(
|
||||
new Directive.MemoryArea(Variable.MemoryArea.ZEROPAGE_MEMORY, null)
|
||||
));
|
||||
this.scopeDirectives = new HashMap<>();
|
||||
//this.scopeDirectives.put(DirectiveScope.GLOBAL, Arrays.asList(
|
||||
// new Directive.MemoryArea(Variable.MemoryArea.MAIN_MEMORY, null),
|
||||
// new Directive.FormSsa(false)
|
||||
//));
|
||||
this.scopeTypeDirectives = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies directives to a variable. Applies directives using the correct priority.
|
||||
* Find the variable kind for a declared variable (not used for intermediates or PHI-versions)
|
||||
*
|
||||
* @param type The type of the variable
|
||||
* @param scope The scope
|
||||
* @param isParameter true if the variable is a procedure parameter
|
||||
* @param sourceDirectives The directives in the source code
|
||||
* @param source The source line (for exceptions)
|
||||
* @return The variable kind
|
||||
*/
|
||||
public Variable.Kind getKind(SymbolType type, Scope scope, boolean isParameter, List<Directive> sourceDirectives, StatementSource source) {
|
||||
// Look for const without volatile
|
||||
if(hasDirective(Directive.Const.class, sourceDirectives))
|
||||
if(!hasDirective(Directive.Volatile.class, sourceDirectives))
|
||||
return Variable.Kind.CONSTANT;
|
||||
// Look for array (which is implicitly const
|
||||
DirectiveType directiveType = DirectiveType.getFor(type);
|
||||
if(DirectiveType.ARRAY.equals(directiveType))
|
||||
return Variable.Kind.CONSTANT;
|
||||
// It is not a constant - determine PHI_MASTER vs LOAD_STORE
|
||||
if(hasDirective(Directive.FormSsa.class, sourceDirectives))
|
||||
return Variable.Kind.PHI_MASTER;
|
||||
if(hasDirective(Directive.FormMa.class, sourceDirectives))
|
||||
return Variable.Kind.LOAD_STORE;
|
||||
if(hasDirective(Directive.Register.class, sourceDirectives))
|
||||
return Variable.Kind.PHI_MASTER;
|
||||
if(hasDirective(Directive.NamedRegister.class, sourceDirectives))
|
||||
return Variable.Kind.PHI_MASTER;
|
||||
// TODO: Add strategy for selecting LOAD_STORE for global vars
|
||||
return Variable.Kind.PHI_MASTER;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @return
|
||||
* @param source The source line (for exceptions)
|
||||
*/
|
||||
public void applyDirectives(Variable lValue, boolean isParameter, List<Directive> sourceDirectives, StatementSource source) {
|
||||
DirectiveType directiveType = DirectiveType.getFor(lValue.getType());
|
||||
DirectiveScope directiveScope = DirectiveScope.getFor(lValue, isParameter);
|
||||
|
||||
Directive.FormSsa ssaDirective = findDirective(Directive.FormSsa.class, sourceDirectives, directiveScope, directiveType);
|
||||
if(ssaDirective != null) {
|
||||
if(ssaDirective.ssa) {
|
||||
lValue.setStorageStrategy(Variable.StorageStrategy.PHI_MASTER);
|
||||
} else {
|
||||
lValue.setStorageStrategy(Variable.StorageStrategy.LOAD_STORE);
|
||||
}
|
||||
}
|
||||
|
||||
Directive.Const constDirective = findDirective(Directive.Const.class, sourceDirectives, directiveScope, directiveType);
|
||||
if(constDirective != null) {
|
||||
lValue.setConstantDeclaration(constDirective.constantDeclaration);
|
||||
if(Variable.ConstantDeclaration.CONST.equals(constDirective.constantDeclaration)) {
|
||||
lValue.setStorageStrategy(Variable.StorageStrategy.CONSTANT);
|
||||
if(!(lValue.getType() instanceof SymbolTypePointer))
|
||||
lValue.setMemoryArea(Variable.MemoryArea.MAIN_MEMORY);
|
||||
}
|
||||
}
|
||||
|
||||
Directive.Volatile volatileDirective = findDirective(Directive.Volatile.class, sourceDirectives, directiveScope, directiveType);
|
||||
if(volatileDirective != null) {
|
||||
lValue.setDeclaredVolatile(volatileDirective.isVolatile);
|
||||
}
|
||||
|
||||
Directive.Export exportDirective = findDirective(Directive.Export.class, sourceDirectives, directiveScope, directiveType);
|
||||
if(exportDirective != null) {
|
||||
if(hasDirective(Directive.Const.class, sourceDirectives))
|
||||
lValue.setConstantDeclaration(Variable.ConstantDeclaration.CONST);
|
||||
if(directiveType.equals(DirectiveType.ARRAY))
|
||||
lValue.setConstantDeclaration(Variable.ConstantDeclaration.CONST);
|
||||
if(hasDirective(Directive.NotConst.class, sourceDirectives))
|
||||
lValue.setConstantDeclaration(Variable.ConstantDeclaration.NOT_CONST);
|
||||
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(directiveType.equals(DirectiveType.ARRAY))
|
||||
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.Align alignDirective = findDirective(Directive.Align.class, sourceDirectives, directiveScope, directiveType);
|
||||
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) {
|
||||
SymbolType type = lValue.getType();
|
||||
if(type instanceof SymbolTypeArray || type.equals(SymbolType.STRING)) {
|
||||
if(directiveType.equals(DirectiveType.ARRAY)) {
|
||||
lValue.setDeclaredAlignment(alignDirective.alignment);
|
||||
} else {
|
||||
throw new CompileError("Error! Cannot align variable that is not a string or an array " + lValue.toString(), source);
|
||||
}
|
||||
}
|
||||
|
||||
Directive.MemoryArea memoryAreaDirective = findDirective(Directive.MemoryArea.class, sourceDirectives, directiveScope, directiveType);
|
||||
if(memoryAreaDirective != null) {
|
||||
lValue.setMemoryArea(memoryAreaDirective.memoryArea);
|
||||
if(memoryAreaDirective.address != null) {
|
||||
if(Variable.MemoryArea.ZEROPAGE_MEMORY.equals(memoryAreaDirective.memoryArea)) {
|
||||
Registers.Register register = new Registers.RegisterZpMem(memoryAreaDirective.address.intValue(), -1, true);
|
||||
lValue.setDeclaredRegister(register);
|
||||
} else {
|
||||
Registers.Register register = new Registers.RegisterMainMem((VariableRef) lValue.getRef(), -1, memoryAreaDirective.address);
|
||||
lValue.setDeclaredRegister(register);
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: Add strategy for selecting main memory for non-pointer local variables
|
||||
//DirectiveScope directiveScope = DirectiveScope.getFor(lValue.getScope(), isParameter);
|
||||
|
||||
Directive.Register registerDirective = findDirective(Directive.Register.class, sourceDirectives, directiveScope, directiveType);
|
||||
if(registerDirective != null) {
|
||||
if(registerDirective.isRegister) {
|
||||
lValue.setDeclaredAsRegister(true);
|
||||
lValue.setStorageStrategy(Variable.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(Variable.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.
|
||||
* Examines whether a specific directive is present in the source
|
||||
*
|
||||
* @param sourceDirectives The source directives
|
||||
* @return true if the register keyword is present
|
||||
* @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 boolean isRegister(List<Directive> sourceDirectives) {
|
||||
Directive.Register registerDirective = findDirective(Directive.Register.class, sourceDirectives);
|
||||
return registerDirective != null && registerDirective.isRegister;
|
||||
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
|
||||
*
|
||||
|
@ -35,7 +35,7 @@ public class ProgramValueIterator {
|
||||
* @param handler The handler to execute
|
||||
*/
|
||||
public static void execute(ProgramScope programScope, ProgramValueHandler handler) {
|
||||
for(Variable variable : programScope.getAllSymbolVariables(true)) {
|
||||
for(Variable variable : programScope.getAllVars(true)) {
|
||||
execute(variable, handler);
|
||||
}
|
||||
}
|
||||
|
@ -100,13 +100,17 @@ public abstract class Scope implements Symbol, Serializable {
|
||||
symbols.remove(symbol.getLocalName());
|
||||
}
|
||||
|
||||
public Variable addVariable(Variable.Kind kind, String name, SymbolType type, Variable.MemoryArea memoryArea, String dataSegment) {
|
||||
return add(new Variable( name, this, type, kind, memoryArea, dataSegment));
|
||||
}
|
||||
|
||||
public Variable addVariablePhiMaster(String name, SymbolType type, Variable.MemoryArea memoryArea, String dataSegment) {
|
||||
return add(new Variable( name, this, type, Variable.StorageStrategy.PHI_MASTER, memoryArea, dataSegment));
|
||||
return add(new Variable( name, this, type, Variable.Kind.PHI_MASTER, memoryArea, dataSegment));
|
||||
}
|
||||
|
||||
public Variable addVariableIntermediate() {
|
||||
String name = allocateIntermediateVariableName();
|
||||
return add(new Variable( name, this, SymbolType.VAR, Variable.StorageStrategy.INTERMEDIATE, Variable.MemoryArea.ZEROPAGE_MEMORY, getSegmentData()));
|
||||
return add(new Variable( name, this, SymbolType.VAR, Variable.Kind.INTERMEDIATE, Variable.MemoryArea.ZEROPAGE_MEMORY, getSegmentData()));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -120,7 +124,7 @@ public abstract class Scope implements Symbol, Serializable {
|
||||
for(Symbol symbol : symbols.values()) {
|
||||
if(symbol instanceof Variable) {
|
||||
Variable variable = (Variable) symbol;
|
||||
if(variable.isVariable() && variable.isStoragePhiVersion() && variable.getVersionOf().equals(unversioned)) {
|
||||
if(variable.isVariable() && variable.isKindPhiVersion() && variable.getVersionOf().equals(unversioned)) {
|
||||
versions.add(variable);
|
||||
}
|
||||
}
|
||||
@ -163,6 +167,15 @@ public abstract class Scope implements Symbol, Serializable {
|
||||
return symbols.get(name);
|
||||
}
|
||||
|
||||
public Variable getVar(String name) {
|
||||
Variable symbol = (Variable) getSymbol(name);
|
||||
return symbol;
|
||||
}
|
||||
|
||||
public Variable getVar(SymbolVariableRef variableRef) {
|
||||
return getVar(variableRef.getFullName());
|
||||
}
|
||||
|
||||
public Variable getVariable(String name) {
|
||||
Variable symbol = (Variable) getSymbol(name);
|
||||
if(symbol!=null && !symbol.isVariable()) throw new InternalError("Symbol is not a variable! "+symbol.toString());
|
||||
@ -183,7 +196,12 @@ public abstract class Scope implements Symbol, Serializable {
|
||||
return getConstant(constantRef.getFullName());
|
||||
}
|
||||
|
||||
public Collection<Variable> getAllSymbolVariables(boolean includeSubScopes) {
|
||||
/**
|
||||
* Get all variables/constants
|
||||
* @param includeSubScopes true to include sub-scopes
|
||||
* @return all variables/constants
|
||||
*/
|
||||
public Collection<Variable> getAllVars(boolean includeSubScopes) {
|
||||
Collection<Variable> vars = new ArrayList<>();
|
||||
for(Symbol symbol : symbols.values()) {
|
||||
if(symbol instanceof Variable) {
|
||||
@ -191,25 +209,33 @@ public abstract class Scope implements Symbol, Serializable {
|
||||
}
|
||||
if(includeSubScopes && symbol instanceof Scope) {
|
||||
Scope subScope = (Scope) symbol;
|
||||
vars.addAll(subScope.getAllSymbolVariables(true));
|
||||
vars.addAll(subScope.getAllVars(true));
|
||||
}
|
||||
}
|
||||
return vars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all runtime variables (excluding constants)
|
||||
* @param includeSubScopes true to include sub-scopes
|
||||
* @return all runtime variables (excluding constants)
|
||||
*/
|
||||
public Collection<Variable> getAllVariables(boolean includeSubScopes) {
|
||||
Collection<Variable> variables = getAllSymbolVariables(includeSubScopes);
|
||||
Collection<Variable> vars = new ArrayList<>();
|
||||
variables.stream().
|
||||
getAllVars(includeSubScopes).stream().
|
||||
filter(Variable::isVariable).
|
||||
forEach(vars::add);
|
||||
return vars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all constants
|
||||
* @param includeSubScopes true to include sub-scopes
|
||||
* @return all constants
|
||||
*/
|
||||
public Collection<Variable> getAllConstants(boolean includeSubScopes) {
|
||||
Collection<Variable> variables = getAllSymbolVariables(includeSubScopes);
|
||||
Collection<Variable> vars = new ArrayList<>();
|
||||
variables.stream().
|
||||
getAllVars(includeSubScopes).stream().
|
||||
filter(Variable::isConstant).
|
||||
forEach(vars::add);
|
||||
return vars;
|
||||
@ -351,7 +377,7 @@ public abstract class Scope implements Symbol, Serializable {
|
||||
if(symVar.getAsmName() != null && !symVar.getName().equals(symVar.getAsmName())) {
|
||||
res.append(" " + symVar.getAsmName());
|
||||
}
|
||||
if(symVar.isStorageLoadStore()) {
|
||||
if(symVar.isKindLoadStore()) {
|
||||
res.append(" notregister");
|
||||
}
|
||||
Registers.Register declRegister = symVar.getDeclaredRegister();
|
||||
|
@ -16,43 +16,60 @@ import java.util.List;
|
||||
/** A Variable symbol (can either be a runtime variable or a compile-time constant)*/
|
||||
public class Variable implements Symbol {
|
||||
|
||||
/** The name of the variable. */
|
||||
private String name;
|
||||
|
||||
/** The scope containing the variable */
|
||||
private Scope scope;
|
||||
|
||||
/** The type of the variable. VAR means tha type is unknown, and has not been inferred yet. */
|
||||
private SymbolType type;
|
||||
|
||||
/** true if the symbol type is inferred (not declared) */
|
||||
private boolean inferredType;
|
||||
|
||||
/** A short name used for the variable in ASM code. If possible variable names of variables are shortened in ASM code. This is possible, when several versions of the var use the same register. */
|
||||
private String asmName;
|
||||
|
||||
/** True of the variable is a compile-time constant (previously ConstantVar */
|
||||
private boolean isConstant;
|
||||
|
||||
/** Specifies whether the symbol is declared to be constant, never constant or maybe constant. */
|
||||
public enum ConstantDeclaration {
|
||||
CONST, NOT_CONST, MAYBE_CONST
|
||||
/**
|
||||
* The kind of the variable. The kind is the most significant property of the variable since it drives most of the behavior.
|
||||
*
|
||||
* The value depends on the directives memory/register/volatile/const - and on the compilers optimization decisions.
|
||||
* <ul>
|
||||
* <li>PHI_MASTER variables are turned into PHI-versions and PHI-nodes are used for them throughout the entire program. The PHI-master itself is only an information container and does not live in memory at runtime.</li>
|
||||
* <li>PHI_VERSION variables are versions of a PHI-master. A PHI-version lives in memory or a register at runtime.</li>
|
||||
* <li>INTERMEDIATE variables are created when expressions are broken into smaller statements. The type of intermediate variables must be inferred by the compiler. An intermediate variable lives in memory or a register at runtime.</li>
|
||||
* <li>LOAD_STORE variables are accessed through load/store operations. They can have hardcoded memory addresses. A load/store-variable lives in memory or a register at runtime</li>
|
||||
* <li>CONSTANT variables are compile-time constants. They do not live in memory at runtime. An array is a compile-time constant pointer. The array itself lives in memory but the pointer does not.
|
||||
* </ul>
|
||||
**/
|
||||
public enum Kind {
|
||||
PHI_MASTER, PHI_VERSION, INTERMEDIATE, LOAD_STORE, CONSTANT
|
||||
}
|
||||
|
||||
/** Specifies that the variable is declared a constant. It will be replaced by a ConstantVar when possible. */
|
||||
/** The storage strategy for the variable. */
|
||||
private Kind kind;
|
||||
|
||||
/** The local name of the variable. [ALL] */
|
||||
private String name;
|
||||
|
||||
/** Full name of variable including scope (scope::name or name) [ALL] */
|
||||
private String fullName;
|
||||
|
||||
/** A short name used for the variable in ASM code. If possible variable names of variables are shortened in ASM code. This is possible, when several versions of the var use the same register. [ALL]*/
|
||||
private String asmName;
|
||||
|
||||
/** The scope containing the variable. [ALL] */
|
||||
private Scope scope;
|
||||
|
||||
/** The type of the variable. VAR means tha type is unknown, and has not been inferred yet. [ALL]*/
|
||||
private SymbolType type;
|
||||
|
||||
/** true if the symbol type is inferred (not declared) [kind:INTERMEDIATE] TODO: Collapse with kind==INTERMEDIATE? */
|
||||
private boolean inferredType;
|
||||
|
||||
/** True of the variable is a compile-time constant (previously ConstantVar) [ALL] */
|
||||
private boolean isConstant;
|
||||
|
||||
/** Specifies that the variable is declared a constant. It will be replaced by a ConstantVar when possible. [ALL] TODO: Collapse with isConstant?*/
|
||||
private ConstantDeclaration constantDeclaration;
|
||||
|
||||
/** Specifies that the variable must be aligned in memory. Only allowed for arrays & strings. */
|
||||
/** Specifies that the variable must be aligned in memory. Only allowed for arrays & strings. [Only Variables in memory and arrays] */
|
||||
private Integer declaredAlignment;
|
||||
|
||||
/** Specifies the register the variable must be put into during execution. */
|
||||
/** Specifies the register the variable must be put into during execution. [Only variables] */
|
||||
private Registers.Register declaredRegister;
|
||||
|
||||
/** Specifies that the variable must always live in memory to be available for any multi-threaded accees (eg. in interrupts). */
|
||||
/** Specifies that the variable must always live in memory to be available for any multi-threaded accees (eg. in interrupts). [Only Variables]*/
|
||||
private boolean declaredVolatile;
|
||||
|
||||
/** Specifies that the variable must always live in memory to be available for any multi-threaded accees (eg. in interrupts). */
|
||||
private boolean inferedVolatile;
|
||||
/** Specifies that the variable must always live in memory to be available for any multi-threaded accees (eg. in interrupts). [Only variables] TODO: Remove this */
|
||||
private boolean inferredVolatile;
|
||||
|
||||
/** Specifies that the variable must always be added to the output ASM even if it is never used anywhere. */
|
||||
private boolean declaredExport;
|
||||
@ -60,52 +77,37 @@ public class Variable implements Symbol {
|
||||
/** Specifies that the variable must live in a register if possible (CPU register or ZP-address). */
|
||||
private boolean declaredAsRegister;
|
||||
|
||||
/** Specifies that the variable must live in memory. */
|
||||
/** Specifies that the variable must live in memory. TODO: Remove this */
|
||||
private boolean declaredAsNotRegister;
|
||||
|
||||
/**
|
||||
* Strategy being used for storing and accessing the variable. The value depends on the directives memory/register/volatile/const - and on the compilers optimization decisions.
|
||||
* <ul>
|
||||
* <li>PHI variables are turned into versions and PHI-nodes are used for them throughout the entire program. They cannot be "volatile" and the "address-of" operator cannot be used on them.</li>
|
||||
* <li>INTERMEDIATE variables are created when expressions are broken into smaller statements. </li>
|
||||
* <li>LOAD_STORE variables are accessed through load/store operations. </li>
|
||||
* <li>CONSTANT variables are constant.
|
||||
* </ul>
|
||||
**/
|
||||
public enum StorageStrategy {
|
||||
PHI_MASTER, PHI_VERSION, INTERMEDIATE, LOAD_STORE, CONSTANT
|
||||
}
|
||||
/** The memory area where the variable lives (if stored in memory). [Only variables] */
|
||||
private MemoryArea memoryArea;
|
||||
|
||||
/** The storage strategy for the variable. */
|
||||
private StorageStrategy storageStrategy;
|
||||
/** Comments preceding the procedure in the source code. [ALL] */
|
||||
private List<Comment> comments;
|
||||
|
||||
/** The data segment to put the variable into (if it is allocated in memory). [Only variables stored in memory and arrays] */
|
||||
private String dataSegment;
|
||||
|
||||
/** The constant value if the variable is a constant. Null otherwise. [Only constants] */
|
||||
private ConstantValue constantValue;
|
||||
|
||||
/** The number of the next version (only used for PHI masters) [Only PHI masters] */
|
||||
private Integer nextPhiVersionNumber;
|
||||
|
||||
/** If the variable is assigned to a specific "register", this contains the register. If null the variable has no allocation (yet). Constants are never assigned to registers. [Only variables - not constants and not PHI masters] */
|
||||
private Registers.Register allocation;
|
||||
|
||||
/** Specifies whether the symbol is declared to be constant, never constant or maybe constant. */
|
||||
public enum ConstantDeclaration {
|
||||
CONST, NOT_CONST, MAYBE_CONST
|
||||
}
|
||||
|
||||
/** Memory area used for storing the variable (if is is stored in memory). */
|
||||
public enum MemoryArea {
|
||||
ZEROPAGE_MEMORY, MAIN_MEMORY
|
||||
}
|
||||
|
||||
/** The memory area where the variable lives (if stored in memory). */
|
||||
private MemoryArea memoryArea;
|
||||
|
||||
/** Comments preceding the procedure in the source code. */
|
||||
private List<Comment> comments;
|
||||
|
||||
/** Full name of variable (scope::name or name) */
|
||||
private String fullName;
|
||||
|
||||
/** The data segment to put the variable into (if it is allocated in memory). */
|
||||
private String dataSegment;
|
||||
|
||||
/** The constant value if the variable is a constant. Null otherwise. */
|
||||
private ConstantValue constantValue;
|
||||
|
||||
/** The number of the next version (only used for PHI masters) */
|
||||
private Integer nextPhiVersionNumber;
|
||||
|
||||
/** If the variable is assigned to a specific "register", this contains the register. If null the variable has no allocation (yet). Constants are never assigned to registers. */
|
||||
private Registers.Register allocation;
|
||||
|
||||
|
||||
/**
|
||||
* Create a compile-time constant variable
|
||||
* @param name The name
|
||||
@ -120,7 +122,7 @@ public class Variable implements Symbol {
|
||||
this.scope = scope;
|
||||
this.type = type;
|
||||
this.dataSegment = dataSegment;
|
||||
this.storageStrategy = StorageStrategy.CONSTANT;
|
||||
this.kind = Kind.CONSTANT;
|
||||
this.memoryArea = MemoryArea.MAIN_MEMORY;
|
||||
this.constantDeclaration = ConstantDeclaration.MAYBE_CONST;
|
||||
this.constantValue = value;
|
||||
@ -134,20 +136,20 @@ public class Variable implements Symbol {
|
||||
* @param name The name
|
||||
* @param scope The scope
|
||||
* @param type The type
|
||||
* @param storageStrategy The storage strategy (PHI-master/PHI-version/Intermediate/load store/constant)
|
||||
* @param kind The storage strategy (PHI-master/PHI-version/Intermediate/load store/constant)
|
||||
* @param memoryArea The memory area (zeropage/main memory)
|
||||
* @param dataSegment The data segment (in main memory)
|
||||
*/
|
||||
public Variable(String name, Scope scope, SymbolType type, StorageStrategy storageStrategy, MemoryArea memoryArea, String dataSegment) {
|
||||
public Variable(String name, Scope scope, SymbolType type, Kind kind, MemoryArea memoryArea, String dataSegment) {
|
||||
this.isConstant = false;
|
||||
this.name = name;
|
||||
this.scope = scope;
|
||||
this.type = type;
|
||||
this.dataSegment = dataSegment;
|
||||
this.storageStrategy = storageStrategy;
|
||||
this.kind = kind;
|
||||
this.memoryArea = memoryArea;
|
||||
this.constantDeclaration = ConstantDeclaration.MAYBE_CONST;
|
||||
if(StorageStrategy.PHI_MASTER.equals(storageStrategy))
|
||||
if(Kind.PHI_MASTER.equals(kind))
|
||||
this.nextPhiVersionNumber = 0;
|
||||
this.inferredType = false;
|
||||
this.comments = new ArrayList<>();
|
||||
@ -162,7 +164,7 @@ public class Variable implements Symbol {
|
||||
* @param version The version number
|
||||
*/
|
||||
public Variable(Variable phiMaster, int version) {
|
||||
this(phiMaster.getName() + "#" + version, phiMaster.getScope(), phiMaster.getType(), StorageStrategy.PHI_VERSION, phiMaster.getMemoryArea(), phiMaster.getDataSegment());
|
||||
this(phiMaster.getName() + "#" + version, phiMaster.getScope(), phiMaster.getType(), Kind.PHI_VERSION, phiMaster.getMemoryArea(), phiMaster.getDataSegment());
|
||||
this.setDeclaredAlignment(phiMaster.getDeclaredAlignment());
|
||||
this.setDeclaredAsRegister(phiMaster.isDeclaredAsRegister());
|
||||
this.setDeclaredNotRegister(phiMaster.isDeclaredAsNotRegister());
|
||||
@ -170,11 +172,40 @@ public class Variable implements Symbol {
|
||||
this.setDeclaredRegister(phiMaster.getDeclaredRegister());
|
||||
this.setDeclaredVolatile(phiMaster.isDeclaredVolatile());
|
||||
this.setDeclaredExport(phiMaster.isDeclaredExport());
|
||||
this.setInferedVolatile(phiMaster.isInferedVolatile());
|
||||
this.setInferredVolatile(phiMaster.isInferredVolatile());
|
||||
this.setInferredType(phiMaster.isInferredType());
|
||||
this.setComments(phiMaster.getComments());
|
||||
}
|
||||
|
||||
|
||||
public Kind getKind() {
|
||||
return kind;
|
||||
}
|
||||
|
||||
public void setKind(Kind kind) {
|
||||
this.kind = kind;
|
||||
}
|
||||
|
||||
public boolean isKindConstant() {
|
||||
return Kind.CONSTANT.equals(getKind());
|
||||
}
|
||||
|
||||
public boolean isKindPhiMaster() {
|
||||
return Kind.PHI_MASTER.equals(getKind());
|
||||
}
|
||||
|
||||
public boolean isKindPhiVersion() {
|
||||
return Kind.PHI_VERSION.equals(getKind());
|
||||
}
|
||||
|
||||
public boolean isKindLoadStore() {
|
||||
return Kind.LOAD_STORE.equals(getKind());
|
||||
}
|
||||
|
||||
public boolean isKindIntermediate() {
|
||||
return Kind.INTERMEDIATE.equals(getKind());
|
||||
}
|
||||
|
||||
/**
|
||||
* True if the variable is a compile time constant. (Previously this was ConstantVar)
|
||||
*
|
||||
@ -190,11 +221,11 @@ public class Variable implements Symbol {
|
||||
* @return True if the variable is not a compile-time constant
|
||||
*/
|
||||
public boolean isVariable() {
|
||||
return !isConstant;
|
||||
return !isConstant();
|
||||
}
|
||||
|
||||
public SymbolVariableRef getRef() {
|
||||
if(isConstant)
|
||||
if(isConstant())
|
||||
return new ConstantRef(this);
|
||||
else
|
||||
return new VariableRef(this);
|
||||
@ -219,7 +250,7 @@ public class Variable implements Symbol {
|
||||
* @return The new version of the PHI master
|
||||
*/
|
||||
public Variable createVersion() {
|
||||
if(!isStoragePhiMaster())
|
||||
if(!isKindPhiMaster())
|
||||
throw new InternalError("Cannot version non-PHI variable " + this.toString());
|
||||
Variable version = new Variable(this, nextPhiVersionNumber++);
|
||||
getScope().add(version);
|
||||
@ -232,7 +263,7 @@ public class Variable implements Symbol {
|
||||
* @return The original variable. Null if this is not a version.
|
||||
*/
|
||||
public Variable getVersionOf() {
|
||||
if(!isStoragePhiVersion())
|
||||
if(!isKindPhiVersion())
|
||||
throw new InternalError("Cannot get master for non-PHI version variable " + this.toString());
|
||||
String name = getName();
|
||||
String versionOfName = name.substring(0, name.indexOf("#"));
|
||||
@ -366,16 +397,16 @@ public class Variable implements Symbol {
|
||||
this.declaredVolatile = declaredVolatile;
|
||||
}
|
||||
|
||||
public void setInferedVolatile(boolean inferedVolatile) {
|
||||
this.inferedVolatile = inferedVolatile;
|
||||
public void setInferredVolatile(boolean inferredVolatile) {
|
||||
this.inferredVolatile = inferredVolatile;
|
||||
}
|
||||
|
||||
public boolean isInferedVolatile() {
|
||||
return inferedVolatile;
|
||||
public boolean isInferredVolatile() {
|
||||
return inferredVolatile;
|
||||
}
|
||||
|
||||
public boolean isVolatile() {
|
||||
return declaredVolatile || inferedVolatile;
|
||||
return declaredVolatile || inferredVolatile;
|
||||
}
|
||||
|
||||
public boolean isDeclaredExport() {
|
||||
@ -402,34 +433,6 @@ public class Variable implements Symbol {
|
||||
this.declaredAsNotRegister = declaredAsMemory;
|
||||
}
|
||||
|
||||
public StorageStrategy getStorageStrategy() {
|
||||
return storageStrategy;
|
||||
}
|
||||
|
||||
public void setStorageStrategy(StorageStrategy storageStrategy) {
|
||||
this.storageStrategy = storageStrategy;
|
||||
}
|
||||
|
||||
public boolean isStorageConstant() {
|
||||
return StorageStrategy.CONSTANT.equals(getStorageStrategy());
|
||||
}
|
||||
|
||||
public boolean isStoragePhiMaster() {
|
||||
return StorageStrategy.PHI_MASTER.equals(getStorageStrategy());
|
||||
}
|
||||
|
||||
public boolean isStoragePhiVersion() {
|
||||
return StorageStrategy.PHI_VERSION.equals(getStorageStrategy());
|
||||
}
|
||||
|
||||
public boolean isStorageLoadStore() {
|
||||
return StorageStrategy.LOAD_STORE.equals(getStorageStrategy());
|
||||
}
|
||||
|
||||
public boolean isStorageIntermediate() {
|
||||
return StorageStrategy.INTERMEDIATE.equals(getStorageStrategy());
|
||||
}
|
||||
|
||||
public MemoryArea getMemoryArea() {
|
||||
return memoryArea;
|
||||
}
|
||||
|
@ -15,12 +15,9 @@ public class SymbolTypeInference {
|
||||
|
||||
public static SymbolType inferType(ProgramScope symbols, RValue rValue) {
|
||||
SymbolType type = null;
|
||||
if(rValue instanceof VariableRef) {
|
||||
Variable variable = symbols.getVariable((VariableRef) rValue);
|
||||
if(rValue instanceof SymbolVariableRef) {
|
||||
Variable variable = symbols.getVar((SymbolVariableRef) rValue);
|
||||
type = variable.getType();
|
||||
} else if(rValue instanceof ConstantRef) {
|
||||
Variable constVar = symbols.getConstant((ConstantRef) rValue);
|
||||
type = constVar.getType();
|
||||
} else if(rValue instanceof Symbol) {
|
||||
Symbol rSymbol = (Symbol) rValue;
|
||||
type = rSymbol.getType();
|
||||
|
@ -74,21 +74,19 @@ CODESEG:'code_seg';
|
||||
DATASEG:'data_seg';
|
||||
ENCODING:'encoding';
|
||||
CONST: 'const' ;
|
||||
NOTCONST: '__notconst' ;
|
||||
MAYBECONST: '__maybeconst' ;
|
||||
EXTERN: 'extern' ;
|
||||
EXPORT: 'export' ;
|
||||
ALIGN: 'align' ;
|
||||
INLINE: 'inline' ;
|
||||
VOLATILE: 'volatile' ;
|
||||
INTERRUPT: 'interrupt' ;
|
||||
REGISTER: 'register' ;
|
||||
ADDRESS: '__address' ;
|
||||
ADDRESS_ZEROPAGE: '__zp' ;
|
||||
ADDRESS_MAINMEM: '__mem' ;
|
||||
NOTCONST: '__notconst' ;
|
||||
FORM_SSA: '__ssa' ;
|
||||
FORM_NOTSSA: '__notssa' ;
|
||||
INLINE: 'inline' ;
|
||||
VOLATILE: 'volatile' ;
|
||||
NOTVOLATILE: '__notvolatile' ;
|
||||
INTERRUPT: 'interrupt' ;
|
||||
FORM_MA: '__ma' ;
|
||||
CALLING: 'calling';
|
||||
CALLINGCONVENTION: '__stackcall' | '__phicall' ;
|
||||
IF: 'if' ;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -47,101 +47,99 @@ CODESEG=46
|
||||
DATASEG=47
|
||||
ENCODING=48
|
||||
CONST=49
|
||||
NOTCONST=50
|
||||
MAYBECONST=51
|
||||
EXTERN=52
|
||||
EXPORT=53
|
||||
ALIGN=54
|
||||
REGISTER=55
|
||||
ADDRESS=56
|
||||
ADDRESS_ZEROPAGE=57
|
||||
ADDRESS_MAINMEM=58
|
||||
FORM_SSA=59
|
||||
FORM_NOTSSA=60
|
||||
INLINE=61
|
||||
VOLATILE=62
|
||||
NOTVOLATILE=63
|
||||
INTERRUPT=64
|
||||
CALLING=65
|
||||
CALLINGCONVENTION=66
|
||||
IF=67
|
||||
ELSE=68
|
||||
WHILE=69
|
||||
DO=70
|
||||
FOR=71
|
||||
SWITCH=72
|
||||
RETURN=73
|
||||
BREAK=74
|
||||
CONTINUE=75
|
||||
ASM=76
|
||||
DEFAULT=77
|
||||
CASE=78
|
||||
STRUCT=79
|
||||
ENUM=80
|
||||
SIZEOF=81
|
||||
TYPEID=82
|
||||
KICKASM=83
|
||||
RESOURCE=84
|
||||
USES=85
|
||||
CLOBBERS=86
|
||||
BYTES=87
|
||||
CYCLES=88
|
||||
LOGIC_NOT=89
|
||||
SIGNEDNESS=90
|
||||
SIMPLETYPE=91
|
||||
BOOLEAN=92
|
||||
KICKASM_BODY=93
|
||||
STRING=94
|
||||
CHAR=95
|
||||
NUMBER=96
|
||||
NUMFLOAT=97
|
||||
BINFLOAT=98
|
||||
DECFLOAT=99
|
||||
HEXFLOAT=100
|
||||
NUMINT=101
|
||||
BININTEGER=102
|
||||
DECINTEGER=103
|
||||
HEXINTEGER=104
|
||||
NAME=105
|
||||
WS=106
|
||||
COMMENT_LINE=107
|
||||
COMMENT_BLOCK=108
|
||||
ASM_BYTE=109
|
||||
ASM_MNEMONIC=110
|
||||
ASM_IMM=111
|
||||
ASM_COLON=112
|
||||
ASM_COMMA=113
|
||||
ASM_PAR_BEGIN=114
|
||||
ASM_PAR_END=115
|
||||
ASM_BRACKET_BEGIN=116
|
||||
ASM_BRACKET_END=117
|
||||
ASM_DOT=118
|
||||
ASM_SHIFT_LEFT=119
|
||||
ASM_SHIFT_RIGHT=120
|
||||
ASM_PLUS=121
|
||||
ASM_MINUS=122
|
||||
ASM_LESS_THAN=123
|
||||
ASM_GREATER_THAN=124
|
||||
ASM_MULTIPLY=125
|
||||
ASM_DIVIDE=126
|
||||
ASM_CURLY_BEGIN=127
|
||||
ASM_CURLY_END=128
|
||||
ASM_NUMBER=129
|
||||
ASM_NUMFLOAT=130
|
||||
ASM_BINFLOAT=131
|
||||
ASM_DECFLOAT=132
|
||||
ASM_HEXFLOAT=133
|
||||
ASM_NUMINT=134
|
||||
ASM_BININTEGER=135
|
||||
ASM_DECINTEGER=136
|
||||
ASM_HEXINTEGER=137
|
||||
ASM_CHAR=138
|
||||
ASM_MULTI_REL=139
|
||||
ASM_MULTI_NAME=140
|
||||
ASM_NAME=141
|
||||
ASM_WS=142
|
||||
ASM_COMMENT_LINE=143
|
||||
ASM_COMMENT_BLOCK=144
|
||||
EXTERN=50
|
||||
EXPORT=51
|
||||
ALIGN=52
|
||||
INLINE=53
|
||||
VOLATILE=54
|
||||
INTERRUPT=55
|
||||
REGISTER=56
|
||||
ADDRESS=57
|
||||
ADDRESS_ZEROPAGE=58
|
||||
ADDRESS_MAINMEM=59
|
||||
NOTCONST=60
|
||||
FORM_SSA=61
|
||||
FORM_MA=62
|
||||
CALLING=63
|
||||
CALLINGCONVENTION=64
|
||||
IF=65
|
||||
ELSE=66
|
||||
WHILE=67
|
||||
DO=68
|
||||
FOR=69
|
||||
SWITCH=70
|
||||
RETURN=71
|
||||
BREAK=72
|
||||
CONTINUE=73
|
||||
ASM=74
|
||||
DEFAULT=75
|
||||
CASE=76
|
||||
STRUCT=77
|
||||
ENUM=78
|
||||
SIZEOF=79
|
||||
TYPEID=80
|
||||
KICKASM=81
|
||||
RESOURCE=82
|
||||
USES=83
|
||||
CLOBBERS=84
|
||||
BYTES=85
|
||||
CYCLES=86
|
||||
LOGIC_NOT=87
|
||||
SIGNEDNESS=88
|
||||
SIMPLETYPE=89
|
||||
BOOLEAN=90
|
||||
KICKASM_BODY=91
|
||||
STRING=92
|
||||
CHAR=93
|
||||
NUMBER=94
|
||||
NUMFLOAT=95
|
||||
BINFLOAT=96
|
||||
DECFLOAT=97
|
||||
HEXFLOAT=98
|
||||
NUMINT=99
|
||||
BININTEGER=100
|
||||
DECINTEGER=101
|
||||
HEXINTEGER=102
|
||||
NAME=103
|
||||
WS=104
|
||||
COMMENT_LINE=105
|
||||
COMMENT_BLOCK=106
|
||||
ASM_BYTE=107
|
||||
ASM_MNEMONIC=108
|
||||
ASM_IMM=109
|
||||
ASM_COLON=110
|
||||
ASM_COMMA=111
|
||||
ASM_PAR_BEGIN=112
|
||||
ASM_PAR_END=113
|
||||
ASM_BRACKET_BEGIN=114
|
||||
ASM_BRACKET_END=115
|
||||
ASM_DOT=116
|
||||
ASM_SHIFT_LEFT=117
|
||||
ASM_SHIFT_RIGHT=118
|
||||
ASM_PLUS=119
|
||||
ASM_MINUS=120
|
||||
ASM_LESS_THAN=121
|
||||
ASM_GREATER_THAN=122
|
||||
ASM_MULTIPLY=123
|
||||
ASM_DIVIDE=124
|
||||
ASM_CURLY_BEGIN=125
|
||||
ASM_CURLY_END=126
|
||||
ASM_NUMBER=127
|
||||
ASM_NUMFLOAT=128
|
||||
ASM_BINFLOAT=129
|
||||
ASM_DECFLOAT=130
|
||||
ASM_HEXFLOAT=131
|
||||
ASM_NUMINT=132
|
||||
ASM_BININTEGER=133
|
||||
ASM_DECINTEGER=134
|
||||
ASM_HEXINTEGER=135
|
||||
ASM_CHAR=136
|
||||
ASM_MULTI_REL=137
|
||||
ASM_MULTI_NAME=138
|
||||
ASM_NAME=139
|
||||
ASM_WS=140
|
||||
ASM_COMMENT_LINE=141
|
||||
ASM_COMMENT_BLOCK=142
|
||||
';'=8
|
||||
'..'=11
|
||||
'?'=12
|
||||
@ -172,44 +170,42 @@ ASM_COMMENT_BLOCK=144
|
||||
'data_seg'=47
|
||||
'encoding'=48
|
||||
'const'=49
|
||||
'__notconst'=50
|
||||
'__maybeconst'=51
|
||||
'extern'=52
|
||||
'export'=53
|
||||
'align'=54
|
||||
'register'=55
|
||||
'__address'=56
|
||||
'__zp'=57
|
||||
'__mem'=58
|
||||
'__ssa'=59
|
||||
'__notssa'=60
|
||||
'inline'=61
|
||||
'volatile'=62
|
||||
'__notvolatile'=63
|
||||
'interrupt'=64
|
||||
'calling'=65
|
||||
'if'=67
|
||||
'else'=68
|
||||
'while'=69
|
||||
'do'=70
|
||||
'for'=71
|
||||
'switch'=72
|
||||
'return'=73
|
||||
'break'=74
|
||||
'continue'=75
|
||||
'asm'=76
|
||||
'default'=77
|
||||
'case'=78
|
||||
'struct'=79
|
||||
'enum'=80
|
||||
'sizeof'=81
|
||||
'typeid'=82
|
||||
'kickasm'=83
|
||||
'resource'=84
|
||||
'uses'=85
|
||||
'clobbers'=86
|
||||
'bytes'=87
|
||||
'cycles'=88
|
||||
'!'=89
|
||||
'.byte'=109
|
||||
'#'=111
|
||||
'extern'=50
|
||||
'export'=51
|
||||
'align'=52
|
||||
'inline'=53
|
||||
'volatile'=54
|
||||
'interrupt'=55
|
||||
'register'=56
|
||||
'__address'=57
|
||||
'__zp'=58
|
||||
'__mem'=59
|
||||
'__notconst'=60
|
||||
'__ssa'=61
|
||||
'__ma'=62
|
||||
'calling'=63
|
||||
'if'=65
|
||||
'else'=66
|
||||
'while'=67
|
||||
'do'=68
|
||||
'for'=69
|
||||
'switch'=70
|
||||
'return'=71
|
||||
'break'=72
|
||||
'continue'=73
|
||||
'asm'=74
|
||||
'default'=75
|
||||
'case'=76
|
||||
'struct'=77
|
||||
'enum'=78
|
||||
'sizeof'=79
|
||||
'typeid'=80
|
||||
'kickasm'=81
|
||||
'resource'=82
|
||||
'uses'=83
|
||||
'clobbers'=84
|
||||
'bytes'=85
|
||||
'cycles'=86
|
||||
'!'=87
|
||||
'.byte'=107
|
||||
'#'=109
|
||||
|
@ -97,16 +97,14 @@ globalDirective
|
||||
directive
|
||||
: CONST #directiveConst
|
||||
| NOTCONST #directiveNotConst
|
||||
| MAYBECONST #directiveMaybeConst
|
||||
| ALIGN PAR_BEGIN NUMBER PAR_END #directiveAlign
|
||||
| REGISTER ( PAR_BEGIN ( NAME ) PAR_END)? #directiveRegister
|
||||
| ADDRESS_ZEROPAGE #directiveMemoryAreaZp
|
||||
| ADDRESS_MAINMEM #directiveMemoryAreaMain
|
||||
| ADDRESS PAR_BEGIN ( NUMBER ) PAR_END #directiveMemoryAreaAddress
|
||||
| VOLATILE #directiveVolatile
|
||||
| NOTVOLATILE #directiveNotVolatile
|
||||
| FORM_SSA #directiveFormSsa
|
||||
| FORM_NOTSSA #directiveFormNotSsa
|
||||
| FORM_MA #directiveFormMa
|
||||
| EXTERN #directiveExtern
|
||||
| EXPORT #directiveExport
|
||||
| INLINE #directiveInline
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -47,101 +47,99 @@ CODESEG=46
|
||||
DATASEG=47
|
||||
ENCODING=48
|
||||
CONST=49
|
||||
NOTCONST=50
|
||||
MAYBECONST=51
|
||||
EXTERN=52
|
||||
EXPORT=53
|
||||
ALIGN=54
|
||||
REGISTER=55
|
||||
ADDRESS=56
|
||||
ADDRESS_ZEROPAGE=57
|
||||
ADDRESS_MAINMEM=58
|
||||
FORM_SSA=59
|
||||
FORM_NOTSSA=60
|
||||
INLINE=61
|
||||
VOLATILE=62
|
||||
NOTVOLATILE=63
|
||||
INTERRUPT=64
|
||||
CALLING=65
|
||||
CALLINGCONVENTION=66
|
||||
IF=67
|
||||
ELSE=68
|
||||
WHILE=69
|
||||
DO=70
|
||||
FOR=71
|
||||
SWITCH=72
|
||||
RETURN=73
|
||||
BREAK=74
|
||||
CONTINUE=75
|
||||
ASM=76
|
||||
DEFAULT=77
|
||||
CASE=78
|
||||
STRUCT=79
|
||||
ENUM=80
|
||||
SIZEOF=81
|
||||
TYPEID=82
|
||||
KICKASM=83
|
||||
RESOURCE=84
|
||||
USES=85
|
||||
CLOBBERS=86
|
||||
BYTES=87
|
||||
CYCLES=88
|
||||
LOGIC_NOT=89
|
||||
SIGNEDNESS=90
|
||||
SIMPLETYPE=91
|
||||
BOOLEAN=92
|
||||
KICKASM_BODY=93
|
||||
STRING=94
|
||||
CHAR=95
|
||||
NUMBER=96
|
||||
NUMFLOAT=97
|
||||
BINFLOAT=98
|
||||
DECFLOAT=99
|
||||
HEXFLOAT=100
|
||||
NUMINT=101
|
||||
BININTEGER=102
|
||||
DECINTEGER=103
|
||||
HEXINTEGER=104
|
||||
NAME=105
|
||||
WS=106
|
||||
COMMENT_LINE=107
|
||||
COMMENT_BLOCK=108
|
||||
ASM_BYTE=109
|
||||
ASM_MNEMONIC=110
|
||||
ASM_IMM=111
|
||||
ASM_COLON=112
|
||||
ASM_COMMA=113
|
||||
ASM_PAR_BEGIN=114
|
||||
ASM_PAR_END=115
|
||||
ASM_BRACKET_BEGIN=116
|
||||
ASM_BRACKET_END=117
|
||||
ASM_DOT=118
|
||||
ASM_SHIFT_LEFT=119
|
||||
ASM_SHIFT_RIGHT=120
|
||||
ASM_PLUS=121
|
||||
ASM_MINUS=122
|
||||
ASM_LESS_THAN=123
|
||||
ASM_GREATER_THAN=124
|
||||
ASM_MULTIPLY=125
|
||||
ASM_DIVIDE=126
|
||||
ASM_CURLY_BEGIN=127
|
||||
ASM_CURLY_END=128
|
||||
ASM_NUMBER=129
|
||||
ASM_NUMFLOAT=130
|
||||
ASM_BINFLOAT=131
|
||||
ASM_DECFLOAT=132
|
||||
ASM_HEXFLOAT=133
|
||||
ASM_NUMINT=134
|
||||
ASM_BININTEGER=135
|
||||
ASM_DECINTEGER=136
|
||||
ASM_HEXINTEGER=137
|
||||
ASM_CHAR=138
|
||||
ASM_MULTI_REL=139
|
||||
ASM_MULTI_NAME=140
|
||||
ASM_NAME=141
|
||||
ASM_WS=142
|
||||
ASM_COMMENT_LINE=143
|
||||
ASM_COMMENT_BLOCK=144
|
||||
EXTERN=50
|
||||
EXPORT=51
|
||||
ALIGN=52
|
||||
INLINE=53
|
||||
VOLATILE=54
|
||||
INTERRUPT=55
|
||||
REGISTER=56
|
||||
ADDRESS=57
|
||||
ADDRESS_ZEROPAGE=58
|
||||
ADDRESS_MAINMEM=59
|
||||
NOTCONST=60
|
||||
FORM_SSA=61
|
||||
FORM_MA=62
|
||||
CALLING=63
|
||||
CALLINGCONVENTION=64
|
||||
IF=65
|
||||
ELSE=66
|
||||
WHILE=67
|
||||
DO=68
|
||||
FOR=69
|
||||
SWITCH=70
|
||||
RETURN=71
|
||||
BREAK=72
|
||||
CONTINUE=73
|
||||
ASM=74
|
||||
DEFAULT=75
|
||||
CASE=76
|
||||
STRUCT=77
|
||||
ENUM=78
|
||||
SIZEOF=79
|
||||
TYPEID=80
|
||||
KICKASM=81
|
||||
RESOURCE=82
|
||||
USES=83
|
||||
CLOBBERS=84
|
||||
BYTES=85
|
||||
CYCLES=86
|
||||
LOGIC_NOT=87
|
||||
SIGNEDNESS=88
|
||||
SIMPLETYPE=89
|
||||
BOOLEAN=90
|
||||
KICKASM_BODY=91
|
||||
STRING=92
|
||||
CHAR=93
|
||||
NUMBER=94
|
||||
NUMFLOAT=95
|
||||
BINFLOAT=96
|
||||
DECFLOAT=97
|
||||
HEXFLOAT=98
|
||||
NUMINT=99
|
||||
BININTEGER=100
|
||||
DECINTEGER=101
|
||||
HEXINTEGER=102
|
||||
NAME=103
|
||||
WS=104
|
||||
COMMENT_LINE=105
|
||||
COMMENT_BLOCK=106
|
||||
ASM_BYTE=107
|
||||
ASM_MNEMONIC=108
|
||||
ASM_IMM=109
|
||||
ASM_COLON=110
|
||||
ASM_COMMA=111
|
||||
ASM_PAR_BEGIN=112
|
||||
ASM_PAR_END=113
|
||||
ASM_BRACKET_BEGIN=114
|
||||
ASM_BRACKET_END=115
|
||||
ASM_DOT=116
|
||||
ASM_SHIFT_LEFT=117
|
||||
ASM_SHIFT_RIGHT=118
|
||||
ASM_PLUS=119
|
||||
ASM_MINUS=120
|
||||
ASM_LESS_THAN=121
|
||||
ASM_GREATER_THAN=122
|
||||
ASM_MULTIPLY=123
|
||||
ASM_DIVIDE=124
|
||||
ASM_CURLY_BEGIN=125
|
||||
ASM_CURLY_END=126
|
||||
ASM_NUMBER=127
|
||||
ASM_NUMFLOAT=128
|
||||
ASM_BINFLOAT=129
|
||||
ASM_DECFLOAT=130
|
||||
ASM_HEXFLOAT=131
|
||||
ASM_NUMINT=132
|
||||
ASM_BININTEGER=133
|
||||
ASM_DECINTEGER=134
|
||||
ASM_HEXINTEGER=135
|
||||
ASM_CHAR=136
|
||||
ASM_MULTI_REL=137
|
||||
ASM_MULTI_NAME=138
|
||||
ASM_NAME=139
|
||||
ASM_WS=140
|
||||
ASM_COMMENT_LINE=141
|
||||
ASM_COMMENT_BLOCK=142
|
||||
';'=8
|
||||
'..'=11
|
||||
'?'=12
|
||||
@ -172,44 +170,42 @@ ASM_COMMENT_BLOCK=144
|
||||
'data_seg'=47
|
||||
'encoding'=48
|
||||
'const'=49
|
||||
'__notconst'=50
|
||||
'__maybeconst'=51
|
||||
'extern'=52
|
||||
'export'=53
|
||||
'align'=54
|
||||
'register'=55
|
||||
'__address'=56
|
||||
'__zp'=57
|
||||
'__mem'=58
|
||||
'__ssa'=59
|
||||
'__notssa'=60
|
||||
'inline'=61
|
||||
'volatile'=62
|
||||
'__notvolatile'=63
|
||||
'interrupt'=64
|
||||
'calling'=65
|
||||
'if'=67
|
||||
'else'=68
|
||||
'while'=69
|
||||
'do'=70
|
||||
'for'=71
|
||||
'switch'=72
|
||||
'return'=73
|
||||
'break'=74
|
||||
'continue'=75
|
||||
'asm'=76
|
||||
'default'=77
|
||||
'case'=78
|
||||
'struct'=79
|
||||
'enum'=80
|
||||
'sizeof'=81
|
||||
'typeid'=82
|
||||
'kickasm'=83
|
||||
'resource'=84
|
||||
'uses'=85
|
||||
'clobbers'=86
|
||||
'bytes'=87
|
||||
'cycles'=88
|
||||
'!'=89
|
||||
'.byte'=109
|
||||
'#'=111
|
||||
'extern'=50
|
||||
'export'=51
|
||||
'align'=52
|
||||
'inline'=53
|
||||
'volatile'=54
|
||||
'interrupt'=55
|
||||
'register'=56
|
||||
'__address'=57
|
||||
'__zp'=58
|
||||
'__mem'=59
|
||||
'__notconst'=60
|
||||
'__ssa'=61
|
||||
'__ma'=62
|
||||
'calling'=63
|
||||
'if'=65
|
||||
'else'=66
|
||||
'while'=67
|
||||
'do'=68
|
||||
'for'=69
|
||||
'switch'=70
|
||||
'return'=71
|
||||
'break'=72
|
||||
'continue'=73
|
||||
'asm'=74
|
||||
'default'=75
|
||||
'case'=76
|
||||
'struct'=77
|
||||
'enum'=78
|
||||
'sizeof'=79
|
||||
'typeid'=80
|
||||
'kickasm'=81
|
||||
'resource'=82
|
||||
'uses'=83
|
||||
'clobbers'=84
|
||||
'bytes'=85
|
||||
'cycles'=86
|
||||
'!'=87
|
||||
'.byte'=107
|
||||
'#'=109
|
||||
|
@ -337,18 +337,6 @@ public class KickCParserBaseListener implements KickCParserListener {
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitDirectiveNotConst(KickCParser.DirectiveNotConstContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void enterDirectiveMaybeConst(KickCParser.DirectiveMaybeConstContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitDirectiveMaybeConst(KickCParser.DirectiveMaybeConstContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
@ -421,18 +409,6 @@ public class KickCParserBaseListener implements KickCParserListener {
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitDirectiveVolatile(KickCParser.DirectiveVolatileContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void enterDirectiveNotVolatile(KickCParser.DirectiveNotVolatileContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitDirectiveNotVolatile(KickCParser.DirectiveNotVolatileContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
@ -450,13 +426,13 @@ public class KickCParserBaseListener implements KickCParserListener {
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void enterDirectiveFormNotSsa(KickCParser.DirectiveFormNotSsaContext ctx) { }
|
||||
@Override public void enterDirectiveFormMa(KickCParser.DirectiveFormMaContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitDirectiveFormNotSsa(KickCParser.DirectiveFormNotSsaContext ctx) { }
|
||||
@Override public void exitDirectiveFormMa(KickCParser.DirectiveFormMaContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
|
@ -202,13 +202,6 @@ public class KickCParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> imple
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitDirectiveNotConst(KickCParser.DirectiveNotConstContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitDirectiveMaybeConst(KickCParser.DirectiveMaybeConstContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
@ -251,13 +244,6 @@ public class KickCParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> imple
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitDirectiveVolatile(KickCParser.DirectiveVolatileContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitDirectiveNotVolatile(KickCParser.DirectiveNotVolatileContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
@ -271,7 +257,7 @@ public class KickCParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> imple
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitDirectiveFormNotSsa(KickCParser.DirectiveFormNotSsaContext ctx) { return visitChildren(ctx); }
|
||||
@Override public T visitDirectiveFormMa(KickCParser.DirectiveFormMaContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
|
@ -309,18 +309,6 @@ public interface KickCParserListener extends ParseTreeListener {
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitDirectiveNotConst(KickCParser.DirectiveNotConstContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by the {@code directiveMaybeConst}
|
||||
* labeled alternative in {@link KickCParser#directive}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void enterDirectiveMaybeConst(KickCParser.DirectiveMaybeConstContext ctx);
|
||||
/**
|
||||
* Exit a parse tree produced by the {@code directiveMaybeConst}
|
||||
* labeled alternative in {@link KickCParser#directive}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitDirectiveMaybeConst(KickCParser.DirectiveMaybeConstContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by the {@code directiveAlign}
|
||||
* labeled alternative in {@link KickCParser#directive}.
|
||||
@ -393,18 +381,6 @@ public interface KickCParserListener extends ParseTreeListener {
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitDirectiveVolatile(KickCParser.DirectiveVolatileContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by the {@code directiveNotVolatile}
|
||||
* labeled alternative in {@link KickCParser#directive}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void enterDirectiveNotVolatile(KickCParser.DirectiveNotVolatileContext ctx);
|
||||
/**
|
||||
* Exit a parse tree produced by the {@code directiveNotVolatile}
|
||||
* labeled alternative in {@link KickCParser#directive}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitDirectiveNotVolatile(KickCParser.DirectiveNotVolatileContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by the {@code directiveFormSsa}
|
||||
* labeled alternative in {@link KickCParser#directive}.
|
||||
@ -418,17 +394,17 @@ public interface KickCParserListener extends ParseTreeListener {
|
||||
*/
|
||||
void exitDirectiveFormSsa(KickCParser.DirectiveFormSsaContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by the {@code directiveFormNotSsa}
|
||||
* Enter a parse tree produced by the {@code directiveFormMa}
|
||||
* labeled alternative in {@link KickCParser#directive}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void enterDirectiveFormNotSsa(KickCParser.DirectiveFormNotSsaContext ctx);
|
||||
void enterDirectiveFormMa(KickCParser.DirectiveFormMaContext ctx);
|
||||
/**
|
||||
* Exit a parse tree produced by the {@code directiveFormNotSsa}
|
||||
* Exit a parse tree produced by the {@code directiveFormMa}
|
||||
* labeled alternative in {@link KickCParser#directive}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitDirectiveFormNotSsa(KickCParser.DirectiveFormNotSsaContext ctx);
|
||||
void exitDirectiveFormMa(KickCParser.DirectiveFormMaContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by the {@code directiveExtern}
|
||||
* labeled alternative in {@link KickCParser#directive}.
|
||||
|
@ -189,13 +189,6 @@ public interface KickCParserVisitor<T> extends ParseTreeVisitor<T> {
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitDirectiveNotConst(KickCParser.DirectiveNotConstContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code directiveMaybeConst}
|
||||
* labeled alternative in {@link KickCParser#directive}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitDirectiveMaybeConst(KickCParser.DirectiveMaybeConstContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code directiveAlign}
|
||||
* labeled alternative in {@link KickCParser#directive}.
|
||||
@ -238,13 +231,6 @@ public interface KickCParserVisitor<T> extends ParseTreeVisitor<T> {
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitDirectiveVolatile(KickCParser.DirectiveVolatileContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code directiveNotVolatile}
|
||||
* labeled alternative in {@link KickCParser#directive}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitDirectiveNotVolatile(KickCParser.DirectiveNotVolatileContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code directiveFormSsa}
|
||||
* labeled alternative in {@link KickCParser#directive}.
|
||||
@ -253,12 +239,12 @@ public interface KickCParserVisitor<T> extends ParseTreeVisitor<T> {
|
||||
*/
|
||||
T visitDirectiveFormSsa(KickCParser.DirectiveFormSsaContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code directiveFormNotSsa}
|
||||
* Visit a parse tree produced by the {@code directiveFormMa}
|
||||
* labeled alternative in {@link KickCParser#directive}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitDirectiveFormNotSsa(KickCParser.DirectiveFormNotSsaContext ctx);
|
||||
T visitDirectiveFormMa(KickCParser.DirectiveFormMaContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code directiveExtern}
|
||||
* labeled alternative in {@link KickCParser#directive}.
|
||||
|
@ -266,9 +266,9 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
this.visitDeclTypes(ctx.declTypes());
|
||||
SymbolType type = declVarType;
|
||||
List<Directive> directives = declVarDirectives;
|
||||
Variable param = new Variable( ctx.NAME().getText(), getCurrentScope(), type, Variable.StorageStrategy.PHI_MASTER, defaultMemoryArea, currentDataSegment);
|
||||
Variable param = new Variable(ctx.NAME().getText(), getCurrentScope(), type, Variable.Kind.PHI_MASTER, defaultMemoryArea, currentDataSegment);
|
||||
// Add directives
|
||||
addDirectives(param, true, directives, new StatementSource(ctx));
|
||||
directiveContext.applyDirectives(param, true, directives, new StatementSource(ctx));
|
||||
exitDeclTypes();
|
||||
return param;
|
||||
}
|
||||
@ -612,29 +612,24 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
}
|
||||
|
||||
private Variable visitDeclVariableInit(String varName, KickCParser.DeclVariableInitContext ctx) {
|
||||
List<Directive> directives = declVarDirectives;
|
||||
SymbolType type = declVarType;
|
||||
List<Comment> comments = declVarComments;
|
||||
|
||||
Variable lValue;
|
||||
try {
|
||||
lValue = getCurrentScope().addVariablePhiMaster(varName, type, defaultMemoryArea, currentDataSegment);
|
||||
List<Directive> directives = declVarDirectives;
|
||||
SymbolType type = declVarType;
|
||||
List<Comment> comments = declVarComments;
|
||||
// Find kind
|
||||
Variable.Kind kind = directiveContext.getKind(type, getCurrentScope(), false, directives, new StatementSource(ctx));
|
||||
// Create variable
|
||||
Variable lValue = getCurrentScope().addVariable(kind, varName, type, defaultMemoryArea, currentDataSegment);
|
||||
// Add directives
|
||||
directiveContext.applyDirectives(lValue, false, directives, new StatementSource(ctx));
|
||||
if(lValue.isDeclaredConstant()) {
|
||||
// Add comments to constant
|
||||
lValue.setComments(ensureUnusedComments(comments));
|
||||
}
|
||||
return lValue;
|
||||
} catch(CompileError e) {
|
||||
throw new CompileError(e.getMessage(), new StatementSource(ctx));
|
||||
}
|
||||
// Add directives
|
||||
addDirectives(lValue, false, directives, new StatementSource(ctx));
|
||||
// Array / String variables are implicitly constant
|
||||
if(type instanceof SymbolTypeArray || type.equals(SymbolType.STRING)) {
|
||||
lValue.setConstantDeclaration(Variable.ConstantDeclaration.CONST);
|
||||
lValue.setStorageStrategy(Variable.StorageStrategy.CONSTANT);
|
||||
lValue.setMemoryArea(Variable.MemoryArea.MAIN_MEMORY);
|
||||
}
|
||||
if(lValue.isDeclaredConstant()) {
|
||||
// Add comments to constant
|
||||
lValue.setComments(ensureUnusedComments(comments));
|
||||
}
|
||||
return lValue;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -675,17 +670,6 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
return initStmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add declared directives to an lValue (typically a variable).
|
||||
*
|
||||
* @param lValue The lValue
|
||||
* @param isParameter True if the lValue is a parameter
|
||||
* @param directives The directives to add
|
||||
*/
|
||||
private void addDirectives(Variable lValue, boolean isParameter, List<Directive> directives, StatementSource source) {
|
||||
directiveContext.applyDirectives(lValue, isParameter, directives, source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the directives in the parse tree
|
||||
*
|
||||
@ -742,17 +726,12 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
|
||||
@Override
|
||||
public Directive visitDirectiveConst(KickCParser.DirectiveConstContext ctx) {
|
||||
return new Directive.Const(Variable.ConstantDeclaration.CONST);
|
||||
return new Directive.Const();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitDirectiveNotConst(KickCParser.DirectiveNotConstContext ctx) {
|
||||
return new Directive.Const(Variable.ConstantDeclaration.NOT_CONST);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitDirectiveMaybeConst(KickCParser.DirectiveMaybeConstContext ctx) {
|
||||
return new Directive.Const(Variable.ConstantDeclaration.MAYBE_CONST);
|
||||
return new Directive.NotConst();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -791,53 +770,50 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
if(ctx.NAME() != null) {
|
||||
name = ctx.NAME().getText();
|
||||
}
|
||||
return new Directive.Register(true, name);
|
||||
if(name != null)
|
||||
return new Directive.NamedRegister(name);
|
||||
else
|
||||
return new Directive.Register();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitDirectiveMemoryAreaZp(KickCParser.DirectiveMemoryAreaZpContext ctx) {
|
||||
return new Directive.MemoryArea(Variable.MemoryArea.ZEROPAGE_MEMORY, null);
|
||||
public Directive visitDirectiveMemoryAreaZp(KickCParser.DirectiveMemoryAreaZpContext ctx) {
|
||||
return new Directive.MemZp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitDirectiveMemoryAreaMain(KickCParser.DirectiveMemoryAreaMainContext ctx) {
|
||||
return new Directive.MemoryArea(Variable.MemoryArea.MAIN_MEMORY, null);
|
||||
public Directive visitDirectiveMemoryAreaMain(KickCParser.DirectiveMemoryAreaMainContext ctx) {
|
||||
return new Directive.MemMain();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitDirectiveMemoryAreaAddress(KickCParser.DirectiveMemoryAreaAddressContext ctx) {
|
||||
public Directive visitDirectiveMemoryAreaAddress(KickCParser.DirectiveMemoryAreaAddressContext ctx) {
|
||||
try {
|
||||
ConstantInteger memoryAddress = NumberParser.parseIntegerLiteral(ctx.NUMBER().getText());
|
||||
Long address = memoryAddress.getInteger();
|
||||
Variable.MemoryArea memoryArea = (address < 0x100) ? Variable.MemoryArea.ZEROPAGE_MEMORY : Variable.MemoryArea.MAIN_MEMORY;
|
||||
return new Directive.MemoryArea(memoryArea, address);
|
||||
return new Directive.Address(address);
|
||||
} catch(NumberFormatException e) {
|
||||
throw new CompileError(e.getMessage(), new StatementSource(ctx));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitDirectiveFormSsa(KickCParser.DirectiveFormSsaContext ctx) {
|
||||
return new Directive.FormSsa(true);
|
||||
public Directive visitDirectiveFormSsa(KickCParser.DirectiveFormSsaContext ctx) {
|
||||
return new Directive.FormSsa();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitDirectiveFormNotSsa(KickCParser.DirectiveFormNotSsaContext ctx) {
|
||||
return new Directive.FormSsa(false);
|
||||
public Directive visitDirectiveFormMa(KickCParser.DirectiveFormMaContext ctx) {
|
||||
return new Directive.FormMa();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Directive visitDirectiveVolatile(KickCParser.DirectiveVolatileContext ctx) {
|
||||
return new Directive.Volatile(true);
|
||||
return new Directive.Volatile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitDirectiveNotVolatile(KickCParser.DirectiveNotVolatileContext ctx) {
|
||||
return new Directive.Volatile(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitDirectiveExport(KickCParser.DirectiveExportContext ctx) {
|
||||
public Directive visitDirectiveExport(KickCParser.DirectiveExportContext ctx) {
|
||||
return new Directive.Export();
|
||||
}
|
||||
|
||||
@ -1192,7 +1168,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
throw new CompileError(e.getMessage(), statementSource);
|
||||
}
|
||||
// Add directives
|
||||
addDirectives(lValue, false, varDirectives, statementSource);
|
||||
directiveContext.applyDirectives(lValue, false, varDirectives, statementSource);
|
||||
} else {
|
||||
lValue = getCurrentScope().getVariable(varName);
|
||||
if(lValue == null) {
|
||||
|
@ -30,7 +30,7 @@ public class Pass1AddressOfVolatile extends Pass2SsaOptimization {
|
||||
if(rValue instanceof SymbolVariableRef) {
|
||||
Symbol toSymbol = getScope().getSymbol((SymbolVariableRef) rValue);
|
||||
if(toSymbol instanceof Variable) {
|
||||
((Variable) toSymbol).setInferedVolatile(true);
|
||||
((Variable) toSymbol).setInferredVolatile(true);
|
||||
getLog().append("Setting inferred volatile on symbol affected by address-of "+statement.toString(getProgram(), false));
|
||||
}
|
||||
}
|
||||
|
@ -41,11 +41,11 @@ public class Pass1EarlyConstantIdentification extends Pass1Base {
|
||||
if(assign.getrValue1() == null && assign.getOperator() == null && assign.getrValue2() instanceof ConstantValue) {
|
||||
getLog().append("Identified constant variable " + variable.toString(getProgram()));
|
||||
earlyConstants.add(variableRef);
|
||||
variable.setStorageStrategy(Variable.StorageStrategy.CONSTANT);
|
||||
variable.setKind(Variable.Kind.CONSTANT);
|
||||
} else if(assign.getrValue1() == null && assign.getOperator() instanceof OperatorCastPtr && assign.getrValue2() instanceof ConstantValue) {
|
||||
getLog().append("Identified constant variable " + variable.toString(getProgram()));
|
||||
earlyConstants.add(variableRef);
|
||||
variable.setStorageStrategy(Variable.StorageStrategy.CONSTANT);
|
||||
variable.setKind(Variable.Kind.CONSTANT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
|
||||
private void versionAssignment(VariableRef lValueRef, ProgramValue programLValue, StatementSource source) {
|
||||
Collection<SymbolVariableRef> earlyIdentifiedConstants = getProgram().getEarlyIdentifiedConstants();
|
||||
Variable assignedVar = getScope().getVariable(lValueRef);
|
||||
if(assignedVar.isStoragePhiMaster()) {
|
||||
if(assignedVar.isKindPhiMaster()) {
|
||||
if(assignedVar.isDeclaredConstant() || earlyIdentifiedConstants.contains(assignedVar.getRef()))
|
||||
throw new InternalError("Error! Constants can not be versioned ", source);
|
||||
Variable version = assignedVar.createVersion();
|
||||
@ -145,9 +145,8 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
|
||||
}
|
||||
|
||||
private void updateBlockVersions(VariableRef lValue, Map<Variable, Variable> blockVersions) {
|
||||
VariableRef lValueRef = lValue;
|
||||
Variable variable = Pass1GenerateSingleStaticAssignmentForm.this.getScope().getVariable(lValueRef);
|
||||
if(variable.isStoragePhiVersion()) {
|
||||
Variable variable = Pass1GenerateSingleStaticAssignmentForm.this.getScope().getVariable(lValue);
|
||||
if(variable.isKindPhiVersion()) {
|
||||
blockVersions.put(variable.getVersionOf(), variable);
|
||||
}
|
||||
}
|
||||
@ -169,7 +168,7 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
|
||||
Variable version = null;
|
||||
if(rValue instanceof VariableRef) {
|
||||
Variable rValueVar = getScope().getVariable((VariableRef) rValue);
|
||||
if(rValueVar.isStoragePhiMaster()) {
|
||||
if(rValueVar.isKindPhiMaster()) {
|
||||
// rValue needs versioning - look for version in statements
|
||||
Variable rSymbol = rValueVar;
|
||||
if(rSymbol.isDeclaredConstant() || earlyIdentifiedConstants.contains(rSymbol.getRef())) {
|
||||
@ -311,7 +310,7 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
|
||||
private void addSymbolToMap(LValue lValue, ControlFlowBlock block, Map<LabelRef, Map<Variable, Variable>> symbolMap) {
|
||||
if(lValue instanceof VariableRef) {
|
||||
Variable lValueVar = getScope().getVariable((VariableRef) lValue);
|
||||
if(lValueVar.isStoragePhiVersion()) {
|
||||
if(lValueVar.isKindPhiVersion()) {
|
||||
Variable versioned = lValueVar;
|
||||
LabelRef label = block.getLabel();
|
||||
Variable unversioned = versioned.getVersionOf();
|
||||
|
@ -115,7 +115,7 @@ public class Pass1ProcedureCallParameters extends ControlFlowGraphCopyVisitor {
|
||||
// Add self-assignments for all variables modified in the procedure
|
||||
Set<VariableRef> modifiedVars = program.getProcedureModifiedVars().getModifiedVars(procedure.getRef());
|
||||
for(VariableRef modifiedVar : modifiedVars) {
|
||||
if(getScope().getVariable(modifiedVar).isStorageLoadStore())
|
||||
if(getScope().getVariable(modifiedVar).isKindLoadStore())
|
||||
continue;
|
||||
addStatementToCurrentBlock(new StatementAssignment(modifiedVar, modifiedVar, origCall.getSource(), Comment.NO_COMMENTS));
|
||||
}
|
||||
@ -134,7 +134,7 @@ public class Pass1ProcedureCallParameters extends ControlFlowGraphCopyVisitor {
|
||||
// Add self-assignments for all variables modified in the procedure
|
||||
Set<VariableRef> modifiedVars = program.getProcedureModifiedVars().getModifiedVars(procedure.getRef());
|
||||
for(VariableRef modifiedVar : modifiedVars) {
|
||||
if(getScope().getVariable(modifiedVar).isStorageLoadStore())
|
||||
if(getScope().getVariable(modifiedVar).isKindLoadStore())
|
||||
continue;
|
||||
addStatementToCurrentBlock(new StatementAssignment(modifiedVar, modifiedVar, orig.getSource(), Comment.NO_COMMENTS));
|
||||
}
|
||||
|
@ -307,10 +307,10 @@ public class Pass1ProcedureInline extends Pass1Base {
|
||||
inlineVar.setDeclaredAsRegister(procVar.isDeclaredAsRegister());
|
||||
inlineVar.setDeclaredNotRegister(procVar.isDeclaredAsNotRegister());
|
||||
inlineVar.setDeclaredRegister(procVar.getDeclaredRegister());
|
||||
inlineVar.setStorageStrategy(procVar.getStorageStrategy());
|
||||
inlineVar.setKind(procVar.getKind());
|
||||
inlineVar.setMemoryArea(procVar.getMemoryArea());
|
||||
inlineVar.setDeclaredVolatile(procVar.isDeclaredVolatile());
|
||||
inlineVar.setInferedVolatile(procVar.isInferedVolatile());
|
||||
inlineVar.setInferredVolatile(procVar.isInferredVolatile());
|
||||
inlineVar.setDeclaredExport(procVar.isDeclaredExport());
|
||||
} else if(procSymbol instanceof Label) {
|
||||
String inlineLabelName = getInlineSymbolName(procedure, procSymbol, serial);
|
||||
|
@ -73,22 +73,22 @@ public class Pass1UnwindBlockScopes extends Pass1Base {
|
||||
}
|
||||
} else if(symbol instanceof Variable) {
|
||||
Variable variable = (Variable) symbol;
|
||||
if(variable.isStoragePhiMaster() || variable.isStorageConstant()) {
|
||||
if(variable.isKindPhiMaster() || variable.isKindConstant()) {
|
||||
String name = findLocalName(procedure, symbol);
|
||||
Variable var = (Variable) symbol;
|
||||
Variable unwound = procedure.addVariablePhiMaster(name, symbol.getType(), var.getMemoryArea(), var.getDataSegment());
|
||||
unwound.setDeclaredAlignment(var.getDeclaredAlignment());
|
||||
unwound.setConstantDeclaration(var.getConstantDeclaration());
|
||||
unwound.setDeclaredVolatile(var.isDeclaredVolatile());
|
||||
unwound.setInferedVolatile(var.isInferedVolatile());
|
||||
unwound.setInferredVolatile(var.isInferredVolatile());
|
||||
unwound.setDeclaredRegister((var.getDeclaredRegister()));
|
||||
unwound.setDeclaredExport(var.isDeclaredExport());
|
||||
unwoundSymbols.put(symbol.getRef(), unwound.getRef());
|
||||
unwound.setStorageStrategy(var.getStorageStrategy());
|
||||
unwound.setKind(var.getKind());
|
||||
unwound.setMemoryArea(var.getMemoryArea());
|
||||
} else if(variable.isStorageIntermediate()) {
|
||||
} else if(variable.isKindIntermediate()) {
|
||||
Variable unwound = procedure.addVariableIntermediate();
|
||||
unwound.setStorageStrategy(variable.getStorageStrategy());
|
||||
unwound.setKind(variable.getKind());
|
||||
unwound.setMemoryArea(variable.getMemoryArea());
|
||||
unwoundSymbols.put(symbol.getRef(), unwound.getRef());
|
||||
} else {
|
||||
|
@ -212,7 +212,7 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
||||
for(Variable member : structDefinition.getAllVariables(false)) {
|
||||
Variable memberVariable;
|
||||
if(variable.getRef().isIntermediate()) {
|
||||
memberVariable = scope.add(new Variable( variable.getLocalName() + "_" + member.getLocalName(), scope, member.getType(), Variable.StorageStrategy.INTERMEDIATE, variable.getMemoryArea(), variable.getDataSegment()));
|
||||
memberVariable = scope.add(new Variable( variable.getLocalName() + "_" + member.getLocalName(), scope, member.getType(), Variable.Kind.INTERMEDIATE, variable.getMemoryArea(), variable.getDataSegment()));
|
||||
} else {
|
||||
if(member.getType() instanceof SymbolTypePointer) {
|
||||
// Always put pointers in ZP memory area
|
||||
@ -222,10 +222,10 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
||||
}
|
||||
}
|
||||
memberVariable.setDeclaredVolatile(variable.isDeclaredVolatile());
|
||||
memberVariable.setInferedVolatile(variable.isInferedVolatile());
|
||||
memberVariable.setInferredVolatile(variable.isInferredVolatile());
|
||||
memberVariable.setConstantDeclaration(variable.getConstantDeclaration());
|
||||
memberVariable.setDeclaredExport(variable.isDeclaredExport());
|
||||
memberVariable.setStorageStrategy(variable.getStorageStrategy());
|
||||
memberVariable.setKind(variable.getKind());
|
||||
if(memberVariable.getType() instanceof SymbolTypePointer) {
|
||||
memberVariable.setMemoryArea(Variable.MemoryArea.ZEROPAGE_MEMORY);
|
||||
} else {
|
||||
|
@ -93,7 +93,7 @@ public class Pass2AliasElimination extends Pass2SsaOptimization {
|
||||
String unversionedFullName = null;
|
||||
for(VariableRef variableRef : aliasSet.getVars()) {
|
||||
Variable variable = programScope.getVariable(variableRef);
|
||||
if(variable.isVolatile() || variable.isStorageLoadStore()) {
|
||||
if(variable.isVolatile() || variable.isKindLoadStore()) {
|
||||
anyVolatile = true;
|
||||
}
|
||||
if(unversionedFullName == null) {
|
||||
@ -420,7 +420,7 @@ public class Pass2AliasElimination extends Pass2SsaOptimization {
|
||||
String name;
|
||||
int score;
|
||||
Variable variable = scope.getVariable(var);
|
||||
if(variable.isDeclaredConstant() || variable.isStorageConstant()) {
|
||||
if(variable.isDeclaredConstant() || variable.isKindConstant()) {
|
||||
name = var.getFullNameUnversioned();
|
||||
score = 100;
|
||||
} else if(var.isVersion()) {
|
||||
|
@ -28,9 +28,8 @@ public class Pass2AssertRValues extends Pass2SsaAssertion {
|
||||
return;
|
||||
}
|
||||
if(rValue instanceof VariableRef) {
|
||||
VariableRef variableRef = (VariableRef) rValue;
|
||||
Variable variable = getScope().getVariable(variableRef);
|
||||
if(variable.isStoragePhiMaster()) {
|
||||
Variable variable = getScope().getVariable((VariableRef) rValue);
|
||||
if(variable.isKindPhiMaster()) {
|
||||
throw new CompileError("No unversioned variable references allowed "+currentStmt.toString(getProgram(), false), currentStmt.getSource());
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ public class Pass2AssertSingleAssignment extends Pass2SsaAssertion {
|
||||
}
|
||||
|
||||
private void checkAssignment(Map<VariableRef, Statement> assignments, VariableRef lValue, Statement statement) {
|
||||
if(getScope().getVariable(lValue).isStorageLoadStore())
|
||||
if(getScope().getVariable(lValue).isKindLoadStore())
|
||||
return;
|
||||
if(assignments.get(lValue) != null) {
|
||||
throw new AssertionFailed("Multiple assignments to variable " + lValue + " 1: " + assignments.get(lValue) + " 2:" + statement);
|
||||
|
@ -43,9 +43,9 @@ public class Pass2AssertSymbols extends Pass2SsaAssertion {
|
||||
Collection<Symbol> tableSymbols = getScope().getAllSymbols(true);
|
||||
|
||||
for(Symbol tableSymbol : tableSymbols) {
|
||||
if(tableSymbol instanceof Variable && ((Variable) tableSymbol).isStoragePhiMaster()) continue;
|
||||
if(tableSymbol instanceof Variable && ((Variable) tableSymbol).isStorageConstant()) continue;
|
||||
if(tableSymbol instanceof Variable && ((Variable) tableSymbol).isStorageLoadStore()) continue;
|
||||
if(tableSymbol instanceof Variable && ((Variable) tableSymbol).isKindPhiMaster()) continue;
|
||||
if(tableSymbol instanceof Variable && ((Variable) tableSymbol).isKindConstant()) continue;
|
||||
if(tableSymbol instanceof Variable && ((Variable) tableSymbol).isKindLoadStore()) continue;
|
||||
if(tableSymbol instanceof Variable && (((Variable) tableSymbol).isConstant()) ) continue;
|
||||
if(tableSymbol instanceof StructDefinition) continue;
|
||||
if(tableSymbol instanceof EnumDefinition) continue;
|
||||
|
@ -152,7 +152,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
||||
if(lValue instanceof VariableRef) {
|
||||
VariableRef varRef = (VariableRef) lValue;
|
||||
Variable var = getScope().getVariable(varRef);
|
||||
if(var.isVolatile() || var.isDeclaredNotConstant() || var.isStorageLoadStore())
|
||||
if(var.isVolatile() || var.isDeclaredNotConstant() || var.isKindLoadStore())
|
||||
// Do not examine volatiles and non-versioned variables
|
||||
continue;
|
||||
ConstantValue constant = getConstant(assignment.getrValue2());
|
||||
@ -168,7 +168,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
||||
if(getConstant(phiRValue.getrValue()) != null) {
|
||||
VariableRef varRef = phiVariable.getVariable();
|
||||
Variable var = getScope().getVariable(varRef);
|
||||
if(var.isVolatile() || var.isDeclaredNotConstant() || var.isStorageLoadStore())
|
||||
if(var.isVolatile() || var.isDeclaredNotConstant() || var.isKindLoadStore())
|
||||
// Do not examine volatiles and non-versioned variables
|
||||
continue;
|
||||
ConstantValue constant = getConstant(phiRValue.getrValue());
|
||||
@ -182,7 +182,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
||||
|
||||
// Look for constants among non-versioned variables
|
||||
for(Variable variable : getScope().getAllVariables(true)) {
|
||||
if(variable.isVolatile() || variable.isDeclaredNotConstant() || !variable.isStorageLoadStore())
|
||||
if(variable.isVolatile() || variable.isDeclaredNotConstant() || !variable.isKindLoadStore())
|
||||
// Do not examine volatiles, non-constants or versioned variables
|
||||
continue;
|
||||
List<StatementLValue> assignments = getGraph().getAssignments(variable.getRef());
|
||||
|
@ -498,13 +498,13 @@ public class Pass4CodeGeneration {
|
||||
for(Variable variable : scopeVariables) {
|
||||
if(variable.isMemoryAreaMain()) {
|
||||
// Skip PHI masters
|
||||
if(variable.isStoragePhiMaster())
|
||||
if(variable.isKindPhiMaster())
|
||||
continue;
|
||||
// Skip if already added
|
||||
if(added.contains(variable.getAsmName())) {
|
||||
continue;
|
||||
}
|
||||
if(variable.isStorageLoadStore() || variable.isStoragePhiVersion() || variable.isStorageIntermediate()) {
|
||||
if(variable.isKindLoadStore() || variable.isKindPhiVersion() || variable.isKindIntermediate()) {
|
||||
Registers.Register allocation = variable.getAllocation();
|
||||
if(allocation instanceof Registers.RegisterCpuByte)
|
||||
continue;
|
||||
|
@ -33,10 +33,10 @@ public class Pass4LiveRangeEquivalenceClassesFinalize extends Pass2Base {
|
||||
|
||||
// Add all versions of volatile variables to the same equivalence class
|
||||
for(Variable variable : getSymbols().getAllVariables(true)) {
|
||||
if(variable.isStoragePhiVersion() && variable.isVolatile()) {
|
||||
if(variable.isKindPhiVersion() && variable.isVolatile()) {
|
||||
// Found a volatile non-versioned variable
|
||||
for(Variable otherVariable : variable.getScope().getAllVariables(false)) {
|
||||
if(otherVariable.isStoragePhiVersion()) {
|
||||
if(otherVariable.isKindPhiVersion()) {
|
||||
if((otherVariable).getVersionOf().equals((variable).getVersionOf())) {
|
||||
// They share the same main variable
|
||||
LiveRangeEquivalenceClass varEC = liveRangeEquivalenceClassSet.getOrCreateEquivalenceClass((VariableRef) variable.getRef());
|
||||
|
@ -78,7 +78,7 @@ public class Pass4RegisterUpliftPotentialInitialize extends Pass2Base {
|
||||
private boolean varVolatile(LiveRangeEquivalenceClass equivalenceClass) {
|
||||
for(VariableRef variableRef : equivalenceClass.getVariables()) {
|
||||
Variable variable = getSymbols().getVariable(variableRef);
|
||||
if(variable.isVolatile() || variable.isStorageLoadStore()) {
|
||||
if(variable.isVolatile() || variable.isKindLoadStore()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ public class PassNAssertConstantModification extends Pass2SsaOptimization {
|
||||
if(lValue instanceof VariableRef) {
|
||||
VariableRef variableRef = (VariableRef) lValue;
|
||||
Variable variable = getScope().getVariable(variableRef);
|
||||
if(variable.isStorageConstant() || earlyIdentifiedConstants.contains(variableRef)) {
|
||||
if(variable.isKindConstant() || earlyIdentifiedConstants.contains(variableRef)) {
|
||||
if(assigned.contains(variableRef)) {
|
||||
throw new CompileError("Error! Constants can not be modified", statement.getSource());
|
||||
} else {
|
||||
|
@ -135,11 +135,11 @@ public class PassNTypeInference extends Pass2SsaOptimization {
|
||||
// If the type is an array or a string the symbol is constant
|
||||
if(symbol.getType() instanceof SymbolTypeArray) {
|
||||
symbol.setConstantDeclaration(Variable.ConstantDeclaration.CONST);
|
||||
symbol.setStorageStrategy(Variable.StorageStrategy.CONSTANT);
|
||||
symbol.setKind(Variable.Kind.CONSTANT);
|
||||
symbol.setMemoryArea(Variable.MemoryArea.MAIN_MEMORY);
|
||||
} else if(SymbolType.STRING.equals(symbol.getType())) {
|
||||
symbol.setConstantDeclaration(Variable.ConstantDeclaration.CONST);
|
||||
symbol.setStorageStrategy(Variable.StorageStrategy.CONSTANT);
|
||||
symbol.setKind(Variable.Kind.CONSTANT);
|
||||
symbol.setMemoryArea(Variable.MemoryArea.MAIN_MEMORY);
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ public class PassNCalcVariableReferenceInfos extends PassNCalcBase<VariableRefer
|
||||
blockSuccessors.put(blockLabel, successorClosure);
|
||||
}
|
||||
// Gather symbols in the symbol table referencing other variables/constants
|
||||
Collection<Variable> allVariables = getProgram().getScope().getAllSymbolVariables(true);
|
||||
Collection<Variable> allVariables = getProgram().getScope().getAllVars(true);
|
||||
for(Variable referencingVar : allVariables) {
|
||||
ProgramValueIterator.execute(referencingVar,
|
||||
(programValue, currentStmt, stmtIt, currentBlock) -> {
|
||||
|
@ -234,10 +234,10 @@ public class Unroller {
|
||||
newVar.setDeclaredAsRegister(definedVar.isDeclaredAsRegister());
|
||||
newVar.setDeclaredRegister(definedVar.getDeclaredRegister());
|
||||
newVar.setDeclaredNotRegister(definedVar.isDeclaredAsNotRegister());
|
||||
newVar.setStorageStrategy(definedVar.getStorageStrategy());
|
||||
newVar.setKind(definedVar.getKind());
|
||||
newVar.setMemoryArea(definedVar.getMemoryArea());
|
||||
newVar.setDeclaredVolatile(definedVar.isDeclaredVolatile());
|
||||
newVar.setInferedVolatile(definedVar.isInferedVolatile());
|
||||
newVar.setInferredVolatile(definedVar.isInferredVolatile());
|
||||
newVar.setDeclaredExport(definedVar.isDeclaredExport());
|
||||
newVar.setDeclaredAlignment(definedVar.getDeclaredAlignment());
|
||||
newVar.setInferredType(definedVar.isInferredType());
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Test declaring a variable as "__mem __notssa", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
|
||||
|
||||
__mem __notssa char idx;
|
||||
__mem __ma char idx;
|
||||
|
||||
const char* SCREEN = 0x0400;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
|
||||
// Test a pointer to a memory variable
|
||||
|
||||
__mem __notssa char idx;
|
||||
__mem __ma char idx;
|
||||
char* idx_p = &idx;
|
||||
|
||||
const char* SCREEN = 0x0400;
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
const char* SCREEN = 0x0400;
|
||||
|
||||
__mem __notssa char* cursor = SCREEN;
|
||||
__mem __ma char* cursor = SCREEN;
|
||||
|
||||
void main() {
|
||||
for( char i: 0..24 ) {
|
||||
|
@ -6,7 +6,7 @@ struct foo {
|
||||
char thing2;
|
||||
};
|
||||
|
||||
__mem __notssa struct foo bar = { 'a', 'b' };
|
||||
__mem __ma struct foo bar = { 'a', 'b' };
|
||||
|
||||
void main(void) {
|
||||
struct foo* barp = &bar;
|
||||
|
@ -7,7 +7,7 @@ struct foo {
|
||||
char[12] thing3;
|
||||
};
|
||||
|
||||
__mem __notssa struct foo bar = { 'a', 'b', "qwe" };
|
||||
__mem __ma struct foo bar = { 'a', 'b', "qwe" };
|
||||
|
||||
void main(void) {
|
||||
struct foo* barp = &bar;
|
||||
|
@ -6,7 +6,7 @@ struct foo {
|
||||
char thing2;
|
||||
};
|
||||
|
||||
__mem __notssa __notconst struct foo bar = { 'a', 'b' };
|
||||
__mem __ma __notconst struct foo bar = { 'a', 'b' };
|
||||
|
||||
void main(void) {
|
||||
const char* SCREEN = 0x0400;
|
||||
|
@ -9,14 +9,14 @@ void main(void) {
|
||||
char __ssa __address(0x10) reg_zp_abs = '.';
|
||||
char __ssa __mem reg_mem_flex = '.';
|
||||
char __ssa __address(0x1000) reg_mem_abs = '.';
|
||||
char __notssa __notconst __zp notreg_zp_flex = '.';
|
||||
char __notssa __notconst __address(0x10) notreg_zp_abs = '.';
|
||||
char __notssa __notconst __mem notreg_mem_flex = '.';
|
||||
char __notssa __notconst __address(0x1000) notreg_mem_abs = '.';
|
||||
char __ma __notconst __zp notreg_zp_flex = '.';
|
||||
char __ma __notconst __address(0x10) notreg_zp_abs = '.';
|
||||
char __ma __notconst __mem notreg_mem_flex = '.';
|
||||
char __ma __notconst __address(0x1000) notreg_mem_abs = '.';
|
||||
|
||||
char default_default = '.';
|
||||
char reg_default = '.';
|
||||
char __notssa __notconst notreg_default = '.';
|
||||
char __ma __notconst notreg_default = '.';
|
||||
char __ssa __zp default_zp_flex = '.';
|
||||
char __address(0x10) default_zp_abs = '.';
|
||||
char __mem default_mem_flex = '.';
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
|
||||
// Test a zeropage notregister variable
|
||||
|
||||
__notssa char idx;
|
||||
__ma char idx;
|
||||
|
||||
const char* SCREEN = 0x0400;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Test declaring a variable as "memory", meaning it will be stored in main memory
|
||||
// Test a fixed main memory address __notssa variable
|
||||
|
||||
__notssa __address(0x1000) char idx;
|
||||
__ma __address(0x1000) char idx;
|
||||
|
||||
const char* SCREEN = 0x0400;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Tests declaring variables as __ssa / __notssa
|
||||
|
||||
char __ssa idx_ssa_g;
|
||||
char __notssa idx_nssa_g;
|
||||
char __ma idx_nssa_g;
|
||||
|
||||
const char* SCREEN1 = 0x0400;
|
||||
const char* SCREEN2 = 0x0400+40;
|
||||
@ -10,7 +10,7 @@ const char* SCREEN4 = 0x0400+120;
|
||||
|
||||
void main() {
|
||||
char __ssa idx_ssa_l;
|
||||
char __notssa idx_nssa_l;
|
||||
char __ma idx_nssa_l;
|
||||
|
||||
SCREEN1[idx_ssa_g++] = 'C';
|
||||
for( char i: 'M'..'L')
|
||||
|
Loading…
x
Reference in New Issue
Block a user