Merge branch 'master' into c128target

# Conflicts:
#	compiler/src/prog8/CompilerMain.kt
#	examples/test.p8
This commit is contained in:
Irmen de Jong 2021-12-30 18:22:05 +01:00
commit c15a75556d
26 changed files with 143 additions and 47 deletions

View File

@ -37,7 +37,8 @@ What does Prog8 provide?
- small program boilerplate/compilersupport overhead - small program boilerplate/compilersupport overhead
- programs can be run multiple times without reloading because of automatic variable (re)initializations. - programs can be run multiple times without reloading because of automatic variable (re)initializations.
- conditional branches - conditional branches
- 'when' statement to provide a concise jump table alternative to if/elseif chains - ``when`` statement to provide a concise jump table alternative to if/elseif chains
- ``in`` expression for concise and efficient multi-value/containment check
- many built-in functions such as ``sin``, ``cos``, ``rnd``, ``abs``, ``min``, ``max``, ``sqrt``, ``msb``, ``rol``, ``ror``, ``swap``, ``sort`` and ``reverse`` - many built-in functions such as ``sin``, ``cos``, ``rnd``, ``abs``, ``min``, ``max``, ``sqrt``, ``msb``, ``rol``, ``ror``, ``swap``, ``sort`` and ``reverse``
- various powerful built-in libraries to do I/O, number conversions, graphics and more - various powerful built-in libraries to do I/O, number conversions, graphics and more
- convenience abstractions for low level aspects such as ZeroPage handling, program startup, explicit memory addresses - convenience abstractions for low level aspects such as ZeroPage handling, program startup, explicit memory addresses

View File

@ -2,7 +2,7 @@ package prog8.codegen.target.c64
import prog8.ast.base.DataType import prog8.ast.base.DataType
import prog8.codegen.target.cbm.Mflpt5 import prog8.codegen.target.cbm.Mflpt5
import prog8.codegen.target.cbm.viceMonListPostfix import prog8.codegen.target.cbm.viceMonListName
import prog8.compilerinterface.* import prog8.compilerinterface.*
import java.io.IOException import java.io.IOException
import java.nio.file.Path import java.nio.file.Path
@ -42,7 +42,8 @@ class C64MachineDefinition: IMachineDefinition {
for(emulator in listOf("x64sc", "x64")) { for(emulator in listOf("x64sc", "x64")) {
println("\nStarting C-64 emulator $emulator...") println("\nStarting C-64 emulator $emulator...")
val cmdline = listOf(emulator, "-silent", "-moncommands", "${programNameWithPath}.$viceMonListPostfix", val viceMonlist = viceMonListName(programNameWithPath.toString())
val cmdline = listOf(emulator, "-silent", "-moncommands", viceMonlist,
"-autostartprgmode", "1", "-autostart-warp", "-autostart", "${programNameWithPath}.prg") "-autostartprgmode", "1", "-autostart-warp", "-autostart", "${programNameWithPath}.prg")
val processb = ProcessBuilder(cmdline).inheritIO() val processb = ProcessBuilder(cmdline).inheritIO()
val process: Process val process: Process

View File

@ -14,7 +14,7 @@ import kotlin.io.path.Path
import kotlin.io.path.isRegularFile import kotlin.io.path.isRegularFile
internal const val viceMonListPostfix = "vice-mon-list" internal fun viceMonListName(baseFilename: String) = "$baseFilename.vice-mon-list"
class AssemblyProgram( class AssemblyProgram(
override val valid: Boolean, override val valid: Boolean,
@ -25,17 +25,22 @@ class AssemblyProgram(
private val assemblyFile = outputDir.resolve("$name.asm") private val assemblyFile = outputDir.resolve("$name.asm")
private val prgFile = outputDir.resolve("$name.prg") private val prgFile = outputDir.resolve("$name.prg")
private val binFile = outputDir.resolve("$name.bin") private val binFile = outputDir.resolve("$name.bin")
private val viceMonListFile = outputDir.resolve("$name.$viceMonListPostfix") private val viceMonListFile = outputDir.resolve(viceMonListName(name))
private val listFile = outputDir.resolve("$name.list")
override fun assemble(quiet: Boolean, options: CompilationOptions): Int { override fun assemble(options: CompilationOptions): Int {
// add "-Wlong-branch" to see warnings about conversion of branch instructions to jumps (default = do this silently) // add "-Wlong-branch" to see warnings about conversion of branch instructions to jumps (default = do this silently)
val command = mutableListOf("64tass", "--ascii", "--case-sensitive", "--long-branch", val command = mutableListOf("64tass", "--ascii", "--case-sensitive", "--long-branch",
"-Wall", "-Wno-strict-bool", "-Wno-shadow", // "-Werror", "-Wall", "-Wno-strict-bool", "-Wno-shadow", // "-Werror",
"--dump-labels", "--vice-labels", "-l", viceMonListFile.toString(), "--no-monitor") "--dump-labels", "--vice-labels", "--labels=$viceMonListFile", "--no-monitor"
)
if(quiet) if(options.asmQuiet)
command.add("--quiet") command.add("--quiet")
if(options.asmListfile)
command.add("--list=$listFile")
val outFile = when (options.output) { val outFile = when (options.output) {
OutputType.PRG -> { OutputType.PRG -> {
command.add("--cbm-prg") command.add("--cbm-prg")

View File

@ -574,6 +574,26 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
asmgen.assignExpressionToRegister(value, RegisterOrPair.A) asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.out(" eor $name | sta $name") asmgen.out(" eor $name | sta $name")
} }
"==" -> {
asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.out("""
cmp $name
beq +
lda #0
beq ++
+ lda #1
+ sta $name""")
}
"!=" -> {
asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.out("""
cmp $name
beq +
lda #1
bne ++
+ lda #0
+ sta $name""")
}
else -> throw AssemblyError("invalid operator for in-place modification $operator") else -> throw AssemblyError("invalid operator for in-place modification $operator")
} }
} }
@ -631,6 +651,26 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
"&", "and" -> asmgen.out(" lda $name | and $otherName | sta $name") "&", "and" -> asmgen.out(" lda $name | and $otherName | sta $name")
"|", "or" -> asmgen.out(" lda $name | ora $otherName | sta $name") "|", "or" -> asmgen.out(" lda $name | ora $otherName | sta $name")
"^", "xor" -> asmgen.out(" lda $name | eor $otherName | sta $name") "^", "xor" -> asmgen.out(" lda $name | eor $otherName | sta $name")
"==" -> {
asmgen.out("""
lda $otherName
cmp $name
beq +
lda #0
bne ++
+ lda #1
+ sta $name""")
}
"!=" -> {
asmgen.out("""
lda $otherName
cmp $name
beq +
lda #1
bne ++
+ lda #0
+ sta $name""")
}
else -> throw AssemblyError("invalid operator for in-place modification $operator") else -> throw AssemblyError("invalid operator for in-place modification $operator")
} }
} }
@ -702,6 +742,26 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
"&", "and" -> asmgen.out(" lda $name | and #$value | sta $name") "&", "and" -> asmgen.out(" lda $name | and #$value | sta $name")
"|", "or" -> asmgen.out(" lda $name | ora #$value | sta $name") "|", "or" -> asmgen.out(" lda $name | ora #$value | sta $name")
"^", "xor" -> asmgen.out(" lda $name | eor #$value | sta $name") "^", "xor" -> asmgen.out(" lda $name | eor #$value | sta $name")
"==" -> {
asmgen.out("""
lda #$value
cmp $name
beq +
lda #0
bne ++
+ lda #1
+ sta $name""")
}
"!=" -> {
asmgen.out("""
lda #$value
cmp $name
beq +
lda #1
bne ++
+ lda #0
+ sta $name""")
}
else -> throw AssemblyError("invalid operator for in-place modification $operator") else -> throw AssemblyError("invalid operator for in-place modification $operator")
} }
} }

View File

@ -2,7 +2,7 @@ package prog8.codegen.target.cx16
import prog8.ast.base.DataType import prog8.ast.base.DataType
import prog8.codegen.target.cbm.Mflpt5 import prog8.codegen.target.cbm.Mflpt5
import prog8.codegen.target.cbm.viceMonListPostfix import prog8.codegen.target.cbm.viceMonListName
import prog8.compilerinterface.* import prog8.compilerinterface.*
import java.io.IOException import java.io.IOException
import java.nio.file.Path import java.nio.file.Path
@ -44,7 +44,7 @@ class CX16MachineDefinition: IMachineDefinition {
} }
2 -> { 2 -> {
emulatorName = "box16" emulatorName = "box16"
extraArgs = listOf("-sym", "${programNameWithPath}.$viceMonListPostfix") extraArgs = listOf("-sym", viceMonListName(programNameWithPath.toString()))
} }
else -> { else -> {
System.err.println("Cx16 target only supports x16emu and box16 emulators.") System.err.println("Cx16 target only supports x16emu and box16 emulators.")

View File

@ -45,7 +45,7 @@ X = BinExpr X = LeftExpr
*/ */
if(binExpr.operator in AugmentAssignmentOperators && isSimpleTarget(assignment.target)) { if(binExpr.operator in AugmentAssignmentOperators + listOf("==", "!=") && isSimpleTarget(assignment.target)) {
if(assignment.target isSameAs binExpr.right) if(assignment.target isSameAs binExpr.right)
return noModifications return noModifications
if(assignment.target isSameAs binExpr.left) { if(assignment.target isSameAs binExpr.left) {
@ -73,6 +73,15 @@ X = BinExpr X = LeftExpr
// ) // )
} }
if(binExpr.operator == "==" || binExpr.operator == "!=") {
// don't split if the operand(s) don't fit the type of the resulting variable
val targetDt = assignment.target.inferType(program)
val leftDt = binExpr.left.inferType(program)
val rightDt = binExpr.right.inferType(program)
if(leftDt isNotAssignableTo targetDt || rightDt isNotAssignableTo targetDt)
return noModifications
}
if(binExpr.right.isSimple) { if(binExpr.right.isSimple) {
val firstAssign = Assignment(assignment.target.copy(), binExpr.left, binExpr.left.position) val firstAssign = Assignment(assignment.target.copy(), binExpr.left, binExpr.left.position)
val targetExpr = assignment.target.toExpression() val targetExpr = assignment.target.toExpression()

View File

@ -41,6 +41,7 @@ private fun compileMain(args: Array<String>): Boolean {
val watchMode by cli.option(ArgType.Boolean, fullName = "watch", description = "continuous compilation mode (watches for file changes), greatly increases compilation speed") val watchMode by cli.option(ArgType.Boolean, fullName = "watch", description = "continuous compilation mode (watches for file changes), greatly increases compilation speed")
val slowCodegenWarnings by cli.option(ArgType.Boolean, fullName = "slowwarn", description="show debug warnings about slow/problematic assembly code generation") val slowCodegenWarnings by cli.option(ArgType.Boolean, fullName = "slowwarn", description="show debug warnings about slow/problematic assembly code generation")
val quietAssembler by cli.option(ArgType.Boolean, fullName = "quietasm", description = "don't print assembler output results") val quietAssembler by cli.option(ArgType.Boolean, fullName = "quietasm", description = "don't print assembler output results")
val asmListfile by cli.option(ArgType.Boolean, fullName = "asmlist", description = "make the assembler produce a listing file as well")
val compilationTarget by cli.option(ArgType.String, fullName = "target", description = "target output of the compiler (one of '${C64Target.name}', '${C128Target.name}', '${Cx16Target.name}')").default(C64Target.name) val compilationTarget by cli.option(ArgType.String, fullName = "target", description = "target output of the compiler (one of '${C64Target.name}', '${C128Target.name}', '${Cx16Target.name}')").default(C64Target.name)
val sourceDirs by cli.option(ArgType.String, fullName="srcdirs", description = "list of extra paths, separated with ${File.pathSeparator}, to search in for imported modules").multiple().delimiter(File.pathSeparator) val sourceDirs by cli.option(ArgType.String, fullName="srcdirs", description = "list of extra paths, separated with ${File.pathSeparator}, to search in for imported modules").multiple().delimiter(File.pathSeparator)
val moduleFiles by cli.argument(ArgType.String, fullName = "modules", description = "main module file(s) to compile").multiple(999) val moduleFiles by cli.argument(ArgType.String, fullName = "modules", description = "main module file(s) to compile").multiple(999)
@ -89,6 +90,7 @@ private fun compileMain(args: Array<String>): Boolean {
dontWriteAssembly != true, dontWriteAssembly != true,
slowCodegenWarnings == true, slowCodegenWarnings == true,
quietAssembler == true, quietAssembler == true,
asmListfile == true,
compilationTarget, compilationTarget,
srcdirs, srcdirs,
outputPath outputPath
@ -137,6 +139,7 @@ private fun compileMain(args: Array<String>): Boolean {
dontWriteAssembly != true, dontWriteAssembly != true,
slowCodegenWarnings == true, slowCodegenWarnings == true,
quietAssembler == true, quietAssembler == true,
asmListfile == true,
compilationTarget, compilationTarget,
srcdirs, srcdirs,
outputPath outputPath

View File

@ -35,6 +35,7 @@ class CompilerArguments(val filepath: Path,
val writeAssembly: Boolean, val writeAssembly: Boolean,
val slowCodegenWarnings: Boolean, val slowCodegenWarnings: Boolean,
val quietAssembler: Boolean, val quietAssembler: Boolean,
val asmListfile: Boolean,
val compilationTarget: String, val compilationTarget: String,
val sourceDirs: List<String> = emptyList(), val sourceDirs: List<String> = emptyList(),
val outputDir: Path = Path(""), val outputDir: Path = Path(""),
@ -61,14 +62,19 @@ fun compileProgram(args: CompilerArguments): CompilationResult {
// import main module and everything it needs // import main module and everything it needs
val (programresult, compilationOptions, imported) = parseImports(args.filepath, args.errors, compTarget, args.sourceDirs) val (programresult, compilationOptions, imported) = parseImports(args.filepath, args.errors, compTarget, args.sourceDirs)
with(compilationOptions) { with(compilationOptions) {
this.slowCodegenWarnings = args.slowCodegenWarnings slowCodegenWarnings = args.slowCodegenWarnings
this.optimize = args.optimize optimize = args.optimize
this.optimizeFloatExpressions = optimizeFloatExpr optimizeFloatExpressions = optimizeFloatExpr
asmQuiet = args.quietAssembler
asmListfile = args.asmListfile
} }
program = programresult program = programresult
importedFiles = imported importedFiles = imported
processAst(program, args.errors, compilationOptions) processAst(program, args.errors, compilationOptions)
if (compilationOptions.optimize) if (compilationOptions.optimize) {
// println("*********** AST RIGHT BEFORE OPTIMIZING *************")
// printProgram(program)
optimizeAst( optimizeAst(
program, program,
compilationOptions, compilationOptions,
@ -76,13 +82,14 @@ fun compileProgram(args: CompilerArguments): CompilationResult {
BuiltinFunctionsFacade(BuiltinFunctions), BuiltinFunctionsFacade(BuiltinFunctions),
compTarget compTarget
) )
}
postprocessAst(program, args.errors, compilationOptions) postprocessAst(program, args.errors, compilationOptions)
// println("*********** AST BEFORE ASSEMBLYGEN *************") // println("*********** AST BEFORE ASSEMBLYGEN *************")
// printProgram(program) // printProgram(program)
if (args.writeAssembly) { if (args.writeAssembly) {
when (val result = writeAssembly(program, args.errors, args.outputDir, args.quietAssembler, compilationOptions)) { when (val result = writeAssembly(program, args.errors, args.outputDir, compilationOptions)) {
is WriteAssemblyResult.Ok -> programName = result.filename is WriteAssemblyResult.Ok -> programName = result.filename
is WriteAssemblyResult.Fail -> { is WriteAssemblyResult.Fail -> {
System.err.println(result.error) System.err.println(result.error)
@ -324,7 +331,6 @@ private sealed class WriteAssemblyResult {
private fun writeAssembly(program: Program, private fun writeAssembly(program: Program,
errors: IErrorReporter, errors: IErrorReporter,
outputDir: Path, outputDir: Path,
quietAssembler: Boolean,
compilerOptions: CompilationOptions compilerOptions: CompilationOptions
): WriteAssemblyResult { ): WriteAssemblyResult {
// asm generation directly from the Ast // asm generation directly from the Ast
@ -344,7 +350,7 @@ private fun writeAssembly(program: Program,
errors.report() errors.report()
return if(assembly.valid && errors.noErrors()) { return if(assembly.valid && errors.noErrors()) {
val assemblerReturnStatus = assembly.assemble(quietAssembler, compilerOptions) val assemblerReturnStatus = assembly.assemble(compilerOptions)
if(assemblerReturnStatus!=0) if(assemblerReturnStatus!=0)
WriteAssemblyResult.Fail("assembler step failed with return code $assemblerReturnStatus") WriteAssemblyResult.Fail("assembler step failed with return code $assemblerReturnStatus")
else { else {

View File

@ -209,9 +209,9 @@ internal class ParentNodeChecker: AstWalker() {
return noModifications return noModifications
} }
override fun before(`when`: When, parent: Node): Iterable<IAstModification> { override fun before(whenStmt: When, parent: Node): Iterable<IAstModification> {
if(`when`.parent!==parent) if(whenStmt.parent!==parent)
throw FatalAstException("parent node mismatch at $`when`") throw FatalAstException("parent node mismatch at $whenStmt")
return noModifications return noModifications
} }

View File

@ -262,19 +262,19 @@ internal class StatementReorderer(val program: Program,
return noModifications return noModifications
} }
override fun after(`when`: When, parent: Node): Iterable<IAstModification> { override fun after(whenStmt: When, parent: Node): Iterable<IAstModification> {
val lastChoiceValues = `when`.choices.lastOrNull()?.values val lastChoiceValues = whenStmt.choices.lastOrNull()?.values
if(lastChoiceValues?.isNotEmpty()==true) { if(lastChoiceValues?.isNotEmpty()==true) {
val elseChoice = `when`.choices.indexOfFirst { it.values==null || it.values?.isEmpty()==true } val elseChoice = whenStmt.choices.indexOfFirst { it.values==null || it.values?.isEmpty()==true }
if(elseChoice>=0) if(elseChoice>=0)
errors.err("else choice must be the last one", `when`.choices[elseChoice].position) errors.err("else choice must be the last one", whenStmt.choices[elseChoice].position)
} }
val choices = `when`.choiceValues(program).sortedBy { val choices = whenStmt.choiceValues(program).sortedBy {
it.first?.first() ?: Int.MAX_VALUE it.first?.first() ?: Int.MAX_VALUE
} }
`when`.choices.clear() whenStmt.choices.clear()
choices.mapTo(`when`.choices) { it.second } choices.mapTo(whenStmt.choices) { it.second }
return noModifications return noModifications
} }
@ -448,8 +448,6 @@ internal class StatementReorderer(val program: Program,
return noModifications return noModifications
} else { } else {
// clobber risk; evaluate the arguments on the CPU stack first (in reverse order)... // clobber risk; evaluate the arguments on the CPU stack first (in reverse order)...
if (options.slowCodegenWarnings)
errors.warn("slow argument passing used to avoid register clobbering", call.position)
val argOrder = options.compTarget.asmsubArgsEvalOrder(function) val argOrder = options.compTarget.asmsubArgsEvalOrder(function)
val scope = AnonymousScope(mutableListOf(), call.position) val scope = AnonymousScope(mutableListOf(), call.position)
if(function.shouldSaveX()) { if(function.shouldSaveX()) {

View File

@ -99,7 +99,8 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter)
val rightBinExpr = expr.right as? BinaryExpression val rightBinExpr = expr.right as? BinaryExpression
if(leftBinExpr!=null && leftBinExpr.operator=="==" && rightBinExpr!=null && rightBinExpr.operator=="==") { if(leftBinExpr!=null && leftBinExpr.operator=="==" && rightBinExpr!=null && rightBinExpr.operator=="==") {
if(leftBinExpr.right is NumericLiteralValue && rightBinExpr.right is NumericLiteralValue) { if(leftBinExpr.right is NumericLiteralValue && rightBinExpr.right is NumericLiteralValue) {
errors.warn("consider using 'in' or 'when' to test for multiple values", expr.position) if(leftBinExpr.left isSameAs rightBinExpr.left)
errors.warn("consider using 'in' or 'when' to test for multiple values", expr.position)
} }
} }
} }

View File

@ -30,6 +30,7 @@ private fun compileTheThing(filepath: Path, optimize: Boolean, target: ICompilat
writeAssembly = true, writeAssembly = true,
slowCodegenWarnings = false, slowCodegenWarnings = false,
quietAssembler = true, quietAssembler = true,
asmListfile = false,
compilationTarget = target.name, compilationTarget = target.name,
outputDir = outputDir outputDir = outputDir
) )

View File

@ -44,6 +44,7 @@ class TestCompilerOptionSourcedirs: FunSpec({
writeAssembly = true, writeAssembly = true,
slowCodegenWarnings = false, slowCodegenWarnings = false,
quietAssembler = true, quietAssembler = true,
asmListfile = false,
compilationTarget = Cx16Target.name, compilationTarget = Cx16Target.name,
sourceDirs, sourceDirs,
outputDir outputDir

View File

@ -51,6 +51,7 @@ internal fun compileFile(
writeAssembly = writeAssembly, writeAssembly = writeAssembly,
slowCodegenWarnings = false, slowCodegenWarnings = false,
quietAssembler = true, quietAssembler = true,
asmListfile = false,
platform.name, platform.name,
outputDir = outputDir, outputDir = outputDir,
errors = errors ?: ErrorReporterForTests() errors = errors ?: ErrorReporterForTests()

View File

@ -428,12 +428,12 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program:
outputlni("}}") outputlni("}}")
} }
override fun visit(`when`: When) { override fun visit(whenStmt: When) {
output("when ") output("when ")
`when`.condition.accept(this) whenStmt.condition.accept(this)
outputln(" {") outputln(" {")
scopelevel++ scopelevel++
`when`.choices.forEach { it.accept(this) } whenStmt.choices.forEach { it.accept(this) }
scopelevel-- scopelevel--
outputlni("}") outputlni("}")
} }

View File

@ -1055,7 +1055,7 @@ class ContainmentCheck(var element: Expression,
override fun referencesIdentifier(nameInSource: List<String>): Boolean { override fun referencesIdentifier(nameInSource: List<String>): Boolean {
if(element is IdentifierReference) if(element is IdentifierReference)
return element.referencesIdentifier(nameInSource) return element.referencesIdentifier(nameInSource)
return iterable?.referencesIdentifier(nameInSource) ?: false return iterable.referencesIdentifier(nameInSource)
} }
override fun inferType(program: Program) = InferredTypes.knownFor(DataType.UBYTE) override fun inferType(program: Program) = InferredTypes.knownFor(DataType.UBYTE)

View File

@ -28,7 +28,7 @@ interface IAstVisitor {
fun visit(containment: ContainmentCheck) { fun visit(containment: ContainmentCheck) {
containment.element.accept(this) containment.element.accept(this)
containment.iterable?.accept(this) containment.iterable.accept(this)
} }
fun visit(block: Block) { fun visit(block: Block) {
@ -172,9 +172,9 @@ interface IAstVisitor {
fun visit(nop: Nop) { fun visit(nop: Nop) {
} }
fun visit(`when`: When) { fun visit(whenStmt: When) {
`when`.condition.accept(this) whenStmt.condition.accept(this)
`when`.choices.forEach { it.accept(this) } whenStmt.choices.forEach { it.accept(this) }
} }
fun visit(whenChoice: WhenChoice) { fun visit(whenChoice: WhenChoice) {

View File

@ -28,5 +28,7 @@ class CompilationOptions(val output: OutputType,
// these are set based on command line arguments: // these are set based on command line arguments:
var slowCodegenWarnings: Boolean = false, var slowCodegenWarnings: Boolean = false,
var optimize: Boolean = false, var optimize: Boolean = false,
var optimizeFloatExpressions: Boolean = false var optimizeFloatExpressions: Boolean = false,
var asmQuiet: Boolean = false,
var asmListfile: Boolean = false
) )

View File

@ -11,5 +11,5 @@ const val subroutineFloatEvalResultVar2 = "_prog8_float_eval_result2"
interface IAssemblyProgram { interface IAssemblyProgram {
val valid: Boolean val valid: Boolean
val name: String val name: String
fun assemble(quiet: Boolean, options: CompilationOptions): Int fun assemble(options: CompilationOptions): Int
} }

View File

@ -144,6 +144,9 @@ One or more .p8 module files
``-quietasm`` ``-quietasm``
Don't print assembler output results. Don't print assembler output results.
``-asmlist``
Generate an assembler listing file as well.
Module source code files Module source code files
------------------------ ------------------------

View File

@ -54,6 +54,9 @@ Language features
- Subroutines with parameters and return values - Subroutines with parameters and return values
- Complex nested expressions are possible - Complex nested expressions are possible
- Variables are allocated statically - Variables are allocated statically
- Conditional branches to map directly on processor branch instructions
- ``when`` statement to avoid if-else chains
- ``in`` expression for concise and efficient multi-value/containment test
- Nested subroutines can access variables from outer scopes to avoids the overhead to pass everything via parameters - Nested subroutines can access variables from outer scopes to avoids the overhead to pass everything via parameters
- Variable data types include signed and unsigned bytes and words, arrays, strings. - Variable data types include signed and unsigned bytes and words, arrays, strings.
- Floating point math also supported if the target system provides floating point library routines (C64 and Cx16 both do). - Floating point math also supported if the target system provides floating point library routines (C64 and Cx16 both do).

View File

@ -5,6 +5,7 @@ For next compiler release (7.6)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
... ...
Blocked by an official Commander-x16 v39 release Blocked by an official Commander-x16 v39 release
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- simplify cx16.joystick_get2() once this cx16 rom issue is resolved: https://github.com/commanderx16/x16-rom/issues/203 - simplify cx16.joystick_get2() once this cx16 rom issue is resolved: https://github.com/commanderx16/x16-rom/issues/203
@ -13,10 +14,10 @@ Blocked by an official Commander-x16 v39 release
Future Future
^^^^^^ ^^^^^^
- make some sort of "porting guide" with things required to support a new target platform
- make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as ``v_`` - make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as ``v_``
then we can get rid of the instruction lists in the machinedefinitions as well? then we can get rid of the instruction lists in the machinedefinitions as well?
- fix the asm-labels problem (github issue #62) - fix the asm-labels problem (github issue #62)
- make (an option) to let 64tass produce a listing file as well as output.
- simplifyConditionalExpression() should not split expression if it still results in stack-based evaluation - simplifyConditionalExpression() should not split expression if it still results in stack-based evaluation
- simplifyConditionalExpression() sometimes introduces needless assignment to r9 tempvar - simplifyConditionalExpression() sometimes introduces needless assignment to r9 tempvar
- get rid of all TODO's in the code - get rid of all TODO's in the code
@ -41,7 +42,6 @@ Future
More code optimization ideas More code optimization ideas
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- automatically convert if statements that test for multiple values (if X==1 or X==2..) to if X in [1,2,..] statements, instead of just a warning - automatically convert if statements that test for multiple values (if X==1 or X==2..) to if X in [1,2,..] statements, instead of just a warning
-
- byte typed expressions should be evaluated in the accumulator where possible, without (temp)var - byte typed expressions should be evaluated in the accumulator where possible, without (temp)var
for instance value = otherbyte >> 1 --> lda otherbite ; lsr a; sta value for instance value = otherbyte >> 1 --> lda otherbite ; lsr a; sta value
- rewrite expression tree evaluation such that it doesn't use an eval stack but flatten the tree into linear code that uses a fixed number of predetermined value 'variables' - rewrite expression tree evaluation such that it doesn't use an eval stack but flatten the tree into linear code that uses a fixed number of predetermined value 'variables'

View File

@ -8,7 +8,7 @@
main { main {
sub start() { sub start() {
cx16.screen_set_mode(0) void cx16.screen_set_mode(0)
txt.print("\n\n how many sprites does\n the commander x16 have?\n") txt.print("\n\n how many sprites does\n the commander x16 have?\n")
sys.wait(120) sys.wait(120)
txt.print("\n\n the manual says: '128'.\n") txt.print("\n\n the manual says: '128'.\n")

View File

@ -8,7 +8,7 @@
main { main {
sub start() { sub start() {
cx16.screen_set_mode(0) void cx16.screen_set_mode(0)
txt.plot(14,14) txt.plot(14,14)
txt.print("raster bars!") txt.print("raster bars!")

View File

@ -870,7 +870,7 @@ planet {
ubyte ni ubyte ni
for ni in 1 to len(name) { for ni in 1 to len(name) {
ubyte cc = name[ni] ubyte cc = name[ni]
if cc=='e' or cc=='o' or cc==0 if cc in ['e', 'o', 0]
break break
else { else {
@(result_ptr) = cc @(result_ptr) = cc

View File

@ -37,7 +37,8 @@ class RequestParser : Take {
writeAssembly = true, writeAssembly = true,
slowCodegenWarnings = true, slowCodegenWarnings = true,
compilationTarget = "c64", compilationTarget = "c64",
quietAssembler = false quietAssembler = false,
asmListfile = false
) )
val compilationResult = compileProgram(args) val compilationResult = compileProgram(args)
return RsJson(Jsonding()) return RsJson(Jsonding())