added a %target directive

This commit is contained in:
Irmen de Jong 2020-09-09 22:49:32 +02:00
parent e21aa2c8f0
commit 49a0584c54
35 changed files with 97 additions and 41 deletions

View File

@ -4,6 +4,7 @@
;
; indent format: TABS, size=8
%target c64
%option enable_floats
c64flt {

View File

@ -1,3 +1,4 @@
%target c64
%import c64textio
; bitmap pixel graphics module for the C64

View File

@ -5,6 +5,7 @@
;
; indent format: TABS, size=8
%target c64
c64 {
&ubyte TIME_HI = $a0 ; software jiffy clock, hi byte

View File

@ -5,6 +5,7 @@
; indent format: TABS, size=8
%target c64
%import c64lib
%import conv

View File

@ -4,6 +4,7 @@
;
; indent format: TABS, size=8
%target cx16
%option enable_floats
c64flt {

View File

@ -5,6 +5,8 @@
;
; indent format: TABS, size=8
%target cx16
c64 {

View File

@ -4,7 +4,7 @@
;
; indent format: TABS, size=8
%target cx16
%import cx16lib
%import conv

View File

@ -38,7 +38,8 @@ private fun compileMain(args: Array<String>) {
val dontWriteAssembly by cli.flagArgument("-noasm", "don't create assembly code")
val dontOptimize by cli.flagArgument("-noopt", "don't perform any optimizations")
val watchMode by cli.flagArgument("-watch", "continuous compilation mode (watches for file changes), greatly increases compilation speed")
val compilationTarget by cli.flagValueArgument("-target", "compilertarget", "target output of the compiler, currently 'c64' and 'cx16' available", "c64")
val compilationTarget by cli.flagValueArgument("-target", "compilertarget",
"target output of the compiler, currently '${C64Target.name}' and '${Cx16Target.name}' available", C64Target.name)
val moduleFiles by cli.positionalArgumentsList("modules", "main module file(s) to compile", minArgs = 1)
try {
@ -48,14 +49,10 @@ private fun compileMain(args: Array<String>) {
}
when(compilationTarget) {
"c64" -> {
CompilationTarget.instance = C64Target()
}
"cx16" -> {
CompilationTarget.instance = Cx16Target()
}
C64Target.name -> CompilationTarget.instance = C64Target
Cx16Target.name -> CompilationTarget.instance = Cx16Target
else -> {
System.err.println("invalid compilation target. Available are: c64, cx16")
System.err.println("invalid compilation target")
exitProcess(1)
}
}

View File

@ -7,7 +7,9 @@ import prog8.ast.base.*
import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.compiler.CompilationOptions
import prog8.compiler.target.C64Target
import prog8.compiler.target.CompilationTarget
import prog8.compiler.target.Cx16Target
import prog8.functions.BuiltinFunctions
import java.io.File
@ -708,6 +710,14 @@ internal class AstChecker(private val program: Program,
else if(directive.args.map{it.name in setOf("enable_floats", "force_output")}.any { !it })
err("invalid option directive argument(s)")
}
"%target" -> {
if(directive.parent !is Block && directive.parent !is Module)
err("this directive may only occur in a block or at module level")
if(directive.args.size != 1)
err("directive requires one argument")
if(directive.args.single().name !in setOf(C64Target.name, Cx16Target.name))
err("invalid compilation target")
}
else -> throw SyntaxError("invalid directive ${directive.directive}", directive.position)
}
super.visit(directive)

View File

@ -27,7 +27,8 @@ data class CompilationOptions(val output: OutputType,
val launcher: LauncherType,
val zeropage: ZeropageType,
val zpReserved: List<IntRange>,
val floats: Boolean)
val floats: Boolean,
val compilationTarget: String?)
class CompilerException(message: String?) : Exception(message)

View File

@ -4,7 +4,9 @@ import prog8.ast.AstToSourceCode
import prog8.ast.Program
import prog8.ast.base.*
import prog8.ast.statements.Directive
import prog8.compiler.target.C64Target
import prog8.compiler.target.CompilationTarget
import prog8.compiler.target.Cx16Target
import prog8.optimizer.UnusedCodeRemover
import prog8.optimizer.constantFold
import prog8.optimizer.optimizeStatements
@ -129,16 +131,26 @@ private fun determineCompilationOptions(program: Program): CompilationOptions {
.map { it[0].int!!..it[1].int!! }
.toList()
var target = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%target" }
as? Directive)?.args?.single()?.name
when(target) {
C64Target.name -> CompilationTarget.instance = C64Target
Cx16Target.name -> CompilationTarget.instance = Cx16Target
null -> target = CompilationTarget.instance.name
else -> throw FatalAstException("invalid target")
}
return CompilationOptions(
if (outputType == null) OutputType.PRG else OutputType.valueOf(outputType),
if (launcherType == null) LauncherType.BASIC else LauncherType.valueOf(launcherType),
zpType, zpReserved, floatsEnabled
zpType, zpReserved, floatsEnabled, target
)
}
private fun processAst(programAst: Program, errors: ErrorReporter, compilerOptions: CompilationOptions) {
// perform initial syntax checks and processings
println("Processing...")
println("Processing for target ${CompilationTarget.instance.name}...")
programAst.checkIdentifiers(errors)
errors.handle()
programAst.constantFold(errors)
@ -191,6 +203,9 @@ private fun writeAssembly(programAst: Program, errors: ErrorReporter, outputDir:
// printAst(programAst)
if(compilerOptions.compilationTarget!=null && compilerOptions.compilationTarget != CompilationTarget.instance.name)
throw AssemblyError("program's compilation target differs from configured target")
CompilationTarget.instance.machine.initializeZeropage(compilerOptions)
val assembly = CompilationTarget.instance.asmGenerator(
programAst,

View File

@ -26,7 +26,7 @@ internal interface CompilationTarget {
}
internal class C64Target: CompilationTarget {
internal object C64Target: CompilationTarget {
override val name = "c64"
override val machine = C64MachineDefinition
override fun encodeString(str: String, altEncoding: Boolean) =
@ -39,7 +39,7 @@ internal class C64Target: CompilationTarget {
override val initProcName = "c64.init_system"
}
internal class Cx16Target: CompilationTarget {
internal object Cx16Target: CompilationTarget {
override val name = "cx16"
override val machine = CX16MachineDefinition
override fun encodeString(str: String, altEncoding: Boolean) =

View File

@ -2,6 +2,7 @@ package prog8.compiler.target.c64
import prog8.compiler.CompilationOptions
import prog8.compiler.OutputType
import prog8.compiler.target.CompilationTarget
import prog8.compiler.target.IAssemblyProgram
import prog8.compiler.target.generatedLabelPrefix
import java.nio.file.Path
@ -22,12 +23,12 @@ class AssemblyProgram(override val name: String, outputDir: Path) : IAssemblyPro
val outFile = when (options.output) {
OutputType.PRG -> {
command.add("--cbm-prg")
println("\nCreating prg.")
println("\nCreating prg for target ${CompilationTarget.instance.name}.")
prgFile
}
OutputType.RAW -> {
command.add("--nostart")
println("\nCreating raw binary.")
println("\nCreating raw binary for target ${CompilationTarget.instance.name}.")
binFile
}
}

View File

@ -129,7 +129,7 @@ class TestC64Zeropage {
@Test
fun testNames() {
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false))
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false, "c64"))
zp.allocate("", DataType.UBYTE, null, errors)
zp.allocate("", DataType.UBYTE, null, errors)
@ -142,37 +142,37 @@ class TestC64Zeropage {
@Test
fun testZpFloatEnable() {
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false))
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, "c64"))
assertFailsWith<CompilerException> {
zp.allocate("", DataType.FLOAT, null, errors)
}
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.DONTUSE, emptyList(), true))
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.DONTUSE, emptyList(), true, "c64"))
assertFailsWith<CompilerException> {
zp2.allocate("", DataType.FLOAT, null, errors)
}
val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), true))
val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), true, "c64"))
zp3.allocate("", DataType.FLOAT, null, errors)
}
@Test
fun testZpModesWithFloats() {
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false))
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false))
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false))
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false))
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true))
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), true))
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, "c64"))
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false, "c64"))
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false, "c64"))
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false, "c64"))
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, "c64"))
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), true, "c64"))
assertFailsWith<CompilerException> {
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), true))
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), true, "c64"))
}
assertFailsWith<CompilerException> {
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), true))
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), true, "c64"))
}
}
@Test
fun testZpDontuse() {
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.DONTUSE, emptyList(), false))
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.DONTUSE, emptyList(), false, "c64"))
println(zp.free)
assertEquals(0, zp.available())
assertFailsWith<CompilerException> {
@ -182,19 +182,19 @@ class TestC64Zeropage {
@Test
fun testFreeSpaces() {
val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true))
val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, "c64"))
assertEquals(16, zp1.available())
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false))
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false, "c64"))
assertEquals(91, zp2.available())
val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false))
val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false, "c64"))
assertEquals(125, zp3.available())
val zp4 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false))
val zp4 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, "c64"))
assertEquals(238, zp4.available())
}
@Test
fun testReservedSpace() {
val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false))
val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, "c64"))
assertEquals(238, zp1.available())
assertTrue(50 in zp1.free)
assertTrue(100 in zp1.free)
@ -203,7 +203,7 @@ class TestC64Zeropage {
assertTrue(200 in zp1.free)
assertTrue(255 in zp1.free)
assertTrue(199 in zp1.free)
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, listOf(50 .. 100, 200..255), false))
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, listOf(50 .. 100, 200..255), false, "c64"))
assertEquals(139, zp2.available())
assertFalse(50 in zp2.free)
assertFalse(100 in zp2.free)
@ -216,7 +216,7 @@ class TestC64Zeropage {
@Test
fun testBasicsafeAllocation() {
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true))
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, "c64"))
assertEquals(16, zp.available())
assertFailsWith<ZeropageDepletedError> {
@ -239,7 +239,7 @@ class TestC64Zeropage {
@Test
fun testFullAllocation() {
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false))
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, "c64"))
assertEquals(238, zp.available())
val loc = zp.allocate("", DataType.UWORD, null, errors)
assertTrue(loc > 3)
@ -269,7 +269,7 @@ class TestC64Zeropage {
@Test
fun testEfficientAllocation() {
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true))
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, "c64"))
assertEquals(16, zp.available())
assertEquals(0x04, zp.allocate("", DataType.WORD, null, errors))
assertEquals(0x06, zp.allocate("", DataType.UBYTE, null, errors))

View File

@ -33,6 +33,14 @@ This makes it easier to understand and relate the generated code. Examples::
Directives
-----------
.. data:: %target <target>
Level: module.
Global setting, selects a compilation target from within the source file.
The default compilation target is "c64" which targets the Commodore-64 machine.
You can also omit this and use the ``-target`` command line option.
.. data:: %output <type>
Level: module.

View File

@ -1,3 +1,4 @@
%target cx16
%import cx16flt
%import cx16textio
%zeropage basicsafe

View File

@ -1,3 +1,4 @@
%target cx16
%import cx16textio
%zeropage basicsafe

View File

@ -1,3 +1,4 @@
%target cx16
%import cx16flt
%import cx16textio
%zeropage basicsafe

View File

@ -1,3 +1,4 @@
%target cx16
%import cx16flt
%import cx16textio
%zeropage basicsafe

View File

@ -1,3 +1,4 @@
%target cx16
%import cx16flt
%import cx16textio
%zeropage basicsafe

View File

@ -1,3 +1,4 @@
%target cx16
%import cx16flt
%import cx16textio
%zeropage basicsafe

View File

@ -1,3 +1,4 @@
%target cx16
%import cx16flt
%import cx16textio
%zeropage basicsafe

View File

@ -1,3 +1,4 @@
%target cx16
%import cx16textio
%zeropage basicsafe

View File

@ -1,3 +1,4 @@
%target cx16
%import cx16flt
%import cx16textio
%zeropage basicsafe

View File

@ -1,3 +1,4 @@
%target cx16
%import cx16flt
%import cx16textio
%zeropage basicsafe

View File

@ -1,3 +1,4 @@
%target cx16
%import cx16lib
main {

View File

@ -1,3 +1,4 @@
%target cx16
%import cx16textio
main {

View File

@ -1,6 +1,7 @@
; CommanderX16 text datetime example!
; make sure to compile with the cx16 compiler target.
%target cx16
%import cx16textio
%zeropage basicsafe

View File

@ -1,3 +1,4 @@
%target cx16
%import cx16textio
%import cx16flt
%zeropage basicsafe

View File

@ -1,3 +1,4 @@
%target cx16
%import cx16textio
%import cx16flt
%zeropage basicsafe

View File

@ -1,6 +1,7 @@
; CommanderX16 simple graphics example!
; make sure to compile with the cx16 compiler target.
%target cx16
%zeropage basicsafe
main {

View File

@ -1,3 +1,4 @@
%target cx16
%import cx16textio
%import cx16flt
%zeropage basicsafe

View File

@ -1,3 +1,4 @@
%target cx16
%import cx16lib
%import cx16textio
%zeropage basicsafe

View File

@ -1,10 +1,9 @@
%target cx16
%import cx16textio
;%import c64flt
;%option enable_floats
; %zeropage kernalsafe
; TODO add a directive to set the compiler target
main {

View File

@ -126,7 +126,7 @@ unconditionaljump : 'goto' (integerliteral | scoped_identifier) ;
directive :
directivename=('%output' | '%launcher' | '%zeropage' | '%zpreserved' | '%address' | '%import' |
'%breakpoint' | '%asminclude' | '%asmbinary' | '%option')
'%breakpoint' | '%asminclude' | '%asmbinary' | '%option' | '%target' )
(directivearg? | directivearg (',' directivearg)*)
;