mirror of
https://github.com/irmen/prog8.git
synced 2024-09-08 10:55:08 +00:00
assembler reserved symbols checked
This commit is contained in:
parent
2c25df122a
commit
b0dda08e74
@ -35,6 +35,17 @@ init_system .proc
|
|||||||
rts
|
rts
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
|
|
||||||
|
read_byte_from_address .proc
|
||||||
|
; -- read the byte from the memory address on the top of the stack, return in A (stack remains unchanged)
|
||||||
|
lda c64.ESTACK_LO+1,x
|
||||||
|
ldy c64.ESTACK_HI+1,x
|
||||||
|
sta (+) +1
|
||||||
|
sty (+) +2
|
||||||
|
+ lda $ffff ; modified
|
||||||
|
rts
|
||||||
|
.pend
|
||||||
|
|
||||||
|
|
||||||
add_a_to_zpword .proc
|
add_a_to_zpword .proc
|
||||||
; -- add ubyte in A to the uword in c64.SCRATCH_ZPWORD1
|
; -- add ubyte in A to the uword in c64.SCRATCH_ZPWORD1
|
||||||
|
@ -7,10 +7,12 @@ import prog8.ast.Program
|
|||||||
import prog8.ast.base.*
|
import prog8.ast.base.*
|
||||||
import prog8.ast.expressions.*
|
import prog8.ast.expressions.*
|
||||||
import prog8.ast.statements.*
|
import prog8.ast.statements.*
|
||||||
|
import prog8.compiler.target.c64.AssemblyProgram
|
||||||
import prog8.functions.BuiltinFunctions
|
import prog8.functions.BuiltinFunctions
|
||||||
|
|
||||||
|
|
||||||
internal class AstIdentifiersChecker(private val program: Program) : IAstModifyingVisitor {
|
internal class AstIdentifiersChecker(private val program: Program) : IAstModifyingVisitor {
|
||||||
|
|
||||||
private val checkResult: MutableList<AstException> = mutableListOf()
|
private val checkResult: MutableList<AstException> = mutableListOf()
|
||||||
|
|
||||||
private var blocks = mutableMapOf<String, Block>()
|
private var blocks = mutableMapOf<String, Block>()
|
||||||
@ -64,6 +66,11 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi
|
|||||||
// the builtin functions can't be redefined
|
// the builtin functions can't be redefined
|
||||||
checkResult.add(NameError("builtin function cannot be redefined", decl.position))
|
checkResult.add(NameError("builtin function cannot be redefined", decl.position))
|
||||||
|
|
||||||
|
if(decl.name in AssemblyProgram.reservedNames)
|
||||||
|
checkResult.add(NameError("can't use a symbol name reserved by the assembler program", decl.position))
|
||||||
|
if(decl.name in AssemblyProgram.opcodeNames)
|
||||||
|
checkResult.add(NameError("can't use a cpu opcode name as a symbol", decl.position))
|
||||||
|
|
||||||
// is it a struct variable? then define all its struct members as mangled names,
|
// is it a struct variable? then define all its struct members as mangled names,
|
||||||
// and include the original decl as well.
|
// and include the original decl as well.
|
||||||
if(decl.datatype==DataType.STRUCT) {
|
if(decl.datatype==DataType.STRUCT) {
|
||||||
@ -102,8 +109,9 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi
|
|||||||
// the builtin functions can't be redefined
|
// the builtin functions can't be redefined
|
||||||
checkResult.add(NameError("builtin function cannot be redefined", subroutine.position))
|
checkResult.add(NameError("builtin function cannot be redefined", subroutine.position))
|
||||||
} else {
|
} else {
|
||||||
if (subroutine.parameters.any { it.name in BuiltinFunctions })
|
// already reported elsewhere:
|
||||||
checkResult.add(NameError("builtin function name cannot be used as parameter", subroutine.position))
|
// if (subroutine.parameters.any { it.name in BuiltinFunctions })
|
||||||
|
// checkResult.add(NameError("builtin function name cannot be used as parameter", subroutine.position))
|
||||||
|
|
||||||
val existing = program.namespace.lookup(listOf(subroutine.name), subroutine)
|
val existing = program.namespace.lookup(listOf(subroutine.name), subroutine)
|
||||||
if (existing != null && existing !== subroutine)
|
if (existing != null && existing !== subroutine)
|
||||||
|
@ -9,6 +9,25 @@ class AssemblyProgram(val name: String) {
|
|||||||
private val assemblyFile = "$name.asm"
|
private val assemblyFile = "$name.asm"
|
||||||
private val viceMonListFile = "$name.vice-mon-list"
|
private val viceMonListFile = "$name.vice-mon-list"
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
// reserved by the 64tass assembler (on top of prog8"s own reserved names)
|
||||||
|
val reservedNames = setOf("bit", "bits", "bool", "bytes", "code", "dict", "gap", "int", "list", "tuple", "type",
|
||||||
|
"trunc", " frac", "cbrt", "log10", "log", "exp", "pow", "asin", "sinh", "acos", "cosh", "tanh", "hypot",
|
||||||
|
"atan2", "sign", "binary", "format", "random", "range", "repr", "size", "sort")
|
||||||
|
|
||||||
|
// 6502 opcodes (including aliases and illegal opcodes), these cannot be used as variable names either
|
||||||
|
val opcodeNames = setOf("adc", "ahx", "alr", "anc", "and", "ane", "arr", "asl", "asr", "axs", "bcc", "bcs",
|
||||||
|
"beq", "bge", "bit", "blt", "bmi", "bne", "bpl", "brk", "bvc", "bvs", "clc",
|
||||||
|
"cld", "cli", "clv", "cmp", "cpx", "cpy", "dcm", "dcp", "dec", "dex", "dey",
|
||||||
|
"eor", "gcc", "gcs", "geq", "gge", "glt", "gmi", "gne", "gpl", "gvc", "gvs",
|
||||||
|
"inc", "ins", "inx", "iny", "isb", "isc", "jam", "jmp", "jsr", "lae", "las",
|
||||||
|
"lax", "lda", "lds", "ldx", "ldy", "lsr", "lxa", "nop", "ora", "pha", "php",
|
||||||
|
"pla", "plp", "rla", "rol", "ror", "rra", "rti", "rts", "sax", "sbc", "sbx",
|
||||||
|
"sec", "sed", "sei", "sha", "shl", "shr", "shs", "shx", "shy", "slo", "sre",
|
||||||
|
"sta", "stx", "sty", "tas", "tax", "tay", "tsx", "txa", "txs", "tya", "xaa")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fun assemble(options: CompilationOptions) {
|
fun assemble(options: CompilationOptions) {
|
||||||
// add "-Wlong-branch" to see warnings about conversion of branch instructions to jumps
|
// add "-Wlong-branch" to see warnings about conversion of branch instructions to jumps
|
||||||
val command = mutableListOf("64tass", "--ascii", "--case-sensitive", "--long-branch", "-Wall", "-Wno-strict-bool",
|
val command = mutableListOf("64tass", "--ascii", "--case-sensitive", "--long-branch", "-Wall", "-Wno-strict-bool",
|
||||||
@ -41,7 +60,7 @@ class AssemblyProgram(val name: String) {
|
|||||||
private fun generateBreakpointList() {
|
private fun generateBreakpointList() {
|
||||||
// builds list of breakpoints, appends to monitor list file
|
// builds list of breakpoints, appends to monitor list file
|
||||||
val breakpoints = mutableListOf<String>()
|
val breakpoints = mutableListOf<String>()
|
||||||
val pattern = Regex("""al (\w+) \S+_prog8_breakpoint_\d+.?""") // gather breakpoints by the source label that's generated for them
|
val pattern = Regex("""al (\w+) \S+_prog8_breakpoint_\d+.?""") // gather breakpoints by the source label that"s generated for them
|
||||||
for(line in File(viceMonListFile).readLines()) {
|
for(line in File(viceMonListFile).readLines()) {
|
||||||
val match = pattern.matchEntire(line)
|
val match = pattern.matchEntire(line)
|
||||||
if(match!=null)
|
if(match!=null)
|
||||||
|
@ -644,19 +644,18 @@ internal class AsmGen2(val program: Program,
|
|||||||
val scopedParamVar = (sub.scopedname+"."+paramVar.name).split(".")
|
val scopedParamVar = (sub.scopedname+"."+paramVar.name).split(".")
|
||||||
val target = AssignTarget(null, IdentifierReference(scopedParamVar, sub.position), null, null, sub.position)
|
val target = AssignTarget(null, IdentifierReference(scopedParamVar, sub.position), null, null, sub.position)
|
||||||
target.linkParents(value.parent)
|
target.linkParents(value.parent)
|
||||||
val literal = value as? NumericLiteralValue
|
when (value) {
|
||||||
when {
|
is NumericLiteralValue -> {
|
||||||
literal!=null -> {
|
|
||||||
// optimize when the argument is a constant literal
|
// optimize when the argument is a constant literal
|
||||||
when(arg.value.type) {
|
when(arg.value.type) {
|
||||||
in ByteDatatypes -> assignFromByteConstant(target, literal.number.toShort())
|
in ByteDatatypes -> assignFromByteConstant(target, value.number.toShort())
|
||||||
in WordDatatypes -> assignFromWordConstant(target, literal.number.toInt())
|
in WordDatatypes -> assignFromWordConstant(target, value.number.toInt())
|
||||||
DataType.FLOAT -> assignFromFloatConstant(target, literal.number.toDouble())
|
DataType.FLOAT -> assignFromFloatConstant(target, value.number.toDouble())
|
||||||
in PassByReferenceDatatypes -> throw AssemblyError("can't pass string/array as arguments?")
|
in PassByReferenceDatatypes -> throw AssemblyError("can't pass string/array as arguments?")
|
||||||
else -> throw AssemblyError("weird arg datatype")
|
else -> throw AssemblyError("weird arg datatype")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
value is IdentifierReference -> {
|
is IdentifierReference -> {
|
||||||
// optimize when the argument is a variable
|
// optimize when the argument is a variable
|
||||||
when (arg.value.type) {
|
when (arg.value.type) {
|
||||||
in ByteDatatypes -> assignFromByteVariable(target, value)
|
in ByteDatatypes -> assignFromByteVariable(target, value)
|
||||||
@ -666,7 +665,29 @@ internal class AsmGen2(val program: Program,
|
|||||||
else -> throw AssemblyError("weird arg datatype")
|
else -> throw AssemblyError("weird arg datatype")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> TODO("non-constant sub arg $arg")
|
is RegisterExpr -> {
|
||||||
|
assignFromRegister(target, value.register)
|
||||||
|
}
|
||||||
|
is DirectMemoryRead -> {
|
||||||
|
when(value.addressExpression) {
|
||||||
|
is NumericLiteralValue -> {
|
||||||
|
val address = (value.addressExpression as NumericLiteralValue).number.toInt()
|
||||||
|
assignFromMemoryByte(target, address, null)
|
||||||
|
}
|
||||||
|
is IdentifierReference -> {
|
||||||
|
assignFromMemoryByte(target, null, value.addressExpression as IdentifierReference)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
translateExpression(value.addressExpression)
|
||||||
|
out(" jsr prog8_lib.read_byte_from_address | inx")
|
||||||
|
assignFromRegister(target, Register.A)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
translateExpression(value)
|
||||||
|
assignFromEvalResult(target)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// pass arg via a register parameter
|
// pass arg via a register parameter
|
||||||
@ -1149,7 +1170,21 @@ internal class AsmGen2(val program: Program,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun translateExpression(expr: DirectMemoryRead) {
|
private fun translateExpression(expr: DirectMemoryRead) {
|
||||||
TODO("memread $expr")
|
when(expr.addressExpression) {
|
||||||
|
is NumericLiteralValue -> {
|
||||||
|
val address = (expr.addressExpression as NumericLiteralValue).number.toInt()
|
||||||
|
out(" lda ${address.toHex()} | sta $ESTACK_LO_HEX,x | dex")
|
||||||
|
}
|
||||||
|
is IdentifierReference -> {
|
||||||
|
val sourceName = asmIdentifierName(expr.addressExpression as IdentifierReference)
|
||||||
|
out(" lda $sourceName | sta $ESTACK_LO_HEX,x | dex")
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
translateExpression(expr.addressExpression)
|
||||||
|
out(" jsr prog8_lib.read_byte_from_address")
|
||||||
|
out(" sta $ESTACK_LO_PLUS1_HEX,x")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun translateExpression(expr: NumericLiteralValue) {
|
private fun translateExpression(expr: NumericLiteralValue) {
|
||||||
@ -1514,9 +1549,9 @@ internal class AsmGen2(val program: Program,
|
|||||||
out("""
|
out("""
|
||||||
inx
|
inx
|
||||||
lda $ESTACK_LO_HEX,x
|
lda $ESTACK_LO_HEX,x
|
||||||
|
ldy $ESTACK_HI_HEX,x
|
||||||
sta (+) +1
|
sta (+) +1
|
||||||
lda $ESTACK_HI_HEX,x
|
sty (+) +2
|
||||||
sta (+) +2
|
|
||||||
lda $sourceName
|
lda $sourceName
|
||||||
+ sta ${65535.toHex()} ; modified
|
+ sta ${65535.toHex()} ; modified
|
||||||
""")
|
""")
|
||||||
@ -1554,7 +1589,97 @@ internal class AsmGen2(val program: Program,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> out("; TODO assign register $register to $target") // TODO
|
target.memoryAddress!=null -> {
|
||||||
|
val addressExpr = target.memoryAddress.addressExpression
|
||||||
|
val addressLv = addressExpr as? NumericLiteralValue
|
||||||
|
val registerName = register.name.toLowerCase()
|
||||||
|
when {
|
||||||
|
addressLv != null -> out(" st$registerName ${addressLv.number.toHex()}")
|
||||||
|
addressExpr is IdentifierReference -> {
|
||||||
|
val targetName = asmIdentifierName(addressExpr)
|
||||||
|
out(" st$registerName $targetName")
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
translateExpression(addressExpr)
|
||||||
|
when (register) {
|
||||||
|
Register.A -> out(" tay")
|
||||||
|
Register.X -> throw AssemblyError("can't use X register here")
|
||||||
|
Register.Y -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out("""
|
||||||
|
inx
|
||||||
|
lda $ESTACK_LO_HEX,x
|
||||||
|
sta (+) +1
|
||||||
|
lda $ESTACK_HI_HEX,x
|
||||||
|
sta (+) +2
|
||||||
|
+ sty ${65535.toHex()} ; modified
|
||||||
|
""")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
targetArrayIdx!=null -> {
|
||||||
|
val index = targetArrayIdx.arrayspec.index
|
||||||
|
val targetName = asmIdentifierName(targetArrayIdx.identifier)
|
||||||
|
when (index) {
|
||||||
|
is NumericLiteralValue -> {
|
||||||
|
val memindex = index.number.toInt()
|
||||||
|
when(register) {
|
||||||
|
Register.A -> out(" sta $targetName+$memindex")
|
||||||
|
Register.X -> out(" stx $targetName+$memindex")
|
||||||
|
Register.Y -> out(" sty $targetName+$memindex")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is RegisterExpr -> {
|
||||||
|
when(register) {
|
||||||
|
Register.A -> out(" sta ${C64Zeropage.SCRATCH_B1}")
|
||||||
|
Register.X -> out(" stx ${C64Zeropage.SCRATCH_B1}")
|
||||||
|
Register.Y -> out(" sty ${C64Zeropage.SCRATCH_B1}")
|
||||||
|
}
|
||||||
|
when(index.register) {
|
||||||
|
Register.A -> {}
|
||||||
|
Register.X -> out(" txa")
|
||||||
|
Register.Y -> out(" tya")
|
||||||
|
}
|
||||||
|
out("""
|
||||||
|
tay
|
||||||
|
lda ${C64Zeropage.SCRATCH_B1}
|
||||||
|
sta $targetName,y
|
||||||
|
""")
|
||||||
|
}
|
||||||
|
is IdentifierReference -> {
|
||||||
|
when(register) {
|
||||||
|
Register.A -> out(" sta ${C64Zeropage.SCRATCH_B1}")
|
||||||
|
Register.X -> out(" stx ${C64Zeropage.SCRATCH_B1}")
|
||||||
|
Register.Y -> out(" sty ${C64Zeropage.SCRATCH_B1}")
|
||||||
|
}
|
||||||
|
out("""
|
||||||
|
lda ${asmIdentifierName(index)}
|
||||||
|
tay
|
||||||
|
lda ${C64Zeropage.SCRATCH_B1}
|
||||||
|
sta $targetName,y
|
||||||
|
""")
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
saveRegister(register)
|
||||||
|
translateExpression(index)
|
||||||
|
restoreRegister(register)
|
||||||
|
when(register) {
|
||||||
|
Register.A -> out(" sta ${C64Zeropage.SCRATCH_B1}")
|
||||||
|
Register.X -> out(" stx ${C64Zeropage.SCRATCH_B1}")
|
||||||
|
Register.Y -> out(" sty ${C64Zeropage.SCRATCH_B1}")
|
||||||
|
}
|
||||||
|
out("""
|
||||||
|
inx
|
||||||
|
lda $ESTACK_LO_HEX,x
|
||||||
|
tay
|
||||||
|
lda ${C64Zeropage.SCRATCH_B1}
|
||||||
|
sta $targetName,y
|
||||||
|
""")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> TODO("assign register $register to $target")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,22 +6,27 @@
|
|||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
|
|
||||||
str s1 = "hello"
|
carry(1)
|
||||||
str s2 = "hello"
|
carry(0)
|
||||||
str s3 = "hello"
|
; ubyte bb = @($d020)+4
|
||||||
str s4 = "hello"
|
; ubyte bb2 = @($d020+A)+4
|
||||||
|
;
|
||||||
|
; subje(55)
|
||||||
|
; subje(@($d020+bb))
|
||||||
|
; subje(A)
|
||||||
|
; subje(bb)
|
||||||
|
; subje(bb+43)
|
||||||
|
}
|
||||||
|
|
||||||
if true {
|
sub carry(ubyte cc) {
|
||||||
c64scr.print("irmen")
|
A=cc
|
||||||
c64scr.print("hello")
|
if A!=0
|
||||||
c64scr.print("hello2")
|
c64scr.print("carry set\n")
|
||||||
}
|
else
|
||||||
|
c64scr.print("carry clear\n")
|
||||||
if true {
|
}
|
||||||
c64scr.print("irmen")
|
|
||||||
c64scr.print("hello")
|
|
||||||
c64scr.print("hello2")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
sub subje(ubyte arg) {
|
||||||
|
A=arg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user