mirror of
https://github.com/irmen/prog8.git
synced 2024-11-25 19:31:36 +00:00
moved initialvalues to asmgen, fixed sgn bug and internal float 0.0 variable disappearing bug
This commit is contained in:
parent
3a99115070
commit
f0d4c3aba9
@ -10,8 +10,8 @@
|
||||
c64flt {
|
||||
; ---- this block contains C-64 floating point related functions ----
|
||||
|
||||
const float PI = 3.141592653589793
|
||||
const float TWOPI = 6.283185307179586
|
||||
const float PI = 3.141592653589793
|
||||
const float TWOPI = 6.283185307179586
|
||||
|
||||
|
||||
; ---- C64 basic and kernal ROM float constants and functions ----
|
||||
@ -34,7 +34,8 @@ c64flt {
|
||||
&float FL_PIHALF = $e2e0 ; PI / 2
|
||||
&float FL_TWOPI = $e2e5 ; 2 * PI
|
||||
&float FL_FR4 = $e2ea ; .25
|
||||
float FL_ZERO = 0.0 ; oddly enough 0.0 isn't available in the kernel
|
||||
; oddly enough, 0.0 isn't available in the kernel.
|
||||
float FL_ZERO = 0.0 ; oddly enough 0.0 isn't available in the kernel
|
||||
|
||||
|
||||
; note: fac1/2 might get clobbered even if not mentioned in the function's name.
|
||||
@ -209,8 +210,8 @@ sub print_fln (float value) {
|
||||
; ---- prints the floating point value (with a newline at the end) using basic rom routines
|
||||
%asm {{
|
||||
stx c64.SCRATCH_ZPREGX
|
||||
lda #<print_fln_value
|
||||
ldy #>print_fln_value
|
||||
lda #<value
|
||||
ldy #>value
|
||||
jsr MOVFM ; load float into fac1
|
||||
jsr FPRINTLN ; print fac1 with newline
|
||||
ldx c64.SCRATCH_ZPREGX
|
||||
|
@ -308,7 +308,7 @@ class GlobalNamespace(val modules: List<Module>): Node, INameScope {
|
||||
return when (val stmt = localContext.definingModule().lookup(scopedName, localContext)) {
|
||||
is Label, is VarDecl, is Block, is Subroutine -> stmt
|
||||
null -> null
|
||||
else -> throw SyntaxError("wrong identifier target: $stmt", stmt.position)
|
||||
else -> throw SyntaxError("wrong identifier target for $scopedName: $stmt", stmt.position)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,11 @@ package prog8.ast.base
|
||||
import prog8.ast.Module
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.processing.*
|
||||
import prog8.ast.statements.Block
|
||||
import prog8.ast.statements.VarDecl
|
||||
import prog8.compiler.CompilationOptions
|
||||
import prog8.compiler.target.AsmInitialValuesGatherer
|
||||
import prog8.compiler.target.AsmVariablePreparer
|
||||
import prog8.optimizer.FlattenAnonymousScopesAndNopRemover
|
||||
|
||||
|
||||
@ -12,12 +16,18 @@ internal fun Program.checkValid(compilerOptions: CompilationOptions, errors: Err
|
||||
checker.visit(this)
|
||||
}
|
||||
|
||||
internal fun Program.moveAnonScopeVarsToSubroutine(errors: ErrorReporter) {
|
||||
val mover = AnonScopeVarsToSubroutineMover(errors)
|
||||
internal fun Program.prepareAsmVariables(errors: ErrorReporter) {
|
||||
val mover = AsmVariablePreparer(this, errors)
|
||||
mover.visit(this)
|
||||
mover.applyModifications()
|
||||
}
|
||||
|
||||
internal fun Program.gatherInitialValues(): Map<Block, Map<String, VarDecl>> {
|
||||
val gather = AsmInitialValuesGatherer(this)
|
||||
gather.visit(this)
|
||||
return gather.initialValues
|
||||
}
|
||||
|
||||
internal fun Program.reorderStatements() {
|
||||
val initvalueCreator = AddressOfInserter(this)
|
||||
initvalueCreator.visit(this)
|
||||
|
@ -16,20 +16,6 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke
|
||||
* (this includes function call arguments)
|
||||
*/
|
||||
|
||||
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
|
||||
|
||||
// collect all variables that have an initialisation value
|
||||
val declValue = decl.value
|
||||
if(declValue!=null
|
||||
&& decl.type== VarDeclType.VAR
|
||||
&& decl.datatype in NumericDatatypes
|
||||
&& declValue.constValue(program)!=null) {
|
||||
decl.definingBlock().initialValues[decl.scopedname] = decl
|
||||
}
|
||||
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> {
|
||||
val leftDt = expr.left.inferType(program)
|
||||
val rightDt = expr.right.inferType(program)
|
||||
|
@ -73,7 +73,6 @@ class Block(override val name: String,
|
||||
val idx = statements.indexOf(node)
|
||||
statements[idx] = replacement
|
||||
}
|
||||
val initialValues = mutableMapOf<String, VarDecl>() // will be gathered by one of the Ast processing steps
|
||||
|
||||
override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this)
|
||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||
@ -271,8 +270,6 @@ class VarDecl(val type: VarDeclType,
|
||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
||||
|
||||
val scopedname: String by lazy { makeScopedName(name) }
|
||||
|
||||
override fun toString(): String {
|
||||
return "VarDecl(name=$name, vartype=$type, datatype=$datatype, struct=$structName, value=$value, pos=$position)"
|
||||
}
|
||||
|
@ -116,11 +116,17 @@ fun compileProgram(filepath: Path,
|
||||
// printAst(programAst)
|
||||
|
||||
if(writeAssembly) {
|
||||
// asm generation directly from the Ast, no need for intermediate code
|
||||
// asm generation directly from the Ast,
|
||||
val zeropage = CompilationTarget.machine.getZeropage(compilerOptions)
|
||||
programAst.moveAnonScopeVarsToSubroutine(errors)
|
||||
programAst.prepareAsmVariables(errors)
|
||||
errors.handle()
|
||||
val assembly = CompilationTarget.asmGenerator(programAst, zeropage, compilerOptions, outputDir).compileToAssembly(optimize)
|
||||
val initialValues = programAst.gatherInitialValues()
|
||||
val assembly = CompilationTarget.asmGenerator(
|
||||
programAst,
|
||||
zeropage,
|
||||
initialValues,
|
||||
compilerOptions,
|
||||
outputDir).compileToAssembly(optimize)
|
||||
assembly.assemble(compilerOptions)
|
||||
programName = assembly.name
|
||||
}
|
||||
|
@ -0,0 +1,31 @@
|
||||
package prog8.compiler.target
|
||||
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.NumericDatatypes
|
||||
import prog8.ast.base.VarDeclType
|
||||
import prog8.ast.processing.IAstVisitor
|
||||
import prog8.ast.statements.Block
|
||||
import prog8.ast.statements.VarDecl
|
||||
|
||||
internal class AsmInitialValuesGatherer(val program: Program): IAstVisitor {
|
||||
val initialValues = mutableMapOf<Block, MutableMap<String, VarDecl>>()
|
||||
|
||||
override fun visit(decl: VarDecl) {
|
||||
// collect all variables that have an initialisation value
|
||||
super.visit(decl)
|
||||
val declValue = decl.value
|
||||
if(declValue!=null
|
||||
&& decl.type== VarDeclType.VAR
|
||||
&& decl.datatype in NumericDatatypes
|
||||
&& declValue.constValue(program)!=null) {
|
||||
|
||||
val block = decl.definingBlock()
|
||||
var blockInits = initialValues[block]
|
||||
if(blockInits==null) {
|
||||
blockInits = mutableMapOf()
|
||||
initialValues[block] = blockInits
|
||||
}
|
||||
blockInits[decl.makeScopedName(decl.name)] = decl
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +1,17 @@
|
||||
package prog8.ast.processing
|
||||
package prog8.compiler.target
|
||||
|
||||
import prog8.ast.Node
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.ErrorReporter
|
||||
import prog8.ast.processing.AstWalker
|
||||
import prog8.ast.processing.IAstModification
|
||||
import prog8.ast.statements.AnonymousScope
|
||||
import prog8.ast.statements.Subroutine
|
||||
import prog8.ast.statements.VarDecl
|
||||
|
||||
|
||||
class AnonScopeVarsToSubroutineMover(val errors: ErrorReporter): AstWalker() {
|
||||
class AsmVariablePreparer(val program: Program, val errors: ErrorReporter): AstWalker() {
|
||||
|
||||
override fun after(scope: AnonymousScope, parent: Node): Iterable<IAstModification> {
|
||||
val decls = scope.statements.filterIsInstance<VarDecl>()
|
||||
val sub = scope.definingSubroutine()
|
@ -1,16 +1,22 @@
|
||||
package prog8.compiler.target
|
||||
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.statements.Block
|
||||
import prog8.ast.statements.VarDecl
|
||||
import prog8.compiler.CompilationOptions
|
||||
import prog8.compiler.Zeropage
|
||||
import java.nio.file.Path
|
||||
|
||||
|
||||
typealias InitialValues = Map<Block, Map<String, VarDecl>>
|
||||
|
||||
|
||||
internal interface CompilationTarget {
|
||||
companion object {
|
||||
lateinit var name: String
|
||||
lateinit var machine: IMachineDefinition
|
||||
lateinit var encodeString: (str: String, altEncoding: Boolean) -> List<Short>
|
||||
lateinit var decodeString: (bytes: List<Short>, altEncoding: Boolean) -> String
|
||||
lateinit var asmGenerator: (Program, Zeropage, CompilationOptions, Path) -> IAssemblyGenerator
|
||||
lateinit var asmGenerator: (Program, Zeropage, InitialValues, CompilationOptions, Path) -> IAssemblyGenerator
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import prog8.ast.statements.*
|
||||
import prog8.compiler.*
|
||||
import prog8.compiler.target.IAssemblyGenerator
|
||||
import prog8.compiler.target.IAssemblyProgram
|
||||
import prog8.compiler.target.InitialValues
|
||||
import prog8.compiler.target.c64.AssemblyProgram
|
||||
import prog8.compiler.target.c64.C64MachineDefinition
|
||||
import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_HI_HEX
|
||||
@ -26,9 +27,10 @@ import kotlin.math.absoluteValue
|
||||
|
||||
|
||||
internal class AsmGen(private val program: Program,
|
||||
private val zeropage: Zeropage,
|
||||
private val options: CompilationOptions,
|
||||
private val outputDir: Path): IAssemblyGenerator {
|
||||
private val zeropage: Zeropage,
|
||||
private val initialValues: InitialValues,
|
||||
private val options: CompilationOptions,
|
||||
private val outputDir: Path): IAssemblyGenerator {
|
||||
|
||||
private val assemblyLines = mutableListOf<String>()
|
||||
private val globalFloatConsts = mutableMapOf<Double, String>() // all float values in the entire program (value -> varname)
|
||||
@ -126,7 +128,7 @@ internal class AsmGen(private val program: Program,
|
||||
out(" ldx #\$ff\t; init estack pointer")
|
||||
|
||||
out(" ; initialize the variables in each block")
|
||||
program.allBlocks().filter { it.initialValues.any() }.forEach { out(" jsr ${it.name}.prog8_init_vars") }
|
||||
program.allBlocks().filter { it in initialValues }.forEach { out(" jsr ${it.name}.prog8_init_vars") }
|
||||
|
||||
out(" clc")
|
||||
when (zeropage.exitProgramStrategy) {
|
||||
@ -173,10 +175,12 @@ internal class AsmGen(private val program: Program,
|
||||
|
||||
// if any global vars need to be initialized, generate a subroutine that does this
|
||||
// it will be called from program init.
|
||||
if(block.initialValues.isNotEmpty()) {
|
||||
if(block in initialValues) {
|
||||
out("prog8_init_vars\t.proc\n")
|
||||
block.initialValues.forEach { (scopedName, decl) ->
|
||||
val target = AssignTarget(null, IdentifierReference(scopedName.split('.'), decl.position), null, null, decl.position)
|
||||
initialValues.getValue(block).forEach { (scopedName, decl) ->
|
||||
val scopedFullName = scopedName.split('.')
|
||||
require(scopedFullName.first()==block.name)
|
||||
val target = AssignTarget(null, IdentifierReference(scopedFullName.drop(1), decl.position), null, null, decl.position)
|
||||
val assign = Assignment(target, null, decl.value!!, decl.position)
|
||||
assign.linkParents(decl.parent)
|
||||
assignmentAsmGen.translate(assign)
|
||||
@ -229,7 +233,7 @@ internal class AsmGen(private val program: Program,
|
||||
val variables = statements.filterIsInstance<VarDecl>().filter { it.type==VarDeclType.VAR }
|
||||
for(variable in variables) {
|
||||
// should NOT allocate subroutine parameters on the zero page
|
||||
val fullName = variable.scopedname
|
||||
val fullName = variable.makeScopedName(variable.name)
|
||||
val zpVar = allocatedZeropageVariables[fullName]
|
||||
if(zpVar==null) {
|
||||
// This var is not on the ZP yet. Attempt to move it there (if it's not a float, those take up too much space)
|
||||
@ -305,7 +309,14 @@ internal class AsmGen(private val program: Program,
|
||||
}
|
||||
}
|
||||
DataType.ARRAY_F -> {
|
||||
val array = (decl.value as ArrayLiteralValue).value
|
||||
val array =
|
||||
if(decl.value!=null)
|
||||
(decl.value as ArrayLiteralValue).value
|
||||
else {
|
||||
// no init value, use zeros
|
||||
val zero = decl.asDefaultValueDecl(decl.parent).value!!
|
||||
Array(decl.arraysize!!.size()!!) { zero }
|
||||
}
|
||||
val floatFills = array.map {
|
||||
val number = (it as NumericLiteralValue).number
|
||||
makeFloatFill(C64MachineDefinition.Mflpt5.fromNumber(number))
|
||||
@ -359,7 +370,7 @@ internal class AsmGen(private val program: Program,
|
||||
|
||||
// non-string variables
|
||||
normalVars.filter{ it.datatype != DataType.STR }.sortedBy { it.datatype }.forEach {
|
||||
if(it.scopedname !in allocatedZeropageVariables)
|
||||
if(it.makeScopedName(it.name) !in allocatedZeropageVariables)
|
||||
vardecl2asm(it)
|
||||
}
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
||||
}
|
||||
|
||||
override fun visit(decl: VarDecl) {
|
||||
if (decl.autogeneratedDontRemove || (decl.definingModule().isLibraryModule && decl.type != VarDeclType.VAR)) {
|
||||
if (decl.autogeneratedDontRemove || decl.definingModule().isLibraryModule) {
|
||||
// make sure autogenerated vardecls are in the used symbols
|
||||
addNodeAndParentScopes(decl)
|
||||
}
|
||||
|
@ -79,10 +79,10 @@ main {
|
||||
|
||||
uw1 = 2222
|
||||
uw2 = 999
|
||||
if sgn(uw2 as word - uw1 as word) != -1
|
||||
c64scr.print("sgn2 error6\n")
|
||||
if sgn(uw2 - uw1) != -1
|
||||
c64scr.print("sgn2 error6\n")
|
||||
if sgn((uw2 as word) - (uw1 as word)) != -1
|
||||
c64scr.print("sgn2 error6a\n")
|
||||
if sgn(uw2 - uw1) != 1 ; always 0 or 1 if unsigned
|
||||
c64scr.print("sgn2 error6b\n")
|
||||
|
||||
f1 = 3.45
|
||||
f2 = 1.11
|
||||
|
@ -5,64 +5,45 @@
|
||||
|
||||
main {
|
||||
|
||||
sub subje() {
|
||||
ubyte xyz = 123
|
||||
ubyte foo
|
||||
c64scr.print_ub(xyz)
|
||||
c64.CHROUT('\n')
|
||||
c64scr.print_ub(foo)
|
||||
c64.CHROUT('\n')
|
||||
xyz++
|
||||
foo++
|
||||
}
|
||||
|
||||
sub start() {
|
||||
ubyte xyz = 99 ; TODO fix compiler error when removing unused var
|
||||
word wcosa = cos8(xyz)
|
||||
word wcosa_sinb = wcosa / 128
|
||||
ubyte ub1
|
||||
ubyte ub2 = 99
|
||||
uword uw1
|
||||
uword uw2 = 9999
|
||||
ubyte[5] array1
|
||||
ubyte[5] array2 = [22,33,44,55,66]
|
||||
|
||||
subje()
|
||||
subje()
|
||||
subje()
|
||||
c64scr.print_ub(ub1)
|
||||
c64.CHROUT(',')
|
||||
c64scr.print_ub(ub2)
|
||||
c64.CHROUT(',')
|
||||
c64scr.print_uw(uw1)
|
||||
c64.CHROUT(',')
|
||||
c64scr.print_uw(uw2)
|
||||
c64.CHROUT(',')
|
||||
c64scr.print_ub(array1[0])
|
||||
c64.CHROUT(',')
|
||||
c64scr.print_ub(array2[0])
|
||||
c64.CHROUT('\n')
|
||||
|
||||
; ubyte ub1
|
||||
; ubyte ub2 = 99
|
||||
; uword uw1
|
||||
; uword uw2 = 9999
|
||||
; ubyte[5] array1
|
||||
; ubyte[5] array2 = [22,33,44,55,66]
|
||||
;
|
||||
; c64scr.print_ub(ub1)
|
||||
; c64.CHROUT(',')
|
||||
; c64scr.print_ub(ub2)
|
||||
; c64.CHROUT(',')
|
||||
; c64scr.print_uw(uw1)
|
||||
; c64.CHROUT(',')
|
||||
; c64scr.print_uw(uw2)
|
||||
; c64.CHROUT(',')
|
||||
; c64scr.print_ub(array1[0])
|
||||
; c64.CHROUT(',')
|
||||
; c64scr.print_ub(array2[0])
|
||||
; c64.CHROUT('\n')
|
||||
;
|
||||
; ub1++
|
||||
; ub2++
|
||||
; uw1++
|
||||
; uw2++
|
||||
; array1[0]++
|
||||
; array2[0]++
|
||||
;
|
||||
; c64scr.print_ub(ub1)
|
||||
; c64.CHROUT(',')
|
||||
; c64scr.print_ub(ub2)
|
||||
; c64.CHROUT(',')
|
||||
; c64scr.print_uw(uw1)
|
||||
; c64.CHROUT(',')
|
||||
; c64scr.print_uw(uw2)
|
||||
; c64.CHROUT(',')
|
||||
; c64scr.print_ub(array1[0])
|
||||
; c64.CHROUT(',')
|
||||
; c64scr.print_ub(array2[0])
|
||||
; c64.CHROUT('\n')
|
||||
ub1++
|
||||
ub2++
|
||||
uw1++
|
||||
uw2++
|
||||
array1[0]++
|
||||
array2[0]++
|
||||
|
||||
c64scr.print_ub(ub1)
|
||||
c64.CHROUT(',')
|
||||
c64scr.print_ub(ub2)
|
||||
c64.CHROUT(',')
|
||||
c64scr.print_uw(uw1)
|
||||
c64.CHROUT(',')
|
||||
c64scr.print_uw(uw2)
|
||||
c64.CHROUT(',')
|
||||
c64scr.print_ub(array1[0])
|
||||
c64.CHROUT(',')
|
||||
c64scr.print_ub(array2[0])
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user