mirror of
https://github.com/irmen/prog8.git
synced 2025-08-09 19:25:22 +00:00
removed bogus clang target
fixed various simulator bugs regarding strings and chars
This commit is contained in:
@@ -33,6 +33,7 @@ dependencies {
|
|||||||
// implementation "org.jetbrains.kotlin:kotlin-reflect"
|
// implementation "org.jetbrains.kotlin:kotlin-reflect"
|
||||||
implementation 'org.antlr:antlr4-runtime:4.7.2'
|
implementation 'org.antlr:antlr4-runtime:4.7.2'
|
||||||
implementation 'org.jetbrains.kotlinx:kotlinx-cli-jvm:0.1.0-dev-5'
|
implementation 'org.jetbrains.kotlinx:kotlinx-cli-jvm:0.1.0-dev-5'
|
||||||
|
// implementation 'net.razorvine:ksim65:1.6'
|
||||||
implementation project(':parser')
|
implementation project(':parser')
|
||||||
|
|
||||||
testImplementation "org.jetbrains.kotlin:kotlin-test-junit5"
|
testImplementation "org.jetbrains.kotlin:kotlin-test-junit5"
|
||||||
|
@@ -7,8 +7,6 @@ import prog8.compiler.target.CompilationTarget
|
|||||||
import prog8.compiler.target.c64.C64MachineDefinition
|
import prog8.compiler.target.c64.C64MachineDefinition
|
||||||
import prog8.compiler.target.c64.Petscii
|
import prog8.compiler.target.c64.Petscii
|
||||||
import prog8.compiler.target.c64.codegen.AsmGen
|
import prog8.compiler.target.c64.codegen.AsmGen
|
||||||
import prog8.compiler.target.clang.ClangGen
|
|
||||||
import prog8.compiler.target.clang.ClangMachineDefinition
|
|
||||||
import prog8.parser.ParsingFailedError
|
import prog8.parser.ParsingFailedError
|
||||||
import prog8.vm.astvm.AstVm
|
import prog8.vm.astvm.AstVm
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
@@ -41,9 +39,9 @@ private fun compileMain(args: Array<String>) {
|
|||||||
val outputDir by cli.flagValueArgument("-out", "directory", "directory for output files instead of current directory", ".")
|
val outputDir by cli.flagValueArgument("-out", "directory", "directory for output files instead of current directory", ".")
|
||||||
val dontWriteAssembly by cli.flagArgument("-noasm", "don't create assembly code")
|
val dontWriteAssembly by cli.flagArgument("-noasm", "don't create assembly code")
|
||||||
val dontOptimize by cli.flagArgument("-noopt", "don't perform any optimizations")
|
val dontOptimize by cli.flagArgument("-noopt", "don't perform any optimizations")
|
||||||
val launchSimulator by cli.flagArgument("-sim", "launch the prog8 virtual machine/simulator after compilation")
|
val launchSimulator by cli.flagArgument("-sim", "launch the builtin execution simulator after compilation")
|
||||||
val watchMode by cli.flagArgument("-watch", "continuous compilation mode (watches for file changes)")
|
val watchMode by cli.flagArgument("-watch", "continuous compilation mode (watches for file changes), greatly increases compilation speed")
|
||||||
val compilationTarget by cli.flagValueArgument("-target", "compilationtgt", "target output of the compiler, one of: c64, clang. default=c64", "c64")
|
val compilationTarget by cli.flagValueArgument("-target", "compilertarget", "target output of the compiler, currently only 'c64' (C64 6502 assembly) available", "c64")
|
||||||
val moduleFiles by cli.positionalArgumentsList("modules", "main module file(s) to compile", minArgs = 1)
|
val moduleFiles by cli.positionalArgumentsList("modules", "main module file(s) to compile", minArgs = 1)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -61,14 +59,6 @@ private fun compileMain(args: Array<String>) {
|
|||||||
asmGenerator = ::AsmGen
|
asmGenerator = ::AsmGen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"clang" -> {
|
|
||||||
with(CompilationTarget) {
|
|
||||||
name = "clang"
|
|
||||||
machine = ClangMachineDefinition
|
|
||||||
encodeString = { str -> str.toByteArray().map { it.toShort()} }
|
|
||||||
asmGenerator = ::ClangGen
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> {
|
else -> {
|
||||||
System.err.println("invalid compilation target")
|
System.err.println("invalid compilation target")
|
||||||
exitProcess(1)
|
exitProcess(1)
|
||||||
@@ -124,6 +114,12 @@ private fun compileMain(args: Array<String>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (launchSimulator) {
|
if (launchSimulator) {
|
||||||
|
// val c64 = razorvine.c64emu.C64Machine("C64 emulator launched from Prog8 compiler")
|
||||||
|
// c64.cpu.addBreakpoint(0xea31) { cpu, address ->
|
||||||
|
// println("zz")
|
||||||
|
// Cpu6502.BreakpointResultAction()
|
||||||
|
// }
|
||||||
|
// c64.start()
|
||||||
println("\nLaunching AST-based simulator...")
|
println("\nLaunching AST-based simulator...")
|
||||||
val vm = AstVm(compilationResult.programAst, compilationTarget)
|
val vm = AstVm(compilationResult.programAst, compilationTarget)
|
||||||
vm.run()
|
vm.run()
|
||||||
|
@@ -1058,7 +1058,7 @@ object Petscii {
|
|||||||
0.toShort()
|
0.toShort()
|
||||||
else {
|
else {
|
||||||
val case = if (lowercase) "lower" else "upper"
|
val case = if (lowercase) "lower" else "upper"
|
||||||
throw CharConversionException("no ${case}case Petscii character for '$it'")
|
throw CharConversionException("no ${case}case Petscii character for '$it' (${it.toShort()})")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1076,7 +1076,7 @@ object Petscii {
|
|||||||
0.toShort()
|
0.toShort()
|
||||||
else {
|
else {
|
||||||
val case = if (lowercase) "lower" else "upper"
|
val case = if (lowercase) "lower" else "upper"
|
||||||
throw CharConversionException("no ${case}Screencode character for '$it'")
|
throw CharConversionException("no ${case}Screencode character for '$it' (${it.toShort()})")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,331 +0,0 @@
|
|||||||
package prog8.compiler.target.clang
|
|
||||||
|
|
||||||
import prog8.ast.Program
|
|
||||||
import prog8.ast.base.DataType
|
|
||||||
import prog8.ast.base.VarDeclType
|
|
||||||
import prog8.ast.expressions.*
|
|
||||||
import prog8.ast.statements.*
|
|
||||||
import prog8.compiler.AssemblyError
|
|
||||||
import prog8.compiler.CompilationOptions
|
|
||||||
import prog8.compiler.Zeropage
|
|
||||||
import prog8.compiler.target.IAssemblyGenerator
|
|
||||||
import prog8.compiler.target.IAssemblyProgram
|
|
||||||
import java.io.PrintWriter
|
|
||||||
import java.nio.file.Path
|
|
||||||
|
|
||||||
|
|
||||||
internal class ClangGen(private val program: Program,
|
|
||||||
private val zeropage: Zeropage,
|
|
||||||
private val options: CompilationOptions,
|
|
||||||
private val outputDir: Path) : IAssemblyGenerator {
|
|
||||||
override fun compileToAssembly(optimize: Boolean): IAssemblyProgram {
|
|
||||||
|
|
||||||
println("Generating C++ language code... [UNFINISHED, EXPERIMENTAL]")
|
|
||||||
|
|
||||||
// TODO manually flatten all scopes. Needed because in C++ even with forward declarations it's not possible to freely access members across all classes
|
|
||||||
|
|
||||||
val outputFile = outputDir.resolve("${program.name}.cpp").toFile()
|
|
||||||
outputFile.printWriter().use { out ->
|
|
||||||
header(out)
|
|
||||||
program.allBlocks().forEach { block(out, it) }
|
|
||||||
footer(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ClangAssemblyProgram(program.name, outputDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun header(out: PrintWriter) {
|
|
||||||
out.println("// c++ transpiled version of Prog8 program ${program.name}\n")
|
|
||||||
out.println("#include <cstdint>")
|
|
||||||
out.println("""
|
|
||||||
template <typename T,T iBegin,T iEnd,T iStep=1>
|
|
||||||
class _prog8_range {
|
|
||||||
public:
|
|
||||||
struct iterator {
|
|
||||||
T value;
|
|
||||||
iterator (T v) : value(v) {}
|
|
||||||
operator T () const { return value; }
|
|
||||||
operator T& () { return value; }
|
|
||||||
T operator* () const { return value; }
|
|
||||||
iterator& operator++ () { value += iStep; return *this; }
|
|
||||||
};
|
|
||||||
iterator begin() { return iBegin; }
|
|
||||||
iterator end() { return iEnd; }
|
|
||||||
};
|
|
||||||
|
|
||||||
void _prog8_inlineasm(const char* assembly) { /* nothing */ }
|
|
||||||
void _prog8_goto_addr(uint16_t addr) { /* nothing */ }
|
|
||||||
void _prog8_directive_asminclude(const char* module, const char* scopename) { /* nothing */ }
|
|
||||||
|
|
||||||
uint8_t _prog8_register_A = 0;
|
|
||||||
uint8_t _prog8_register_X = 0;
|
|
||||||
uint8_t _prog8_register_Y = 0;
|
|
||||||
|
|
||||||
uint8_t _prog8_memory[65536];
|
|
||||||
|
|
||||||
|
|
||||||
""")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun footer(out: PrintWriter) {
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun block(out: PrintWriter, block: Block) {
|
|
||||||
out.println("// block: $block")
|
|
||||||
out.println("class ${cname(block.name)} {")
|
|
||||||
out.println("\tconst char* _prog8_linepos = \"${block.position}\";")
|
|
||||||
out.print("\tvoid* _prog8_block_address = ")
|
|
||||||
if (block.address == null)
|
|
||||||
out.println("nullptr;")
|
|
||||||
else {
|
|
||||||
out.println("0x${block.address.toString(16)};")
|
|
||||||
}
|
|
||||||
out.println("public:")
|
|
||||||
block.statements.forEach { statement(out, it) }
|
|
||||||
out.println("};\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun statement(out: PrintWriter, stmt: Statement) {
|
|
||||||
when (stmt) {
|
|
||||||
is BuiltinFunctionStatementPlaceholder -> TODO("$stmt")
|
|
||||||
is Directive -> directive(out, stmt)
|
|
||||||
is Label -> out.println("${cname(stmt.name)}:")
|
|
||||||
is Return -> {
|
|
||||||
if (stmt.parent is Subroutine) {
|
|
||||||
if (stmt.value == null)
|
|
||||||
out.println("return;")
|
|
||||||
else {
|
|
||||||
out.println("return ${expression(stmt.value!!)};")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is Continue -> out.println("continue;")
|
|
||||||
is Break -> out.println("break;")
|
|
||||||
is VarDecl -> {
|
|
||||||
val sub = stmt.definingSubroutine()
|
|
||||||
if (sub == null || sub.parameters.all { it.name != stmt.name })
|
|
||||||
vardecl(out, stmt)
|
|
||||||
}
|
|
||||||
is Assignment -> assignment(out, stmt)
|
|
||||||
is PostIncrDecr -> out.println("${assigntarget(stmt.target)}${stmt.operator};")
|
|
||||||
is Jump -> jump(out, stmt)
|
|
||||||
is FunctionCallStatement -> out.println("${stmt.target.nameInSource.joinToString("::")}(${arguments(stmt.arglist)});")
|
|
||||||
is InlineAssembly -> {
|
|
||||||
val asmlines = stmt.assembly.lines().map { "\"$it\"" }.joinToString("\n")
|
|
||||||
out.println("_prog8_inlineasm($asmlines);")
|
|
||||||
}
|
|
||||||
is AnonymousScope -> {
|
|
||||||
out.println("{")
|
|
||||||
stmt.statements.forEach { statement(out, it) }
|
|
||||||
out.println("}")
|
|
||||||
}
|
|
||||||
is NopStatement -> out.println("// NOP")
|
|
||||||
is Subroutine -> {
|
|
||||||
if (stmt.isAsmSubroutine) {
|
|
||||||
out.println("// TODO ASM-SUBROUTINE: ${stmt.name} @ ${stmt.position}") // TODO
|
|
||||||
} else {
|
|
||||||
val returnType = datatype(stmt.returntypes.singleOrNull(), null)
|
|
||||||
val params = stmt.parameters.map {
|
|
||||||
val dt = datatype(it.type, null)
|
|
||||||
"${dt.first} ${cname(it.name)}${dt.second}"
|
|
||||||
}
|
|
||||||
val paramstr = params.joinToString(", ")
|
|
||||||
out.println("\nstatic ${returnType.first} ${cname(stmt.name)}${returnType.second}($paramstr) {")
|
|
||||||
out.println("\tconst char* _prog8_linepos = \"${stmt.position}\";")
|
|
||||||
stmt.statements.forEach { statement(out, it) }
|
|
||||||
out.println("}\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is IfStatement -> ifstatement(out, stmt)
|
|
||||||
is BranchStatement -> branchstatement(out, stmt)
|
|
||||||
is ForLoop -> forloop(out, stmt)
|
|
||||||
is WhileLoop -> whileloop(out, stmt)
|
|
||||||
is RepeatLoop -> repeatloop(out, stmt)
|
|
||||||
is WhenStatement -> out.println("// stmt: $stmt") // TODO
|
|
||||||
is StructDecl -> out.println("// stmt: $stmt") // TODO
|
|
||||||
else -> throw AssemblyError("c++ translation error: unexpected statement: $stmt")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun assignment(out: PrintWriter, assign: Assignment) {
|
|
||||||
val target = assigntarget(assign.target)
|
|
||||||
val operator = assign.aug_op ?: "="
|
|
||||||
out.println("$target $operator ${expression(assign.value)};")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun assigntarget(target: AssignTarget): String {
|
|
||||||
return when {
|
|
||||||
target.register!=null -> "_prog8_register_${target.register}"
|
|
||||||
target.identifier!=null -> expression(target.identifier!!)
|
|
||||||
target.memoryAddress!=null -> "(*(uint8_t*)${expression(target.memoryAddress.addressExpression)}) "
|
|
||||||
target.arrayindexed!=null -> expression(target.arrayindexed!!)
|
|
||||||
else -> "?????"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun jump(out: PrintWriter, jmp: Jump) {
|
|
||||||
when {
|
|
||||||
jmp.generatedLabel!=null -> out.println("goto ${jmp.generatedLabel};")
|
|
||||||
jmp.address!=null -> out.println("_prog8_goto_addr(${jmp.address.toString(16)});")
|
|
||||||
jmp.identifier!=null -> out.println("goto ${expression(jmp.identifier)};")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun forloop(out: PrintWriter, forlp: ForLoop) {
|
|
||||||
out.println("// forloop $forlp") // TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun repeatloop(out: PrintWriter, repeatLoop: RepeatLoop) {
|
|
||||||
out.println("do {")
|
|
||||||
statement(out, repeatLoop.body)
|
|
||||||
out.println("} while(!(${expression(repeatLoop.untilCondition)}));")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun whileloop(out: PrintWriter, whileLoop: WhileLoop) {
|
|
||||||
out.println("while(${expression(whileLoop.condition)}) {")
|
|
||||||
statement(out, whileLoop.body)
|
|
||||||
out.println("}")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun ifstatement(out: PrintWriter, ifs: IfStatement) {
|
|
||||||
out.println("if(${expression(ifs.condition)}) {")
|
|
||||||
statement(out, ifs.truepart)
|
|
||||||
if(ifs.elsepart.containsCodeOrVars()) {
|
|
||||||
out.println("} else {")
|
|
||||||
statement(out, ifs.elsepart)
|
|
||||||
}
|
|
||||||
out.println("}")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun branchstatement(out: PrintWriter, branch: BranchStatement) {
|
|
||||||
out.println("if(BranchFlag.${branch.condition}) {")
|
|
||||||
statement(out, branch.truepart)
|
|
||||||
if(branch.elsepart.containsCodeOrVars()) {
|
|
||||||
out.println("} else {")
|
|
||||||
statement(out, branch.elsepart)
|
|
||||||
}
|
|
||||||
out.println("}")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun directive(out: PrintWriter, dr: Directive) {
|
|
||||||
val args = dr.args.map {
|
|
||||||
when {
|
|
||||||
it.int!=null -> it.int.toString()
|
|
||||||
it.name!=null -> "\"${it.name}\""
|
|
||||||
it.str!=null -> "\"${it.str}\""
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out.println("_prog8_directive_${dr.directive.substring(1)}(${args.joinToString(", ")});")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun arguments(args: List<Expression>): String = args.map{expression(it)}.joinToString(", ")
|
|
||||||
|
|
||||||
private fun vardecl(out: PrintWriter, decl: VarDecl) {
|
|
||||||
fun cdecl(memory: Boolean) {
|
|
||||||
val dtype = datatype(decl.datatype, decl.arraysize)
|
|
||||||
out.print(dtype.first)
|
|
||||||
if (memory) {
|
|
||||||
out.print("* ${cname(decl.name)}")
|
|
||||||
} else {
|
|
||||||
out.print(" ${cname(decl.name)}${dtype.second}")
|
|
||||||
}
|
|
||||||
if (decl.value != null) {
|
|
||||||
// TODO c++ requires the value initialization to be done outside the class in a static assignment...
|
|
||||||
if (memory)
|
|
||||||
out.print(" = static_cast<${dtype.first}*>(${expression(decl.value!!)})")
|
|
||||||
else
|
|
||||||
out.print(" = ${expression(decl.value!!)}")
|
|
||||||
}
|
|
||||||
// TODO zeropage flag
|
|
||||||
out.println(";")
|
|
||||||
}
|
|
||||||
|
|
||||||
out.print("static ")
|
|
||||||
when (decl.type) {
|
|
||||||
VarDeclType.VAR -> {
|
|
||||||
cdecl(false)
|
|
||||||
}
|
|
||||||
VarDeclType.CONST -> {
|
|
||||||
out.print("constexpr const ")
|
|
||||||
cdecl(false)
|
|
||||||
}
|
|
||||||
VarDeclType.MEMORY -> {
|
|
||||||
out.print("constexpr const ")
|
|
||||||
cdecl(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun expression(expr: Expression): String {
|
|
||||||
return when (expr) {
|
|
||||||
is PrefixExpression -> "${expr.operator}${expression(expr.expression)}"
|
|
||||||
is BinaryExpression -> "${expression(expr.left)} ${expr.operator} ${expression(expr.right)}"
|
|
||||||
is ArrayIndexedExpression -> "${expression(expr.identifier)}[${expression(expr.arrayspec.index)}]"
|
|
||||||
is TypecastExpression -> "static_cast<${datatype(expr.type, null)}>(${expression(expr.expression)}) "
|
|
||||||
is AddressOf -> "&${expr.identifier.nameInSource.joinToString("::")}"
|
|
||||||
is DirectMemoryRead -> "_prog8_memory[${expression(expr.addressExpression)}]"
|
|
||||||
is NumericLiteralValue -> "${expr.number}"
|
|
||||||
is StructLiteralValue -> TODO("struct literal")
|
|
||||||
is StringLiteralValue -> "\"${expr.value}\""
|
|
||||||
is ArrayLiteralValue -> arrayliteral(expr)
|
|
||||||
is RangeExpr -> rangeexpr(expr)
|
|
||||||
is RegisterExpr -> "_prog8_register_${expr.register}"
|
|
||||||
is IdentifierReference -> expr.nameInSource.joinToString("::")
|
|
||||||
is FunctionCall -> functioncall(expr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun rangeexpr(range: RangeExpr): String {
|
|
||||||
val constrange = range.toConstantIntegerRange()
|
|
||||||
return if(constrange!=null) {
|
|
||||||
if(constrange.first>=0 && constrange.last>=0)
|
|
||||||
"_prog8_range<uint16_t, ${constrange.first}, ${constrange.last}, ${constrange.step}>()"
|
|
||||||
else
|
|
||||||
"_prog8_range<int16_t, ${constrange.first}, ${constrange.last}, ${constrange.step}>()"
|
|
||||||
} else {
|
|
||||||
TODO("rangeexpr $range")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun functioncall(fc: FunctionCall): String {
|
|
||||||
val args = fc.arglist.map { expression(it) }.joinToString(", ")
|
|
||||||
return "${expression(fc.target)}($args)"
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun arrayliteral(arraylv: ArrayLiteralValue): String {
|
|
||||||
val values = arraylv.value.map { expression(it) }.joinToString(", ")
|
|
||||||
return "{ $values }"
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun cname(name: String): String {
|
|
||||||
return if (name in listOf("char", "int", "short", "void")) name + "__c_" else name
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun datatype(dt: DataType?, arraysize: ArrayIndex?): Pair<String, String> {
|
|
||||||
return when (dt) {
|
|
||||||
DataType.UBYTE -> Pair("uint8_t", "")
|
|
||||||
DataType.BYTE -> Pair("int8_t", "")
|
|
||||||
DataType.UWORD -> Pair("uint16_t", "")
|
|
||||||
DataType.WORD -> Pair("int16_t", "")
|
|
||||||
DataType.FLOAT -> Pair("float", "")
|
|
||||||
DataType.STR -> Pair("const char*", "")
|
|
||||||
DataType.STR_S -> Pair("const char*", "")
|
|
||||||
DataType.ARRAY_UB -> if (arraysize == null) Pair("uint8_t", "[]") else Pair("uint8_t", "[${expression(arraysize.index)}]")
|
|
||||||
DataType.ARRAY_B -> if (arraysize == null) Pair("int8_t", "[]") else Pair("int8_t", "[${expression(arraysize.index)}]")
|
|
||||||
DataType.ARRAY_UW -> if (arraysize == null) Pair("uint16_t", "[]") else Pair("uint16_t", "[${expression(arraysize.index)}]")
|
|
||||||
DataType.ARRAY_W -> if (arraysize == null) Pair("int16_t", "[]") else Pair("int16_t", "[${expression(arraysize.index)}]")
|
|
||||||
DataType.ARRAY_F -> if (arraysize == null) Pair("float", "[]") else Pair("float", "[${expression(arraysize.index)}]")
|
|
||||||
DataType.STRUCT -> TODO("struct")
|
|
||||||
null -> Pair("void", "")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ClangAssemblyProgram(override val name: String, outputDir: Path) : IAssemblyProgram {
|
|
||||||
override fun assemble(options: CompilationOptions) {
|
|
||||||
println("TODO C++ COMPILE?")
|
|
||||||
TODO("not implemented - use g++ or clang to compile the code")
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,23 +0,0 @@
|
|||||||
package prog8.compiler.target.clang
|
|
||||||
|
|
||||||
import prog8.compiler.CompilationOptions
|
|
||||||
import prog8.compiler.Zeropage
|
|
||||||
import prog8.compiler.target.IMachineDefinition
|
|
||||||
import prog8.compiler.target.c64.C64MachineDefinition
|
|
||||||
|
|
||||||
object ClangMachineDefinition: IMachineDefinition {
|
|
||||||
override val FLOAT_MAX_NEGATIVE: Double = C64MachineDefinition.FLOAT_MAX_NEGATIVE
|
|
||||||
override val FLOAT_MAX_POSITIVE: Double = C64MachineDefinition.FLOAT_MAX_POSITIVE
|
|
||||||
override val FLOAT_MEM_SIZE: Int = C64MachineDefinition.FLOAT_MEM_SIZE
|
|
||||||
override val opcodeNames: Set<String> = C64MachineDefinition.opcodeNames
|
|
||||||
|
|
||||||
override fun getZeropage(compilerOptions: CompilationOptions): Zeropage = ClangZeropage(compilerOptions)
|
|
||||||
|
|
||||||
class ClangZeropage(options: CompilationOptions) : Zeropage(options) {
|
|
||||||
override val exitProgramStrategy: ExitProgramStrategy = ExitProgramStrategy.SYSTEM_RESET
|
|
||||||
init {
|
|
||||||
for (reserved in options.zpReserved)
|
|
||||||
reserve(reserved)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -6,7 +6,6 @@ import prog8.ast.base.WordDatatypes
|
|||||||
import prog8.ast.expressions.ArrayLiteralValue
|
import prog8.ast.expressions.ArrayLiteralValue
|
||||||
import prog8.ast.expressions.NumericLiteralValue
|
import prog8.ast.expressions.NumericLiteralValue
|
||||||
import prog8.ast.expressions.StringLiteralValue
|
import prog8.ast.expressions.StringLiteralValue
|
||||||
import prog8.compiler.target.CompilationTarget
|
|
||||||
import prog8.vm.astvm.VmExecutionException
|
import prog8.vm.astvm.VmExecutionException
|
||||||
import java.util.Objects
|
import java.util.Objects
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
@@ -594,7 +593,7 @@ class RuntimeValueString(type: DataType, val str: String, val heapId: Int?): Run
|
|||||||
return type == other.type && str == other.str
|
return type == other.type && str == other.str
|
||||||
}
|
}
|
||||||
|
|
||||||
fun iterator(): Iterator<Number> = CompilationTarget.encodeString(str).iterator()
|
fun iterator(): Iterator<Number> = str.map { it.toShort() }.iterator()
|
||||||
|
|
||||||
override fun numericValue(): Number {
|
override fun numericValue(): Number {
|
||||||
throw VmExecutionException("string is not a number")
|
throw VmExecutionException("string is not a number")
|
||||||
@@ -619,7 +618,7 @@ open class RuntimeValueArray(type: DataType, val array: Array<Number>, val heapI
|
|||||||
if (elt.value is NumericLiteralValue)
|
if (elt.value is NumericLiteralValue)
|
||||||
resultArray.add((elt.value as NumericLiteralValue).number.toInt())
|
resultArray.add((elt.value as NumericLiteralValue).number.toInt())
|
||||||
else {
|
else {
|
||||||
TODO("ADDRESSOF ${elt.value}")
|
resultArray.add((elt.hashCode())) // ...poor man's implementation of ADDRESSOF(array), it probably won't work very well
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RuntimeValueArray(array.type, resultArray.toTypedArray(), array.heapId!!)
|
RuntimeValueArray(array.type, resultArray.toTypedArray(), array.heapId!!)
|
||||||
|
@@ -8,10 +8,8 @@ import prog8.ast.expressions.IdentifierReference
|
|||||||
import prog8.ast.expressions.NumericLiteralValue
|
import prog8.ast.expressions.NumericLiteralValue
|
||||||
import prog8.ast.statements.*
|
import prog8.ast.statements.*
|
||||||
import prog8.compiler.target.c64.C64MachineDefinition
|
import prog8.compiler.target.c64.C64MachineDefinition
|
||||||
import prog8.compiler.target.c64.Petscii
|
|
||||||
import prog8.vm.*
|
import prog8.vm.*
|
||||||
import java.awt.EventQueue
|
import java.awt.EventQueue
|
||||||
import java.io.CharConversionException
|
|
||||||
import java.util.ArrayDeque
|
import java.util.ArrayDeque
|
||||||
import kotlin.NoSuchElementException
|
import kotlin.NoSuchElementException
|
||||||
import kotlin.concurrent.fixedRateTimer
|
import kotlin.concurrent.fixedRateTimer
|
||||||
@@ -184,7 +182,7 @@ class AstVm(val program: Program, compilationTarget: String) {
|
|||||||
if(address in 1024..2023) {
|
if(address in 1024..2023) {
|
||||||
// write to the screen matrix
|
// write to the screen matrix
|
||||||
val scraddr = address-1024
|
val scraddr = address-1024
|
||||||
dialog.canvas.setChar(scraddr % 40, scraddr / 40, value, 1)
|
dialog.canvas.setScreenChar(scraddr % 40, scraddr / 40, value, 1)
|
||||||
}
|
}
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
@@ -240,7 +238,7 @@ class AstVm(val program: Program, compilationTarget: String) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dialog.canvas.printText("\n<program ended>", true)
|
dialog.canvas.printAsciiText("\n<program ended>")
|
||||||
println("PROGRAM EXITED!")
|
println("PROGRAM EXITED!")
|
||||||
dialog.title = "PROGRAM EXITED"
|
dialog.title = "PROGRAM EXITED"
|
||||||
} catch (tx: VmTerminationException) {
|
} catch (tx: VmTerminationException) {
|
||||||
@@ -357,7 +355,7 @@ class AstVm(val program: Program, compilationTarget: String) {
|
|||||||
// swap cannot be implemented as a function, so inline it here
|
// swap cannot be implemented as a function, so inline it here
|
||||||
executeSwap(stmt)
|
executeSwap(stmt)
|
||||||
} else {
|
} else {
|
||||||
val args = evaluate(stmt.arglist).map { it as RuntimeValueNumeric }
|
val args = evaluate(stmt.arglist)
|
||||||
performBuiltinFunction(target.name, args, statusflags)
|
performBuiltinFunction(target.name, args, statusflags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -625,7 +623,7 @@ class AstVm(val program: Program, compilationTarget: String) {
|
|||||||
(array as RuntimeValueArray).array[index.integerValue()] = value.numericValue()
|
(array as RuntimeValueArray).array[index.integerValue()] = value.numericValue()
|
||||||
else if (array.type in StringDatatypes) {
|
else if (array.type in StringDatatypes) {
|
||||||
val indexInt = index.integerValue()
|
val indexInt = index.integerValue()
|
||||||
val newchr = Petscii.decodePetscii(listOf(value.numericValue().toShort()), true)
|
val newchr = value.numericValue().toChar().toString()
|
||||||
val newstr = (array as RuntimeValueString).str.replaceRange(indexInt, indexInt + 1, newchr)
|
val newstr = (array as RuntimeValueString).str.replaceRange(indexInt, indexInt + 1, newchr)
|
||||||
val ident = contextStmt.definingScope().lookup(targetArrayIndexed.identifier.nameInSource, contextStmt) as? VarDecl
|
val ident = contextStmt.definingScope().lookup(targetArrayIndexed.identifier.nameInSource, contextStmt) as? VarDecl
|
||||||
?: throw VmExecutionException("can't find assignment target ${target.identifier}")
|
?: throw VmExecutionException("can't find assignment target ${target.identifier}")
|
||||||
@@ -672,48 +670,48 @@ class AstVm(val program: Program, compilationTarget: String) {
|
|||||||
"c64scr.print" -> {
|
"c64scr.print" -> {
|
||||||
// if the argument is an UWORD, consider it to be the "address" of the string (=heapId)
|
// if the argument is an UWORD, consider it to be the "address" of the string (=heapId)
|
||||||
if (args[0].wordval != null) {
|
if (args[0].wordval != null) {
|
||||||
val encodedStr = getEncodedStringFromRuntimeVars(args[0].wordval!!)
|
val string = getAsciiStringFromRuntimeVars(args[0].wordval!!)
|
||||||
dialog.canvas.printText(encodedStr)
|
dialog.canvas.printAsciiText(string)
|
||||||
} else
|
} else
|
||||||
throw VmExecutionException("print non-heap string")
|
throw VmExecutionException("print non-heap string")
|
||||||
}
|
}
|
||||||
"c64scr.print_ub" -> {
|
"c64scr.print_ub" -> {
|
||||||
dialog.canvas.printText(args[0].byteval!!.toString(), true)
|
dialog.canvas.printAsciiText(args[0].byteval!!.toString())
|
||||||
}
|
}
|
||||||
"c64scr.print_ub0" -> {
|
"c64scr.print_ub0" -> {
|
||||||
dialog.canvas.printText("%03d".format(args[0].byteval!!), true)
|
dialog.canvas.printAsciiText("%03d".format(args[0].byteval!!))
|
||||||
}
|
}
|
||||||
"c64scr.print_b" -> {
|
"c64scr.print_b" -> {
|
||||||
dialog.canvas.printText(args[0].byteval!!.toString(), true)
|
dialog.canvas.printAsciiText(args[0].byteval!!.toString())
|
||||||
}
|
}
|
||||||
"c64scr.print_uw" -> {
|
"c64scr.print_uw" -> {
|
||||||
dialog.canvas.printText(args[0].wordval!!.toString(), true)
|
dialog.canvas.printAsciiText(args[0].wordval!!.toString())
|
||||||
}
|
}
|
||||||
"c64scr.print_uw0" -> {
|
"c64scr.print_uw0" -> {
|
||||||
dialog.canvas.printText("%05d".format(args[0].wordval!!), true)
|
dialog.canvas.printAsciiText("%05d".format(args[0].wordval!!))
|
||||||
}
|
}
|
||||||
"c64scr.print_w" -> {
|
"c64scr.print_w" -> {
|
||||||
dialog.canvas.printText(args[0].wordval!!.toString(), true)
|
dialog.canvas.printAsciiText(args[0].wordval!!.toString())
|
||||||
}
|
}
|
||||||
"c64scr.print_ubhex" -> {
|
"c64scr.print_ubhex" -> {
|
||||||
val number = args[0].byteval!!
|
val number = args[0].byteval!!
|
||||||
val prefix = if (args[1].asBoolean) "$" else ""
|
val prefix = if (args[1].asBoolean) "$" else ""
|
||||||
dialog.canvas.printText("$prefix${number.toString(16).padStart(2, '0')}", true)
|
dialog.canvas.printAsciiText("$prefix${number.toString(16).padStart(2, '0')}")
|
||||||
}
|
}
|
||||||
"c64scr.print_uwhex" -> {
|
"c64scr.print_uwhex" -> {
|
||||||
val number = args[0].wordval!!
|
val number = args[0].wordval!!
|
||||||
val prefix = if (args[1].asBoolean) "$" else ""
|
val prefix = if (args[1].asBoolean) "$" else ""
|
||||||
dialog.canvas.printText("$prefix${number.toString(16).padStart(4, '0')}", true)
|
dialog.canvas.printAsciiText("$prefix${number.toString(16).padStart(4, '0')}")
|
||||||
}
|
}
|
||||||
"c64scr.print_uwbin" -> {
|
"c64scr.print_uwbin" -> {
|
||||||
val number = args[0].wordval!!
|
val number = args[0].wordval!!
|
||||||
val prefix = if (args[1].asBoolean) "%" else ""
|
val prefix = if (args[1].asBoolean) "%" else ""
|
||||||
dialog.canvas.printText("$prefix${number.toString(2).padStart(16, '0')}", true)
|
dialog.canvas.printAsciiText("$prefix${number.toString(2).padStart(16, '0')}")
|
||||||
}
|
}
|
||||||
"c64scr.print_ubbin" -> {
|
"c64scr.print_ubbin" -> {
|
||||||
val number = args[0].byteval!!
|
val number = args[0].byteval!!
|
||||||
val prefix = if (args[1].asBoolean) "%" else ""
|
val prefix = if (args[1].asBoolean) "%" else ""
|
||||||
dialog.canvas.printText("$prefix${number.toString(2).padStart(8, '0')}", true)
|
dialog.canvas.printAsciiText("$prefix${number.toString(2).padStart(8, '0')}")
|
||||||
}
|
}
|
||||||
"c64scr.clear_screenchars" -> {
|
"c64scr.clear_screenchars" -> {
|
||||||
dialog.canvas.clearScreen(6)
|
dialog.canvas.clearScreen(6)
|
||||||
@@ -722,7 +720,7 @@ class AstVm(val program: Program, compilationTarget: String) {
|
|||||||
dialog.canvas.clearScreen(args[0].integerValue().toShort())
|
dialog.canvas.clearScreen(args[0].integerValue().toShort())
|
||||||
}
|
}
|
||||||
"c64scr.setcc" -> {
|
"c64scr.setcc" -> {
|
||||||
dialog.canvas.setChar(args[0].integerValue(), args[1].integerValue(), args[2].integerValue().toShort(), args[3].integerValue().toShort())
|
dialog.canvas.setScreenChar(args[0].integerValue(), args[1].integerValue(), args[2].integerValue().toShort(), args[3].integerValue().toShort())
|
||||||
}
|
}
|
||||||
"c64scr.plot" -> {
|
"c64scr.plot" -> {
|
||||||
dialog.canvas.setCursorPos(args[0].integerValue(), args[1].integerValue())
|
dialog.canvas.setCursorPos(args[0].integerValue(), args[1].integerValue())
|
||||||
@@ -738,27 +736,23 @@ class AstVm(val program: Program, compilationTarget: String) {
|
|||||||
break
|
break
|
||||||
else {
|
else {
|
||||||
input.add(char)
|
input.add(char)
|
||||||
val printChar = try {
|
dialog.canvas.printAscii(char)
|
||||||
Petscii.encodePetscii("" + char, true).first()
|
|
||||||
} catch (cv: CharConversionException) {
|
|
||||||
0x3f.toShort()
|
|
||||||
}
|
|
||||||
dialog.canvas.printPetscii(printChar)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val inputStr = input.joinToString("")
|
var inputStr = input.joinToString("")
|
||||||
|
val inputLength = inputStr.length
|
||||||
val heapId = args[0].wordval!!
|
val heapId = args[0].wordval!!
|
||||||
val origStrLength = getEncodedStringFromRuntimeVars(heapId).size
|
val origStrLength = getAsciiStringFromRuntimeVars(heapId).length
|
||||||
val encodedStr = Petscii.encodePetscii(inputStr, true).take(origStrLength).toMutableList()
|
while(inputStr.length < origStrLength) {
|
||||||
while(encodedStr.size < origStrLength)
|
inputStr += '\u0000'
|
||||||
encodedStr.add(0)
|
}
|
||||||
result = RuntimeValueNumeric(DataType.UBYTE, encodedStr.indexOf(0))
|
result = RuntimeValueNumeric(DataType.UBYTE, inputLength)
|
||||||
}
|
}
|
||||||
"c64flt.print_f" -> {
|
"c64flt.print_f" -> {
|
||||||
dialog.canvas.printText(args[0].floatval.toString(), false)
|
dialog.canvas.printAsciiText(args[0].floatval.toString())
|
||||||
}
|
}
|
||||||
"c64.CHROUT" -> {
|
"c64.CHROUT" -> {
|
||||||
dialog.canvas.printPetscii(args[0].byteval!!)
|
dialog.canvas.printAscii(args[0].byteval!!.toChar())
|
||||||
}
|
}
|
||||||
"c64.CLEARSCR" -> {
|
"c64.CLEARSCR" -> {
|
||||||
dialog.canvas.clearScreen(6)
|
dialog.canvas.clearScreen(6)
|
||||||
@@ -770,9 +764,16 @@ class AstVm(val program: Program, compilationTarget: String) {
|
|||||||
val char=dialog.keyboardBuffer.pop()
|
val char=dialog.keyboardBuffer.pop()
|
||||||
result = RuntimeValueNumeric(DataType.UBYTE, char.toShort())
|
result = RuntimeValueNumeric(DataType.UBYTE, char.toShort())
|
||||||
}
|
}
|
||||||
|
"c64.GETIN" -> {
|
||||||
|
Thread.sleep(1)
|
||||||
|
result = if(dialog.keyboardBuffer.isEmpty())
|
||||||
|
RuntimeValueNumeric(DataType.UBYTE, 0)
|
||||||
|
else
|
||||||
|
RuntimeValueNumeric(DataType.UBYTE, dialog.keyboardBuffer.pop().toShort())
|
||||||
|
}
|
||||||
"c64utils.str2uword" -> {
|
"c64utils.str2uword" -> {
|
||||||
val heapId = args[0].wordval!!
|
val heapId = args[0].wordval!!
|
||||||
val argString = getEncodedStringFromRuntimeVars(heapId)
|
val argString = getAsciiStringFromRuntimeVars(heapId)
|
||||||
val numericpart = argString.takeWhile { it.toChar().isDigit() }.toString()
|
val numericpart = argString.takeWhile { it.toChar().isDigit() }.toString()
|
||||||
result = RuntimeValueNumeric(DataType.UWORD, numericpart.toInt() and 65535)
|
result = RuntimeValueNumeric(DataType.UWORD, numericpart.toInt() and 65535)
|
||||||
}
|
}
|
||||||
@@ -782,11 +783,10 @@ class AstVm(val program: Program, compilationTarget: String) {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getEncodedStringFromRuntimeVars(heapId: Int): List<Short> {
|
private fun getAsciiStringFromRuntimeVars(heapId: Int): String {
|
||||||
val stringvar = runtimeVariables.getByHeapId(heapId) as RuntimeValueString
|
val stringvar = runtimeVariables.getByHeapId(heapId) as RuntimeValueString
|
||||||
return when {
|
return when (stringvar.type) {
|
||||||
stringvar.type==DataType.STR -> Petscii.encodePetscii(stringvar.str, true)
|
DataType.STR, DataType.STR_S -> stringvar.str
|
||||||
stringvar.type==DataType.STR_S -> Petscii.encodeScreencode(stringvar.str, true)
|
|
||||||
else -> throw VmExecutionException("weird string type")
|
else -> throw VmExecutionException("weird string type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,6 +6,7 @@ import java.awt.*
|
|||||||
import java.awt.event.KeyEvent
|
import java.awt.event.KeyEvent
|
||||||
import java.awt.event.KeyListener
|
import java.awt.event.KeyListener
|
||||||
import java.awt.image.BufferedImage
|
import java.awt.image.BufferedImage
|
||||||
|
import java.io.CharConversionException
|
||||||
import java.util.ArrayDeque
|
import java.util.ArrayDeque
|
||||||
import javax.swing.JFrame
|
import javax.swing.JFrame
|
||||||
import javax.swing.JPanel
|
import javax.swing.JPanel
|
||||||
@@ -63,28 +64,22 @@ class BitmapScreenPanel : KeyListener, JPanel() {
|
|||||||
g2d.drawLine(x1, y1, x2, y2)
|
g2d.drawLine(x1, y1, x2, y2)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun printText(text: String, lowercase: Boolean, inverseVideo: Boolean=false) {
|
fun printAsciiText(text: String) {
|
||||||
val t2 = text.substringBefore(0.toChar())
|
val t2 = text.substringBefore(0.toChar())
|
||||||
val lines = t2.split('\n')
|
val lines = t2.split('\n')
|
||||||
for(line in lines.withIndex()) {
|
for(line in lines.withIndex()) {
|
||||||
val petscii = Petscii.encodePetscii(line.value, lowercase)
|
line.value.forEach { printAscii(it) }
|
||||||
petscii.forEach { printPetscii(it, inverseVideo) }
|
if(line.index<lines.size-1)
|
||||||
if(line.index<lines.size-1) {
|
printAscii('\n')
|
||||||
printPetscii(13) // newline
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun printText(text: Iterable<Short>) {
|
fun printAscii(char: Char) {
|
||||||
text.forEach { printPetscii(it, false) }
|
if(char=='\n' || char=='\u008d') {
|
||||||
}
|
|
||||||
|
|
||||||
fun printPetscii(char: Short, inverseVideo: Boolean=false) {
|
|
||||||
if(char==13.toShort() || char==141.toShort()) {
|
|
||||||
cursorX=0
|
cursorX=0
|
||||||
cursorY++
|
cursorY++
|
||||||
} else {
|
} else {
|
||||||
setPetscii(cursorX, cursorY, char, 1, inverseVideo)
|
setAsciiChar(cursorX, cursorY, char, 1)
|
||||||
cursorX++
|
cursorX++
|
||||||
if (cursorX >= (SCREENWIDTH / 8)) {
|
if (cursorX >= (SCREENWIDTH / 8)) {
|
||||||
cursorY++
|
cursorY++
|
||||||
@@ -105,28 +100,32 @@ class BitmapScreenPanel : KeyListener, JPanel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun writeTextAt(x: Int, y: Int, text: String, color: Short, lowercase: Boolean, inverseVideo: Boolean=false) {
|
fun writeAsciiTextAt(x: Int, y: Int, text: String, color: Short) {
|
||||||
val colorIdx = (color % C64MachineDefinition.colorPalette.size).toShort()
|
val colorIdx = (color % C64MachineDefinition.colorPalette.size).toShort()
|
||||||
var xx=x
|
var xx=x
|
||||||
for(clearx in xx until xx+text.length) {
|
for(clearx in xx until xx+text.length) {
|
||||||
g2d.clearRect(8*clearx, 8*y, 8, 8)
|
g2d.clearRect(8*clearx, 8*y, 8, 8)
|
||||||
}
|
}
|
||||||
for(sc in Petscii.encodePetscii(text, lowercase)) {
|
for(c in text) {
|
||||||
if(sc==0.toShort())
|
if(c=='\u0000')
|
||||||
break
|
break
|
||||||
setPetscii(xx++, y, sc, colorIdx, inverseVideo)
|
setAsciiChar(xx++, y, c, colorIdx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setPetscii(x: Int, y: Int, petscii: Short, color: Short, inverseVideo: Boolean) {
|
fun setAsciiChar(x: Int, y: Int, char: Char, color: Short) {
|
||||||
g2d.clearRect(8*x, 8*y, 8, 8)
|
g2d.clearRect(8*x, 8*y, 8, 8)
|
||||||
val colorIdx = (color % C64MachineDefinition.colorPalette.size).toShort()
|
val colorIdx = (color % C64MachineDefinition.colorPalette.size).toShort()
|
||||||
val screencode = Petscii.petscii2scr(petscii, inverseVideo)
|
val screencode = try {
|
||||||
|
Petscii.encodeScreencode(char.toString(), true)[0]
|
||||||
|
} catch (x: CharConversionException) {
|
||||||
|
'?'.toShort()
|
||||||
|
}
|
||||||
val coloredImage = C64MachineDefinition.Charset.getColoredChar(screencode, colorIdx)
|
val coloredImage = C64MachineDefinition.Charset.getColoredChar(screencode, colorIdx)
|
||||||
g2d.drawImage(coloredImage, 8*x, 8*y , null)
|
g2d.drawImage(coloredImage, 8*x, 8*y , null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setChar(x: Int, y: Int, screencode: Short, color: Short) {
|
fun setScreenChar(x: Int, y: Int, screencode: Short, color: Short) {
|
||||||
g2d.clearRect(8*x, 8*y, 8, 8)
|
g2d.clearRect(8*x, 8*y, 8, 8)
|
||||||
val colorIdx = (color % C64MachineDefinition.colorPalette.size).toShort()
|
val colorIdx = (color % C64MachineDefinition.colorPalette.size).toShort()
|
||||||
val coloredImage = C64MachineDefinition.Charset.getColoredChar(screencode, colorIdx)
|
val coloredImage = C64MachineDefinition.Charset.getColoredChar(screencode, colorIdx)
|
||||||
|
@@ -23,7 +23,7 @@ main {
|
|||||||
|
|
||||||
; use indexed loop to write characters
|
; use indexed loop to write characters
|
||||||
str bye = "Goodbye!\n"
|
str bye = "Goodbye!\n"
|
||||||
for char in 0 to len(bye)
|
for char in 0 to len(bye)-1
|
||||||
c64.CHROUT(bye[char])
|
c64.CHROUT(bye[char])
|
||||||
|
|
||||||
|
|
||||||
@@ -40,6 +40,8 @@ main {
|
|||||||
c64.CHROUT(':')
|
c64.CHROUT(':')
|
||||||
c64flt.print_f(clock_seconds)
|
c64flt.print_f(clock_seconds)
|
||||||
c64.CHROUT('\n')
|
c64.CHROUT('\n')
|
||||||
|
|
||||||
|
c64scr.print("bye!\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,10 +1,15 @@
|
|||||||
|
%import c64lib
|
||||||
%import c64flt
|
%import c64flt
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
%option enable_floats
|
%option enable_floats
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
|
||||||
|
; this is only a parser/compiler test, there's no actual working program
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
|
c64scr.print("this is only a parser/compiler test\n")
|
||||||
|
return
|
||||||
|
|
||||||
str s1 = "irmen"
|
str s1 = "irmen"
|
||||||
str_s s2 = "hello"
|
str_s s2 = "hello"
|
||||||
|
@@ -2,5 +2,3 @@ org.gradle.caching=true
|
|||||||
org.gradle.console=rich
|
org.gradle.console=rich
|
||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
org.gradle.daemon=true
|
org.gradle.daemon=true
|
||||||
|
|
||||||
kotlinVersion=1.3.61
|
|
||||||
|
Reference in New Issue
Block a user