Merge branch 'irmen:v7.1' into v7.1

This commit is contained in:
meisl 2021-07-09 11:03:31 +02:00 committed by GitHub
commit 81abf29bec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 96 additions and 52 deletions

View File

@ -31,7 +31,8 @@ fun pathFrom(stringPath: String, vararg rest: String): Path = FileSystems.getDe
private fun compileMain(args: Array<String>): Boolean {
val cli = ArgParser("prog8compiler", prefixStyle = ArgParser.OptionPrefixStyle.JVM)
val startEmulator by cli.option(ArgType.Boolean, fullName = "emu", description = "auto-start emulator after successful compilation")
val startEmulator1 by cli.option(ArgType.Boolean, fullName = "emu", description = "auto-start emulator after successful compilation")
val startEmulator2 by cli.option(ArgType.Boolean, fullName = "emu2", description = "auto-start alternative emulator after successful compilation")
val outputDir by cli.option(ArgType.String, fullName = "out", description = "directory for output files instead of current directory").default(".")
val dontWriteAssembly by cli.option(ArgType.Boolean, fullName = "noasm", description="don't create assembly code")
val dontOptimize by cli.option(ArgType.Boolean, fullName = "noopt", description = "don't perform any optimizations")
@ -119,13 +120,17 @@ private fun compileMain(args: Array<String>): Boolean {
return false
}
if (startEmulator==true) {
if (compilationResult.programName.isEmpty())
if(startEmulator1==true || startEmulator2==true) {
if (compilationResult.programName.isEmpty()) {
println("\nCan't start emulator because no program was assembled.")
else {
compilationResult.compTarget.machine.launchEmulator(compilationResult.programName)
return true
}
}
if (startEmulator1==true)
compilationResult.compTarget.machine.launchEmulator(1, compilationResult.programName)
else if (startEmulator2==true)
compilationResult.compTarget.machine.launchEmulator(2, compilationResult.programName)
}
}

View File

@ -1,6 +1,5 @@
package prog8.compiler.astprocessing
import prog8.ast.Module
import prog8.ast.Program
import prog8.ast.base.Position
import prog8.ast.expressions.StringLiteralValue
@ -17,29 +16,20 @@ internal class AstIdentifiersChecker(private val program: Program, private val e
errors.err("name conflict '$name', also defined in ${existing.position.file} line ${existing.position.line}", position)
}
override fun visit(module: Module) {
blocks.clear() // blocks may be redefined within a different module
super.visit(module)
}
override fun visit(block: Block) {
if(block.name in compTarget.machine.opcodeNames)
errors.err("can't use a cpu opcode name as a symbol: '${block.name}'", block.position)
val existing = blocks[block.name]
if(existing!=null)
nameError(block.name, block.position, existing)
if(existing!=null) {
if(block.isInLibrary)
nameError(existing.name, existing.position, block)
else
nameError(block.name, block.position, existing)
}
else
blocks[block.name] = block
if(!block.isInLibrary) {
val libraries = program.modules.filter { it.isLibraryModule }
val libraryBlockNames = libraries.flatMap { it.statements.filterIsInstance<Block>().map { b -> b.name } }
if(block.name in libraryBlockNames)
errors.err("block is already defined in an included library module", block.position)
}
super.visit(block)
}

View File

@ -32,6 +32,6 @@ interface IMachineDefinition {
fun getFloat(num: Number): IMachineFloat
fun importLibs(compilerOptions: CompilationOptions, compilationTargetName: String): List<String>
fun launchEmulator(programName: String)
fun launchEmulator(selectedEmulator: Int, programName: String)
fun isRegularRAMaddress(address: Int): Boolean
}

View File

@ -4,6 +4,7 @@ import prog8.compiler.*
import prog8.compiler.target.CpuType
import prog8.compiler.target.IMachineDefinition
import prog8.compiler.target.IMachineFloat
import prog8.compiler.target.cbm.viceMonListPostfix
import java.io.IOException
import kotlin.math.absoluteValue
import kotlin.math.pow
@ -35,10 +36,15 @@ internal object C64MachineDefinition: IMachineDefinition {
emptyList()
}
override fun launchEmulator(programName: String) {
override fun launchEmulator(selectedEmulator: Int, programName: String) {
if(selectedEmulator!=1) {
System.err.println("The c64 target only supports the main emulator (Vice).")
return
}
for(emulator in listOf("x64sc", "x64")) {
println("\nStarting C-64 emulator $emulator...")
val cmdline = listOf(emulator, "-silent", "-moncommands", "$programName.vice-mon-list",
val cmdline = listOf(emulator, "-silent", "-moncommands", "$programName.$viceMonListPostfix",
"-autostartprgmode", "1", "-autostart-warp", "-autostart", "$programName.prg")
val processb = ProcessBuilder(cmdline).inheritIO()
val process: Process

View File

@ -6,11 +6,14 @@ import prog8.compiler.target.IAssemblyProgram
import prog8.compiler.target.generatedLabelPrefix
import java.nio.file.Path
internal const val viceMonListPostfix = "vice-mon-list"
class AssemblyProgram(override val name: String, outputDir: Path, private val compTarget: String) : IAssemblyProgram {
private val assemblyFile = outputDir.resolve("$name.asm")
private val prgFile = outputDir.resolve("$name.prg")
private val binFile = outputDir.resolve("$name.bin")
private val viceMonListFile = outputDir.resolve("$name.vice-mon-list")
private val viceMonListFile = outputDir.resolve("$name.$viceMonListPostfix")
override fun assemble(options: CompilationOptions): Int {
// add "-Wlong-branch" to see warnings about conversion of branch instructions to jumps (default = do this silently)

View File

@ -4,6 +4,7 @@ import prog8.compiler.*
import prog8.compiler.target.CpuType
import prog8.compiler.target.IMachineDefinition
import prog8.compiler.target.c64.C64MachineDefinition
import prog8.compiler.target.cbm.viceMonListPostfix
import java.io.IOException
internal object CX16MachineDefinition: IMachineDefinition {
@ -32,10 +33,28 @@ internal object CX16MachineDefinition: IMachineDefinition {
emptyList()
}
override fun launchEmulator(programName: String) {
for(emulator in listOf("x16emu")) {
override fun launchEmulator(selectedEmulator: Int, programName: String) {
val emulatorName: String
val extraArgs: List<String>
when(selectedEmulator) {
1 -> {
emulatorName = "x16emu"
extraArgs = emptyList()
}
2 -> {
emulatorName = "box16"
extraArgs = listOf("-sym", "$programName.$viceMonListPostfix")
}
else -> {
System.err.println("Cx16 target only supports x16emu and box16 emulators.")
return
}
}
for(emulator in listOf(emulatorName)) {
println("\nStarting Commander X16 emulator $emulator...")
val cmdline = listOf(emulator, "-scale", "2", "-run", "-prg", "$programName.prg")
val cmdline = listOf(emulator, "-scale", "2", "-run", "-prg", "$programName.prg") + extraArgs
val processb = ProcessBuilder(cmdline).inheritIO()
val process: Process
try {

View File

@ -20,7 +20,7 @@ internal class UnusedCodeRemover(private val program: Program,
private val callgraph = CallGraph(program)
override fun before(module: Module, parent: Node): Iterable<IAstModification> {
return if (!module.isLibraryModule && (module.containsNoCodeNorVars() || callgraph.unused(module)))
return if (!module.isLibrary() && (module.containsNoCodeNorVars() || callgraph.unused(module)))
listOf(IAstModification.Remove(module, module.definingScope()))
else
noModifications
@ -80,12 +80,12 @@ internal class UnusedCodeRemover(private val program: Program,
val forceOutput = "force_output" in subroutine.definingBlock().options()
if (subroutine !== program.entrypoint() && !forceOutput && !subroutine.inline && !subroutine.isAsmSubroutine) {
if(callgraph.unused(subroutine)) {
if(!subroutine.definingModule().isLibraryModule)
if(!subroutine.definingModule().isLibrary())
errors.warn("removing unused subroutine '${subroutine.name}'", subroutine.position)
return listOf(IAstModification.Remove(subroutine, subroutine.definingScope()))
}
if(subroutine.containsNoCodeNorVars()) {
if(!subroutine.definingModule().isLibraryModule)
if(!subroutine.definingModule().isLibrary())
errors.warn("removing empty subroutine '${subroutine.name}'", subroutine.position)
val removals = mutableListOf(IAstModification.Remove(subroutine, subroutine.definingScope()))
callgraph.calledBy[subroutine]?.let {

View File

@ -74,7 +74,7 @@ locallabel:
val varInBlock = VarDecl(VarDeclType.VAR, DataType.UWORD, ZeropageWish.DONTCARE, null, "var_outside", null, false, false, false, Position.DUMMY)
val block = Block("main", null, mutableListOf(labelInBlock, varInBlock, subroutine), false, Position.DUMMY)
val module = Module("test", mutableListOf(block), Position.DUMMY, false, Path.of(""))
val module = Module("test", mutableListOf(block), Position.DUMMY, Path.of(""))
module.linkParents(ParentSentinel)
val program = Program("test", mutableListOf(module), DummyFunctions(), DummyMemsizer())
module.program = program

View File

@ -98,7 +98,7 @@ class TestMemory {
val target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
val module = Module("test", mutableListOf(subroutine), Position.DUMMY, false, Path.of(""))
val module = Module("test", mutableListOf(subroutine), Position.DUMMY, Path.of(""))
module.linkParents(ParentSentinel)
return target
}
@ -117,7 +117,7 @@ class TestMemory {
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
val module = Module("test", mutableListOf(subroutine), Position.DUMMY, false, Path.of(""))
val module = Module("test", mutableListOf(subroutine), Position.DUMMY, Path.of(""))
val program = Program("test", mutableListOf(module), DummyFunctions(), DummyMemsizer())
module.linkParents(ParentSentinel)
assertTrue(C64Target.isInRegularRAM(target, program))
@ -130,7 +130,7 @@ class TestMemory {
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
val module = Module("test", mutableListOf(subroutine), Position.DUMMY, false, Path.of(""))
val module = Module("test", mutableListOf(subroutine), Position.DUMMY, Path.of(""))
val program = Program("test", mutableListOf(module), DummyFunctions(), DummyMemsizer())
module.linkParents(ParentSentinel)
assertTrue(C64Target.isInRegularRAM(target, program))
@ -143,7 +143,7 @@ class TestMemory {
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
val module = Module("test", mutableListOf(subroutine), Position.DUMMY, false, Path.of(""))
val module = Module("test", mutableListOf(subroutine), Position.DUMMY, Path.of(""))
val program = Program("test", mutableListOf(module), DummyFunctions(), DummyMemsizer())
module.linkParents(ParentSentinel)
assertFalse(C64Target.isInRegularRAM(target, program))
@ -156,7 +156,7 @@ class TestMemory {
val target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
val module = Module("test", mutableListOf(subroutine), Position.DUMMY, false, Path.of(""))
val module = Module("test", mutableListOf(subroutine), Position.DUMMY, Path.of(""))
val program = Program("test", mutableListOf(module), DummyFunctions(), DummyMemsizer())
module.linkParents(ParentSentinel)
assertTrue(C64Target.isInRegularRAM(target, program))
@ -170,7 +170,7 @@ class TestMemory {
val target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
val module = Module("test", mutableListOf(subroutine), Position.DUMMY, false, Path.of(""))
val module = Module("test", mutableListOf(subroutine), Position.DUMMY, Path.of(""))
val program = Program("test", mutableListOf(module), DummyFunctions(), DummyMemsizer())
module.linkParents(ParentSentinel)
assertTrue(C64Target.isInRegularRAM(target, program))
@ -184,7 +184,7 @@ class TestMemory {
val target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
val module = Module("test", mutableListOf(subroutine), Position.DUMMY, false, Path.of(""))
val module = Module("test", mutableListOf(subroutine), Position.DUMMY, Path.of(""))
val program = Program("test", mutableListOf(module), DummyFunctions(), DummyMemsizer())
module.linkParents(ParentSentinel)
assertFalse(C64Target.isInRegularRAM(target, program))

View File

@ -24,7 +24,7 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program):
}
override fun visit(module: Module) {
if(!module.isLibraryModule) {
if(!module.isLibrary()) {
outputln("; ----------- module: ${module.name} -----------")
super.visit(module)
}

View File

@ -6,6 +6,8 @@ import prog8.ast.statements.*
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstVisitor
import java.nio.file.Path
import java.nio.file.Paths
import kotlin.io.path.name
import kotlin.math.abs
const val internedStringsModuleName = "prog8_interned_strings"
@ -263,7 +265,7 @@ class Program(val name: String,
init {
// insert a container module for all interned strings later
if(modules.firstOrNull()?.name != internedStringsModuleName) {
val internedStringsModule = Module(internedStringsModuleName, mutableListOf(), Position.DUMMY, true, Path.of(""))
val internedStringsModule = Module(internedStringsModuleName, mutableListOf(), Position.DUMMY, Path.of(""))
modules.add(0, internedStringsModule)
val block = Block(internedStringsModuleName, null, mutableListOf(), true, Position.DUMMY)
internedStringsModule.statements.add(block)
@ -340,7 +342,6 @@ class Program(val name: String,
class Module(override val name: String,
override var statements: MutableList<Statement>,
override val position: Position,
val isLibraryModule: Boolean,
val source: Path) : Node, INameScope {
override lateinit var parent: Node
@ -364,10 +365,20 @@ class Module(override val name: String,
replacement.parent = this
}
override fun toString() = "Module(name=$name, pos=$position, lib=$isLibraryModule)"
override fun toString() = "Module(name=$name, pos=$position, lib=${isLibrary()})"
fun accept(visitor: IAstVisitor) = visitor.visit(this)
fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
companion object {
fun pathForResource(resourcePath: String): Path {
return Paths.get("@embedded@/$resourcePath")
}
fun isLibrary(source: Path) = source.name=="" || source.startsWith("@embedded@/")
}
fun isLibrary() = isLibrary(source)
}

View File

@ -19,11 +19,11 @@ import java.nio.file.Path
private data class NumericLiteral(val number: Number, val datatype: DataType)
internal fun prog8Parser.ModuleContext.toAst(name: String, isLibrary: Boolean, source: Path, encoding: IStringEncoding) : Module {
internal fun prog8Parser.ModuleContext.toAst(name: String, source: Path, encoding: IStringEncoding) : Module {
val nameWithoutSuffix = if(name.endsWith(".p8")) name.substringBeforeLast('.') else name
val directives = this.directive().map { it.toAst() }
val blocks = this.block().map { it.toAst(isLibrary, encoding) }
return Module(nameWithoutSuffix, (directives + blocks).toMutableList(), toPosition(), isLibrary, source)
val blocks = this.block().map { it.toAst(Module.isLibrary(source), encoding) }
return Module(nameWithoutSuffix, (directives + blocks).toMutableList(), toPosition(), source)
}
private fun ParserRuleContext.toPosition() : Position {

View File

@ -44,7 +44,7 @@ class ModuleImporter(private val program: Program,
if(!Files.isReadable(filePath))
throw ParsingFailedError("No such file: $filePath")
return importModule(CharStreams.fromPath(filePath), filePath, false)
return importModule(CharStreams.fromPath(filePath), filePath)
}
fun importLibraryModule(name: String): Module? {
@ -68,7 +68,7 @@ class ModuleImporter(private val program: Program,
}
}
private fun importModule(stream: CharStream, modulePath: Path, isLibrary: Boolean): Module {
private fun importModule(stream: CharStream, modulePath: Path): Module {
val moduleName = moduleName(modulePath.fileName)
val lexer = CustomLexer(modulePath, stream)
lexer.removeErrorListeners()
@ -87,7 +87,7 @@ class ModuleImporter(private val program: Program,
// tokens.commentTokens().forEach { println(it) }
// convert to Ast
val moduleAst = parseTree.toAst(moduleName, isLibrary, modulePath, encoder)
val moduleAst = parseTree.toAst(moduleName, modulePath, encoder)
moduleAst.program = program
moduleAst.linkParents(program.namespace)
program.modules.add(moduleAst)
@ -122,7 +122,7 @@ class ModuleImporter(private val program: Program,
resource.use {
println("importing '$moduleName' (library)")
val content = it.reader().readText().replace("\r\n", "\n")
importModule(CharStreams.fromString(content), Paths.get("@embedded@/$resourcePath"), true)
importModule(CharStreams.fromString(content), Module.pathForResource(resourcePath))
}
} else {
val modulePath = tryGetModuleFromFile(moduleName, source, import.position)

View File

@ -249,7 +249,7 @@ main {
// parser.removeErrorListeners()
// parser.addErrorListener(MyErrorListener())
val ast = parser.module().toAst("test", false, Path.of(""), DummyEncoding)
val ast = parser.module().toAst("test", Path.of(""), DummyEncoding)
assertIs<Block>(ast.statements.first())
assertEquals((ast.statements.first() as Block).name, "main")
}

View File

@ -166,7 +166,9 @@ For MacOS you can use the Homebrew system to install a recent version of OpenJDK
Finally: an **emulator** (or a real machine ofcourse) to test and run your programs on.
In C64 mode, the compiler assumes the presence of the `Vice emulator <http://vice-emu.sourceforge.net/>`_.
If you're targeting the CommanderX16 instead, there's the `x16emu <https://github.com/commanderx16/x16-emulator>`_.
If you're targeting the CommanderX16 instead, there's a choice of the official `x16emu <https://github.com/commanderx16/x16-emulator>`_
and the unofficial `box16 <https://github.com/indigodarkwolf/box16>`_ (you can select which one you want to launch
using the ``-emu`` or ``-emu2`` command line options)
.. attention:: **Commander-X16 V38 versus V39**

View File

@ -3,6 +3,10 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- rename libdirs option to srcdirs?
- can we derive module.name from module.source (taking just the filename base)?
- can Position.file be a Path- making the source variable for nodes unnecessary?
- refactor code to improve testability and other things, see [CompilerDevelopment](CompilerDevelopment.md)
- simplify cx16.joystick_get2() once this cx16 rom issue is resolved: https://github.com/commanderx16/x16-rom/issues/203
@ -24,6 +28,9 @@ Future
- refactor the compiler optimizers into own project submodule
- make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as ``v_``
- [problematic due to 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?
(but we lose the optimizing aspect of the assembler where it strips out unused code.
There's not really a dynamic switch possible as all assembly lib code is static and uses one or the other)
- introduce byte-index operator to avoid index multiplications in loops over arrays?
see https://www.reddit.com/r/programming/comments/alhj59/creating_a_programming_language_and_cross/eg898b9?utm_source=share&utm_medium=web2x&context=3

View File

@ -2,3 +2,4 @@ org.gradle.caching=true
org.gradle.console=rich
org.gradle.parallel=true
org.gradle.daemon=true
kotlin.code.style=official