mirror of
https://github.com/irmen/prog8.git
synced 2024-11-25 19:31:36 +00:00
Merge branch 'master' into c128target
# Conflicts: # compiler/src/prog8/CompilerMain.kt # examples/test.p8
This commit is contained in:
commit
c15a75556d
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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")
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.")
|
||||||
|
@ -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()
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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()) {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
)
|
)
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
@ -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("}")
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
)
|
)
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
------------------------
|
------------------------
|
||||||
|
@ -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).
|
||||||
|
@ -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'
|
||||||
|
@ -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")
|
||||||
|
@ -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!")
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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())
|
||||||
|
Loading…
Reference in New Issue
Block a user