diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index d1a4ab85d..4527cdbe8 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -4,7 +4,10 @@ import prog8.code.StRomSub import prog8.code.StStaticVariable import prog8.code.StSub import prog8.code.ast.* -import prog8.code.core.* +import prog8.code.core.AssemblyError +import prog8.code.core.DataType +import prog8.code.core.PassByValueDatatypes +import prog8.code.core.SignedDatatypes import prog8.intermediate.* diff --git a/compiler/res/version.txt b/compiler/res/version.txt index 0ff41bfab..0cf5e26cb 100644 --- a/compiler/res/version.txt +++ b/compiler/res/version.txt @@ -1 +1 @@ -8.7 +8.8-dev diff --git a/compiler/src/prog8/compiler/astprocessing/AstIdentifiersChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstIdentifiersChecker.kt index 92c6af7cc..05a1d1b79 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstIdentifiersChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstIdentifiersChecker.kt @@ -86,7 +86,7 @@ internal class AstIdentifiersChecker(private val errors: IErrorReporter, val existing = subroutine.lookup(listOf(subroutine.name)) if (existing != null && existing !== subroutine) { - if(existing.parent!==existing.parent) + if(existing.parent!==existing.parent) // TODO fix this check nameShadowWarning(subroutine.name, existing.position, subroutine) else nameError(subroutine.name, existing.position, subroutine) @@ -122,7 +122,6 @@ internal class AstIdentifiersChecker(private val errors: IErrorReporter, errors.err("can't use a cpu opcode name as a symbol: '${label.name}'", label.position) if(label.name in BuiltinFunctions) { - // the builtin functions can't be redefined errors.err("builtin function cannot be redefined", label.position) } else { val existing = (label.definingSubroutine ?: label.definingBlock).getAllLabels(label.name) diff --git a/docs/source/syntaxreference.rst b/docs/source/syntaxreference.rst index c5342f9ff..795a762a5 100644 --- a/docs/source/syntaxreference.rst +++ b/docs/source/syntaxreference.rst @@ -508,6 +508,7 @@ logical: ``not`` ``and`` ``or`` ``xor`` Unlike most other programming languages, there is no short-circuit or McCarthy evaluation for the logical ``and`` and ``or`` operators. This means that prog8 currently always evaluates all operands from these logical expressions, even when one of them already determines the outcome! + If you don't want this to happen, you have to split and nest the if-statements yourself. range creation: ``to`` Creates a range of values from the LHS value to the RHS value, inclusive. diff --git a/docs/source/todo.rst b/docs/source/todo.rst index f9906bff9..c214b5136 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,8 +3,10 @@ TODO For next release ^^^^^^^^^^^^^^^^ -- ir: register allocation per data type a specific allocation, so we are certain when a reg is used it's just for one specific datatype -- ir: write addresses as hex into p8ir file +- AstIdentifiersChecker: fix the subroutine name shadow if-condition (see vardecl check) +- 6502 codegen: make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as ``p8v_``? Or not worth it (most 3 letter opcodes as variables are nonsensical anyway) + then we can get rid of the instruction lists in the machinedefinitions as well. This is already no problem at all in the IR codegen. +- create BSS section in output program and put StStaticVariables in there with bss=true. Don't forget to add init code to zero out everything that was put in bss. If array in bss->only zero ONCE! So requires self-modifying code ... @@ -20,7 +22,7 @@ Future Things and Ideas ^^^^^^^^^^^^^^^^^^^^^^^ Compiler: -- create BSS section in output program and put StStaticVariables in there with bss=true. Don't forget to add init code to zero out everything that was put in bss. If array in bss->only zero ONCE! So requires self-modifying code +- AstIdentifiersChecker: can a subroutine really not have the same name as its enclosing block? - ir: mechanism to determine for chunks which registers are getting input values from "outside" - ir: mechanism to determine for chunks which registers are passing values out? (i.e. are used again in another chunk) - ir: peephole opt: renumber registers in chunks to start with 1 again every time (but keep entry values in mind!) @@ -33,20 +35,12 @@ Compiler: - createAssemblyAndAssemble(): make it possible to actually get rid of the VarDecl nodes by fixing the rest of the code mentioned there. but probably better to rewrite the 6502 codegen on top of the new Ast. - generate WASM to eventually run prog8 on a browser canvas? -- make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as ``p8v_``? Or not worth it (most 3 letter opcodes as variables are nonsensical anyway) - then we can get rid of the instruction lists in the machinedefinitions as well? - [problematic due to using 64tass:] add a compiler option to not remove unused subroutines. this allows for building library programs. But this won't work with 64tass's .proc ... Perhaps replace all uses of .proc/.pend by .block/.bend will fix that with a compiler flag? But all library code written in asm uses .proc already..... (search/replace when writing the actual asm?) + Once new codegen is written that is based on the IR, this point is moot anyway as that will have its own dead code removal. - Zig-like try-based error handling where the V flag could indicate error condition? and/or BRK to jump into monitor on failure? (has to set BRK vector for that) - add special (u)word array type (or modifier?) that puts the array into memory as 2 separate byte-arrays 1 for LSB 1 for MSB -> allows for word arrays of length 256 and faster indexing -- ast: don't rewrite by-reference parameter type to uword, but keep the original type (str, array) - BUT that makes the handling of these types different between the scope they are defined in, and the - scope they get passed in by reference... unless we make str and array types by-reference ALWAYS? - BUT that makes simple code accessing them in the declared scope very slow because that then has to always go through - the pointer rather than directly referencing the variable symbol in the generated asm.... - Or maybe make codegen smart to check if it's a subroutine parameter or local declared variable? - Libraries: diff --git a/examples/test.p8 b/examples/test.p8 index db55f955a..15260cf14 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,27 +1,17 @@ %import textio -%import floats %zeropage basicsafe main { + ubyte @shared qqq=123 + + &uword mapped = $ea31 + sub start() { - float f1 - - floats.rndseedf(-1.2345) - txt.spc() - floats.print_f(floats.rndf()) - txt.spc() - floats.print_f(floats.rndf()) - txt.spc() - floats.print_f(floats.rndf()) - txt.nl() - - floats.rndseedf(1.2345) - txt.spc() - floats.print_f(floats.rndf()) - txt.spc() - floats.print_f(floats.rndf()) - txt.spc() - floats.print_f(floats.rndf()) - txt.nl() + ubyte bb = 99 + txt.print_ub(bb) + txt.print("Hello, world!") + uword ww = bb + txt.print_uw(bb) + txt.print_uw(ww) } } diff --git a/intermediate/src/prog8/intermediate/IRFileReader.kt b/intermediate/src/prog8/intermediate/IRFileReader.kt index d236f5e10..163e87816 100644 --- a/intermediate/src/prog8/intermediate/IRFileReader.kt +++ b/intermediate/src/prog8/intermediate/IRFileReader.kt @@ -103,7 +103,7 @@ class IRFileReader { "zeropage" -> zeropage = ZeropageType.valueOf(value) "loadAddress" -> loadAddress = value.toUInt() "dontReinitGlobals" -> dontReinitGlobals = value.toBoolean() - "evalStackBaseAddress" -> evalStackBaseAddress = if(value=="null") null else value.toUInt() + "evalStackBaseAddress" -> evalStackBaseAddress = if(value=="null") null else parseIRValue(value).toUInt() "zpReserved" -> { val (start, end) = value.split(',') zpReserved.add(UIntRange(start.toUInt(), end.toUInt())) @@ -161,7 +161,7 @@ class IRFileReader { } else { require(dontReinitGlobals) bss = false - initNumeric = value.toDouble() + initNumeric = parseIRValue(value).toDouble() } } in ArrayDatatypes -> { @@ -174,7 +174,7 @@ class IRFileReader { if (it.startsWith('&')) StArrayElement(null, it.drop(1).split('.')) else - StArrayElement(it.toDouble(), null) + StArrayElement(parseIRValue(it).toDouble(), null) } } } @@ -206,7 +206,7 @@ class IRFileReader { val (type, arrayspec, name, address) = match.destructured val arraysize = if(arrayspec.isNotBlank()) arrayspec.substring(1, arrayspec.length-1).toInt() else null val dt: DataType = parseDatatype(type, arraysize!=null) - memvars.add(StMemVar(name, dt, address.toUInt(), arraysize, Position.DUMMY)) + memvars.add(StMemVar(name, dt, parseIRValue(address).toUInt(), arraysize, Position.DUMMY)) } return memvars } @@ -286,7 +286,7 @@ class IRFileReader { return blocks } - private val blockPattern = Regex("") + private val blockPattern = Regex("") private val inlineAsmPattern = Regex("") private val bytesPattern = Regex("") private val asmsubPattern = Regex("") @@ -299,7 +299,7 @@ class IRFileReader { throw IRParseException("invalid BLOCK") val match = blockPattern.matchEntire(line) ?: throw IRParseException("invalid BLOCK") val (name, address, align, position) = match.destructured - val addressNum = if(address=="null") null else address.toUInt() + val addressNum = if(address=="null") null else parseIRValue(address).toUInt() val block = IRBlock(name, addressNum, IRBlock.BlockAlignment.valueOf(align), parsePosition(position)) while(true) { line = lines.next() @@ -367,7 +367,7 @@ class IRFileReader { } return IRAsmSubroutine( scopedname, - if(address=="null") null else address.toUInt(), + if(address=="null") null else parseIRValue(address).toUInt(), clobberRegs.toSet(), params, returns, diff --git a/intermediate/src/prog8/intermediate/IRFileWriter.kt b/intermediate/src/prog8/intermediate/IRFileWriter.kt index 446aa7e9d..be670212d 100644 --- a/intermediate/src/prog8/intermediate/IRFileWriter.kt +++ b/intermediate/src/prog8/intermediate/IRFileWriter.kt @@ -1,9 +1,6 @@ package prog8.intermediate -import prog8.code.core.ArrayDatatypes -import prog8.code.core.DataType -import prog8.code.core.InternalCompilerException -import prog8.code.core.NumericDatatypes +import prog8.code.core.* import java.nio.file.Path import kotlin.io.path.bufferedWriter import kotlin.io.path.div @@ -47,7 +44,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { private fun writeBlocks() { irProgram.blocks.forEach { block -> - out.write("\n\n") + out.write("\n\n") block.inlineAssembly.forEach { writeInlineAsm(it) } @@ -73,7 +70,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { if(reg.registerOrPair!=null) "${reg.registerOrPair}:${dt.toString().lowercase()}" else "${reg.statusflag}:${dt.toString().lowercase()}" }.joinToString(",") - out.write("\n") + out.write("\n") out.write("\n") it.parameters.forEach { (dt, regOrSf) -> val reg = if(regOrSf.registerOrPair!=null) regOrSf.registerOrPair.toString() @@ -126,10 +123,10 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { for(range in irProgram.options.zpReserved) { out.write("zpReserved=${range.first},${range.last}\n") } - out.write("loadAddress=${irProgram.options.loadAddress}\n") + out.write("loadAddress=${irProgram.options.loadAddress.toHex()}\n") out.write("optimize=${irProgram.options.optimize}\n") out.write("dontReinitGlobals=${irProgram.options.dontReinitGlobals}\n") - out.write("evalStackBaseAddress=${irProgram.options.evalStackBaseAddress}\n") + out.write("evalStackBaseAddress=${irProgram.options.evalStackBaseAddress?.toHex()}\n") out.write("outputDir=${irProgram.options.outputDir.toAbsolutePath()}\n") // other options not yet useful here? out.write("\n") @@ -142,7 +139,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { val typeStr = getTypeString(variable) val value: String = when(variable.dt) { DataType.FLOAT -> (variable.onetimeInitializationNumericValue ?: "").toString() - in NumericDatatypes -> (variable.onetimeInitializationNumericValue?.toInt() ?: "").toString() + in NumericDatatypes -> (variable.onetimeInitializationNumericValue?.toInt()?.toHex() ?: "").toString() DataType.STR -> { val encoded = irProgram.encoding.encodeString(variable.onetimeInitializationStringValue!!.first, variable.onetimeInitializationStringValue!!.second) + listOf(0u) encoded.joinToString(",") { it.toInt().toString() } @@ -158,7 +155,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { if(variable.onetimeInitializationArrayValue!==null) { variable.onetimeInitializationArrayValue!!.joinToString(",") { if(it.number!=null) - it.number!!.toInt().toString() + it.number!!.toInt().toHex() else "&${it.addressOf!!.joinToString(".")}" } @@ -175,7 +172,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { out.write("\n\n") for (variable in irProgram.st.allMemMappedVariables()) { val typeStr = getTypeString(variable) - out.write("&$typeStr ${variable.name}=${variable.address}\n") + out.write("&$typeStr ${variable.name}=${variable.address.toHex()}\n") } out.write("\n") diff --git a/intermediate/src/prog8/intermediate/IRInstructions.kt b/intermediate/src/prog8/intermediate/IRInstructions.kt index f831fe467..a4c0d19f0 100644 --- a/intermediate/src/prog8/intermediate/IRInstructions.kt +++ b/intermediate/src/prog8/intermediate/IRInstructions.kt @@ -1,5 +1,7 @@ package prog8.intermediate +import prog8.code.core.toHex + /* Intermediate Representation instructions for the IR Virtual machine. @@ -807,7 +809,7 @@ data class IRInstruction( result.add(",") } value?.let { - result.add(it.toString()) + result.add(it.toHex()) result.add(",") } fpValue?.let { diff --git a/intermediate/test/TestInstructions.kt b/intermediate/test/TestInstructions.kt index 72b62925c..6f124afa7 100644 --- a/intermediate/test/TestInstructions.kt +++ b/intermediate/test/TestInstructions.kt @@ -30,7 +30,7 @@ class TestInstructions: FunSpec({ ins.reg2 shouldBe null ins.value shouldBe 99 ins.labelSymbol shouldBe null - ins.toString() shouldBe "bz.b r42,99" + ins.toString() shouldBe "bz.b r42,$63" } test("with label") {