diff --git a/build.gradle b/build.gradle index c122ddb22..b048f783a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,3 @@ plugins { - id "org.jetbrains.kotlin.jvm" version "1.5.20" apply false + id "org.jetbrains.kotlin.jvm" version "1.5.30" apply false } diff --git a/compiler/res/prog8lib/c64/floats.p8 b/compiler/res/prog8lib/c64/floats.p8 index 7d8ee5d29..417e9faf5 100644 --- a/compiler/res/prog8lib/c64/floats.p8 +++ b/compiler/res/prog8lib/c64/floats.p8 @@ -4,7 +4,6 @@ ; ; indent format: TABS, size=8 -%target c64 %option enable_floats floats { diff --git a/compiler/res/prog8lib/c64/graphics.p8 b/compiler/res/prog8lib/c64/graphics.p8 index 4593cf563..c41e3d6f4 100644 --- a/compiler/res/prog8lib/c64/graphics.p8 +++ b/compiler/res/prog8lib/c64/graphics.p8 @@ -1,4 +1,3 @@ -%target c64 %import textio ; bitmap pixel graphics module for the C64 diff --git a/compiler/res/prog8lib/c64/syslib.p8 b/compiler/res/prog8lib/c64/syslib.p8 index 56cce7440..ba58ef10d 100644 --- a/compiler/res/prog8lib/c64/syslib.p8 +++ b/compiler/res/prog8lib/c64/syslib.p8 @@ -5,8 +5,6 @@ ; ; indent format: TABS, size=8 -%target c64 - c64 { &ubyte TIME_HI = $a0 ; software jiffy clock, hi byte &ubyte TIME_MID = $a1 ; .. mid byte @@ -502,11 +500,9 @@ sys { ; --- busy wait till the next vsync has occurred (approximately), without depending on custom irq handling. ; note: a more accurate way to wait for vsync is to set up a vsync irq handler instead. %asm {{ -- lda c64.RASTER - beq - -- lda c64.RASTER - bne - - bit c64.SCROLY +- bit c64.SCROLY + bpl - +- bit c64.SCROLY bmi - rts }} diff --git a/compiler/res/prog8lib/c64/textio.p8 b/compiler/res/prog8lib/c64/textio.p8 index 661403f8e..118d3fa71 100644 --- a/compiler/res/prog8lib/c64/textio.p8 +++ b/compiler/res/prog8lib/c64/textio.p8 @@ -4,7 +4,6 @@ ; ; indent format: TABS, size=8 -%target c64 %import syslib %import conv diff --git a/compiler/res/prog8lib/cx16/floats.p8 b/compiler/res/prog8lib/cx16/floats.p8 index 9400a2af2..a9a0df938 100644 --- a/compiler/res/prog8lib/cx16/floats.p8 +++ b/compiler/res/prog8lib/cx16/floats.p8 @@ -4,7 +4,6 @@ ; ; indent format: TABS, size=8 -%target cx16 %option enable_floats floats { diff --git a/compiler/res/prog8lib/cx16/gfx2.p8 b/compiler/res/prog8lib/cx16/gfx2.p8 index 4842a2f02..37fdf6eba 100644 --- a/compiler/res/prog8lib/cx16/gfx2.p8 +++ b/compiler/res/prog8lib/cx16/gfx2.p8 @@ -1,5 +1,3 @@ -%target cx16 - ; Bitmap pixel graphics routines for the CommanderX16 ; Custom routines to use the full-screen 640x480 and 320x240 screen modes. ; (These modes are not supported by the documented GRAPH_xxxx kernal routines) diff --git a/compiler/res/prog8lib/cx16/graphics.p8 b/compiler/res/prog8lib/cx16/graphics.p8 index 09679bff0..f8cb55b1f 100644 --- a/compiler/res/prog8lib/cx16/graphics.p8 +++ b/compiler/res/prog8lib/cx16/graphics.p8 @@ -1,4 +1,3 @@ -%target cx16 %import syslib %import textio diff --git a/compiler/res/prog8lib/cx16/palette.p8 b/compiler/res/prog8lib/cx16/palette.p8 index 4a4e184e0..b2a1a5dd9 100644 --- a/compiler/res/prog8lib/cx16/palette.p8 +++ b/compiler/res/prog8lib/cx16/palette.p8 @@ -1,5 +1,3 @@ -%target cx16 - ; Manipulate the Commander X16's display color palette. ; Should you want to restore the default palette, you have to reinitialize the Vera yourself. @@ -9,7 +7,7 @@ palette { ubyte c sub set_color(ubyte index, uword color) { - vera_palette_ptr = $fa00+index*2 + vera_palette_ptr = $fa00+(index as uword * 2) cx16.vpoke(1, vera_palette_ptr, lsb(color)) vera_palette_ptr++ cx16.vpoke(1, vera_palette_ptr, msb(color)) @@ -70,11 +68,11 @@ palette { } } - inline sub set_all_black() { + sub set_all_black() { set_monochrome($000, $000) } - inline sub set_all_white() { + sub set_all_white() { set_monochrome($fff, $fff) } diff --git a/compiler/res/prog8lib/cx16/syslib.p8 b/compiler/res/prog8lib/cx16/syslib.p8 index e125f9a99..8fa4ea50b 100644 --- a/compiler/res/prog8lib/cx16/syslib.p8 +++ b/compiler/res/prog8lib/cx16/syslib.p8 @@ -5,9 +5,6 @@ ; ; indent format: TABS, size=8 -%target cx16 - - c64 { ; ---- kernal routines, these are the same as on the Commodore-64 (hence the same block name) ---- diff --git a/compiler/res/prog8lib/cx16/textio.p8 b/compiler/res/prog8lib/cx16/textio.p8 index 79c071ba8..9b2915264 100644 --- a/compiler/res/prog8lib/cx16/textio.p8 +++ b/compiler/res/prog8lib/cx16/textio.p8 @@ -4,7 +4,6 @@ ; ; indent format: TABS, size=8 -%target cx16 %import syslib %import conv diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index c256f4850..bc34795d5 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -297,17 +297,6 @@ private fun optimizeAst(programAst: Program, errors: IErrorReporter, functions: break } - val inliner = SubroutineInliner(programAst, errors, options) - inliner.visit(programAst) - errors.report() - if(errors.noErrors()) { - inliner.applyModifications() - inliner.fixCallsToInlinedSubroutines() - val remover2 = UnusedCodeRemover(programAst, errors, compTarget) - remover2.visit(programAst) - remover2.applyModifications() - } - errors.report() } diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index ea184b71f..fd5a88cc1 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -269,10 +269,11 @@ internal class AstChecker(private val program: Program, } } - // scope check - if(subroutine.parent !is Block && subroutine.parent !is Subroutine) { + if(subroutine.inline && !subroutine.isAsmSubroutine) + err("subroutine inlining is currently only supported on asmsub routines") + + if(subroutine.parent !is Block && subroutine.parent !is Subroutine) err("subroutines can only be defined in the scope of a block or within another subroutine") - } if(subroutine.isAsmSubroutine) { if(subroutine.asmParameterRegisters.size != subroutine.parameters.size) @@ -714,14 +715,6 @@ internal class AstChecker(private val program: Program, else if(directive.args.map{it.name in setOf("enable_floats", "force_output", "no_sysinit", "align_word", "align_page")}.any { !it }) err("invalid option directive argument(s)") } - "%target" -> { - if(directive.parent !is Block && directive.parent !is Module) - err("this directive may only occur in a block or at module level") - if(directive.args.size != 1) - err("directive requires one argument") - if(directive.args.single().name !in setOf(C64Target.name, Cx16Target.name)) - err("invalid compilation target") - } else -> throw SyntaxError("invalid directive ${directive.directive}", directive.position) } super.visit(directive) diff --git a/compiler/src/prog8/compiler/astprocessing/AstIdentifiersChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstIdentifiersChecker.kt index f9f173ce2..00ba76541 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstIdentifiersChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstIdentifiersChecker.kt @@ -33,16 +33,6 @@ internal class AstIdentifiersChecker(private val program: Program, private val e super.visit(block) } - override fun visit(directive: Directive) { - if(directive.directive=="%target") { - val compatibleTarget = directive.args.single().name - if (compatibleTarget != compTarget.name) - errors.err("module's compilation target ($compatibleTarget) differs from active target (${compTarget.name})", directive.position) - } - - super.visit(directive) - } - override fun visit(decl: VarDecl) { decl.datatypeErrors.forEach { errors.err(it.message, it.position) } diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt index 212911571..8ae826bdf 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt @@ -864,7 +864,7 @@ internal class AsmGen(private val program: Program, if(sub.inline) { if(options.optimize) { - if(sub.isAsmSubroutine ||callGraph.unused(sub)) + if(sub.isAsmSubroutine || callGraph.unused(sub)) return // from an inlined subroutine only the local variables are generated, @@ -873,7 +873,7 @@ internal class AsmGen(private val program: Program, onlyVariables = true } else if(sub.amountOfRtsInAsm()==0) { - // make sure the NOT INLINED subroutine actually does an rts at the end + // make sure the NOT INLINED subroutine actually does a rts at the end sub.statements.add(Return(null, Position.DUMMY)) } } diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt index 7ba1b61fa..7ae882f5a 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt @@ -750,7 +750,6 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val // optimized simple case: swap two memory locations if(first is DirectMemoryRead && second is DirectMemoryRead) { - // TODO optimize swap of two memread values with index, using the same pointer expression/variable, like swap(@(ptr+i1), @(ptr+i2)) val addr1 = (first.addressExpression as? NumericLiteralValue)?.number?.toHex() val addr2 = (second.addressExpression as? NumericLiteralValue)?.number?.toHex() val name1 = if(first.addressExpression is IdentifierReference) asmgen.asmVariableName(first.addressExpression as IdentifierReference) else null @@ -773,6 +772,50 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val asmgen.out(" ldy $name1 | lda $name2 | sta $name1 | sty $name2") return } + addr1==null && addr2==null && name1==null && name2==null -> { + val firstExpr = first.addressExpression as? BinaryExpression + val secondExpr = second.addressExpression as? BinaryExpression + if(firstExpr!=null && secondExpr!=null) { + val pointerVariable = firstExpr.left as? IdentifierReference + val firstOffset = firstExpr.right + val secondOffset = secondExpr.right + if(pointerVariable != null + && pointerVariable isSameAs secondExpr.left + && firstExpr.operator == "+" && secondExpr.operator == "+" + && (firstOffset is NumericLiteralValue || firstOffset is IdentifierReference || firstOffset is TypecastExpression) + && (secondOffset is NumericLiteralValue || secondOffset is IdentifierReference || secondOffset is TypecastExpression) + ) { + val pointerVar = firstExpr.left as IdentifierReference + if(firstOffset is NumericLiteralValue && secondOffset is NumericLiteralValue) { + if(firstOffset!=secondOffset) { + swapArrayValues( + DataType.UBYTE, + asmgen.asmVariableName(pointerVariable), firstOffset, + asmgen.asmVariableName(pointerVariable), secondOffset + ) + return + } + } else if(firstOffset is TypecastExpression && secondOffset is TypecastExpression) { + if(firstOffset.type in WordDatatypes && secondOffset.type in WordDatatypes) { + val firstOffsetVar = firstOffset.expression as? IdentifierReference + val secondOffsetVar = secondOffset.expression as? IdentifierReference + if(firstOffsetVar!=null && secondOffsetVar!=null) { + if(firstOffsetVar!=secondOffsetVar) { + swapArrayValues( + DataType.UBYTE, + asmgen.asmVariableName(pointerVariable), firstOffsetVar, + asmgen.asmVariableName(pointerVariable), secondOffsetVar + ) + return + } + } + } + } else if(firstOffset is IdentifierReference || secondOffset is IdentifierReference) { + throw AssemblyError("expected a typecast-to-word for index variable at ${firstOffset.position} and/or ${secondOffset.position}") + } + } + } + } } } @@ -888,7 +931,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val sta P8ZP_SCRATCH_W2 lda #>(${arrayVarName2}+$index2) sta P8ZP_SCRATCH_W2+1 - jsr floats.swap_floats + jsr floats.func_swap_f """) } else -> throw AssemblyError("invalid aray elt type") @@ -961,7 +1004,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val sta P8ZP_SCRATCH_W2 bcc + inc P8ZP_SCRATCH_W2+1 -+ jsr floats.swap_floats ++ jsr floats.func_swap_f """) } else -> throw AssemblyError("invalid aray elt type") @@ -1019,7 +1062,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val sta P8ZP_SCRATCH_W1 bcc + inc P8ZP_SCRATCH_W1+1 -+ jsr floats.swap_floats ++ jsr floats.func_swap_f """) } else -> throw AssemblyError("invalid aray elt type") @@ -1077,7 +1120,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val sta P8ZP_SCRATCH_W2 lda #>(${arrayVarName2}+$index2) sta P8ZP_SCRATCH_W2+1 - jsr floats.swap_floats + jsr floats.func_swap_f """) } else -> throw AssemblyError("invalid aray elt type") diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/FunctionCallAsmGen.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/FunctionCallAsmGen.kt index f44866ef1..05fe27299 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/FunctionCallAsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/FunctionCallAsmGen.kt @@ -118,16 +118,14 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg // we do this by copying the subroutine's statements at the call site. // NOTE: *if* there is a return statement, it will be the only one, and the very last statement of the subroutine // (this condition has been enforced by an ast check earlier) + + // note: for now, this is only reliably supported for asmsubs. + if(!sub.isAsmSubroutine) + throw AssemblyError("can only reliably inline asmsub routines at this time") + asmgen.out(" \t; inlined routine follows: ${sub.name}") - val statements = sub.statements.filter { it !is ParameterVarDecl && it !is Directive } - statements.forEach { - if(it is Return) { - asmgen.translate(it, false) // don't use RTS for the inlined return statement - } else { - if(!sub.inline || it !is VarDecl) - asmgen.translate(it) - } - } + val assembly = sub.statements.single() as InlineAssembly + asmgen.translate(assembly) asmgen.out(" \t; inlined routine end: ${sub.name}") } diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AssignmentAsmGen.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AssignmentAsmGen.kt index 5b80f89c5..a0f14d766 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AssignmentAsmGen.kt @@ -1359,8 +1359,10 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } internal fun assignRegisterByte(target: AsmAssignTarget, register: CpuRegister) { - // we make an exception in the type check for assigning something to a cx16 virtual register - if(target.register !in Cx16VirtualRegisters) { + // we make an exception in the type check for assigning something to a cx16 virtual register, or a register pair + // these will be correctly typecasted from a byte to a word value + if(target.register !in Cx16VirtualRegisters && + target.register!=RegisterOrPair.AX && target.register!=RegisterOrPair.AY && target.register!=RegisterOrPair.XY) { if(target.kind==TargetStorageKind.VARIABLE) { val parts = target.asmVarname.split('.') if (parts.size != 2 || parts[0] != "cx16") diff --git a/compiler/src/prog8/optimizer/ConstantIdentifierReplacer.kt b/compiler/src/prog8/optimizer/ConstantIdentifierReplacer.kt index aae516238..17d34933d 100644 --- a/compiler/src/prog8/optimizer/ConstantIdentifierReplacer.kt +++ b/compiler/src/prog8/optimizer/ConstantIdentifierReplacer.kt @@ -12,6 +12,7 @@ import prog8.compiler.IErrorReporter import prog8.compiler.target.ICompilationTarget // Fix up the literal value's type to match that of the vardecl +// (also check range literal operands types before they get expanded to arrays for instance) internal class VarConstantValueTypeAdjuster(private val program: Program, private val errors: IErrorReporter) : AstWalker() { override fun after(decl: VarDecl, parent: Node): Iterable { @@ -52,6 +53,35 @@ internal class VarConstantValueTypeAdjuster(private val program: Program, privat } return noModifications } + + override fun after(range: RangeExpr, parent: Node): Iterable { + val from = range.from.constValue(program)?.number?.toDouble() + val to = range.to.constValue(program)?.number?.toDouble() + val step = range.step.constValue(program)?.number?.toDouble() + + if(from==null) { + if(!range.from.inferType(program).isInteger()) + errors.err("range expression from value must be integer", range.from.position) + } else if(from-from.toInt()>0) { + errors.err("range expression from value must be integer", range.from.position) + } + + if(to==null) { + if(!range.to.inferType(program).isInteger()) + errors.err("range expression to value must be integer", range.to.position) + } else if(to-to.toInt()>0) { + errors.err("range expression to value must be integer", range.to.position) + } + + if(step==null) { + if(!range.step.inferType(program).isInteger()) + errors.err("range expression step value must be integer", range.step.position) + } else if(step-step.toInt()>0) { + errors.err("range expression step value must be integer", range.step.position) + } + + return noModifications + } } diff --git a/compiler/src/prog8/optimizer/StatementOptimizer.kt b/compiler/src/prog8/optimizer/StatementOptimizer.kt index 413b6e2fd..41355daa8 100644 --- a/compiler/src/prog8/optimizer/StatementOptimizer.kt +++ b/compiler/src/prog8/optimizer/StatementOptimizer.kt @@ -39,6 +39,41 @@ internal class StatementOptimizer(private val program: Program, return noModifications } + override fun before(functionCall: FunctionCall, parent: Node): Iterable { + // if the first instruction in the called subroutine is a return statement with a simple value, + // remove the jump altogeter and inline the returnvalue directly. + val subroutine = functionCall.target.targetSubroutine(program) + if(subroutine!=null) { + val first = subroutine.statements.asSequence().filterNot { it is VarDecl || it is Directive }.firstOrNull() + if(first is Return && first.value?.isSimple==true) { + val orig = first.value!! + val copy = when(orig) { + is AddressOf -> { + val scoped = scopePrefix(orig.identifier, subroutine) + AddressOf(scoped, orig.position) + } + is DirectMemoryRead -> { + when(val expr = orig.addressExpression) { + is NumericLiteralValue -> DirectMemoryRead(expr.copy(), orig.position) + else -> return noModifications + } + } + is IdentifierReference -> scopePrefix(orig, subroutine) + is NumericLiteralValue -> orig.copy() + is StringLiteralValue -> orig.copy() + else -> return noModifications + } + return listOf(IAstModification.ReplaceNode(functionCall, copy, parent)) + } + } + return noModifications + } + + private fun scopePrefix(variable: IdentifierReference, subroutine: Subroutine): IdentifierReference { + val scoped = subroutine.makeScopedName(variable.nameInSource.last()) + return IdentifierReference(scoped.split('.'), variable.position) + } + override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable { if(functionCallStatement.target.nameInSource.size==1 && functionCallStatement.target.nameInSource[0] in functions.names) { val functionName = functionCallStatement.target.nameInSource[0] @@ -101,19 +136,19 @@ internal class StatementOptimizer(private val program: Program, return noModifications } - override fun before(functionCall: FunctionCall, parent: Node): Iterable { - // if the first instruction in the called subroutine is a return statement with constant value, replace with the constant value - val subroutine = functionCall.target.targetSubroutine(program) - if(subroutine!=null) { - val first = subroutine.statements.asSequence().filterNot { it is VarDecl || it is Directive }.firstOrNull() - if(first is Return && first.value!=null) { - val constval = first.value?.constValue(program) - if(constval!=null) - return listOf(IAstModification.ReplaceNode(functionCall, constval, parent)) - } - } - return noModifications - } +// override fun before(functionCall: FunctionCall, parent: Node): Iterable { +// // if the first instruction in the called subroutine is a return statement with constant value, replace with the constant value +// val subroutine = functionCall.target.targetSubroutine(program) +// if(subroutine!=null) { +// val first = subroutine.statements.asSequence().filterNot { it is VarDecl || it is Directive }.firstOrNull() +// if(first is Return && first.value!=null) { +// val constval = first.value?.constValue(program) +// if(constval!=null) +// return listOf(IAstModification.ReplaceNode(functionCall, constval, parent)) +// } +// } +// return noModifications +// } override fun after(ifStatement: IfStatement, parent: Node): Iterable { // remove empty if statements diff --git a/compiler/src/prog8/optimizer/SubroutineInliner.kt b/compiler/src/prog8/optimizer/SubroutineInliner.kt deleted file mode 100644 index 8f45ead9a..000000000 --- a/compiler/src/prog8/optimizer/SubroutineInliner.kt +++ /dev/null @@ -1,96 +0,0 @@ -package prog8.optimizer - -import prog8.ast.IFunctionCall -import prog8.ast.Node -import prog8.ast.Program -import prog8.ast.base.Position -import prog8.ast.expressions.FunctionCall -import prog8.ast.expressions.IdentifierReference -import prog8.ast.statements.* -import prog8.ast.walk.AstWalker -import prog8.ast.walk.IAstModification -import prog8.compiler.CompilationOptions -import prog8.compiler.IErrorReporter - - -internal class SubroutineInliner(private val program: Program, val errors: IErrorReporter, private val compilerOptions: CompilationOptions): AstWalker() { - private var callsToInlinedSubroutines = mutableListOf>() - - fun fixCallsToInlinedSubroutines() { - for((call, parent) in callsToInlinedSubroutines) { - val sub = call.target.targetSubroutine(program)!! - val intermediateReturnValueVar = sub.statements.filterIsInstance().singleOrNull { it.name.endsWith(retvarName) } - if(intermediateReturnValueVar!=null) { - val scope = parent.definingScope() - if(!scope.statements.filterIsInstance().any { it.name==intermediateReturnValueVar.name}) { - val decl = intermediateReturnValueVar.copy() - scope.statements.add(0, decl) - decl.linkParents(scope as Node) - } - } - } - } - - override fun after(subroutine: Subroutine, parent: Node): Iterable { - return if(compilerOptions.optimize && subroutine.inline && !subroutine.isAsmSubroutine) - annotateInlinedSubroutineIdentifiers(subroutine) - else - noModifications - } - - override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable { - return after(functionCallStatement as IFunctionCall, parent, functionCallStatement.position) - } - - override fun after(functionCall: FunctionCall, parent: Node): Iterable { - return after(functionCall as IFunctionCall, parent, functionCall.position) - } - - private fun after(functionCall: IFunctionCall, parent: Node, position: Position): Iterable { - val sub = functionCall.target.targetSubroutine(program) - if(sub != null && compilerOptions.optimize && sub.inline && !sub.isAsmSubroutine) - callsToInlinedSubroutines.add(Pair(functionCall, parent)) - - return noModifications - } - - private fun annotateInlinedSubroutineIdentifiers(sub: Subroutine): List { - // this adds name prefixes to the identifiers used in the subroutine, - // so that the statements can be inlined (=copied) in the call site and still reference - // the correct symbols as seen from the scope of the subroutine. - - class Annotator: AstWalker() { - var numReturns=0 - - override fun before(identifier: IdentifierReference, parent: Node): Iterable { - val stmt = identifier.targetStatement(program)!! - if(stmt is BuiltinFunctionStatementPlaceholder) - return noModifications - - val prefixed = stmt.makeScopedName(identifier.nameInSource.last()).split('.') - val withPrefix = IdentifierReference(prefixed, identifier.position) - return listOf(IAstModification.ReplaceNode(identifier, withPrefix, parent)) - } - - override fun before(returnStmt: Return, parent: Node): Iterable { - numReturns++ - if(parent !== sub || sub.indexOfChild(returnStmt) { - return this.modifications.map { it.first }.toList() - } - } - - val annotator = Annotator() - sub.accept(annotator, sub.parent) - if(annotator.numReturns>1) { - errors.err("inlined subroutine can only have one return statement", sub.position) - return noModifications - } - return annotator.theModifications() - } - -} diff --git a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt index e4ea9097a..1d6d721c2 100644 --- a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt +++ b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt @@ -348,7 +348,7 @@ class DirectMemoryRead(var addressExpression: Expression, override val position: this.addressExpression.linkParents(this) } - override val isSimple = true + override val isSimple = addressExpression is NumericLiteralValue || addressExpression is IdentifierReference override fun replaceChildNode(node: Node, replacement: Node) { require(replacement is Expression && node===addressExpression) @@ -366,8 +366,6 @@ class DirectMemoryRead(var addressExpression: Expression, override val position: override fun toString(): String { return "DirectMemoryRead($addressExpression)" } - - fun copy() = DirectMemoryRead(addressExpression, position) } class NumericLiteralValue(val type: DataType, // only numerical types allowed @@ -376,6 +374,7 @@ class NumericLiteralValue(val type: DataType, // only numerical types allowed override lateinit var parent: Node override val isSimple = true + fun copy() = NumericLiteralValue(type, number, position) companion object { fun fromBoolean(bool: Boolean, position: Position) = @@ -509,6 +508,7 @@ class StringLiteralValue(val value: String, } override val isSimple = true + fun copy() = StringLiteralValue(value, altEncoding, position) override fun replaceChildNode(node: Node, replacement: Node) { throw FatalAstException("can't replace here") diff --git a/compilerAst/src/prog8/parser/ModuleParsing.kt b/compilerAst/src/prog8/parser/ModuleParsing.kt index 94faa6ee4..f927ae7ca 100644 --- a/compilerAst/src/prog8/parser/ModuleParsing.kt +++ b/compilerAst/src/prog8/parser/ModuleParsing.kt @@ -135,7 +135,7 @@ class ModuleImporter(private val program: Program, private fun removeDirectivesFromImportedModule(importedModule: Module) { // Most global directives don't apply for imported modules, so remove them - val moduleLevelDirectives = listOf("%output", "%launcher", "%zeropage", "%zpreserved", "%address", "%target") + val moduleLevelDirectives = listOf("%output", "%launcher", "%zeropage", "%zpreserved", "%address") var directives = importedModule.statements.filterIsInstance() importedModule.statements.removeAll(directives) directives = directives.filter{ it.directive !in moduleLevelDirectives } diff --git a/compilerAst/test/TestAntlrParser.kt b/compilerAst/test/TestAntlrParser.kt index bb90bfb34..9a7868a3d 100644 --- a/compilerAst/test/TestAntlrParser.kt +++ b/compilerAst/test/TestAntlrParser.kt @@ -6,7 +6,6 @@ import org.junit.jupiter.api.Test import prog8.ast.IBuiltinFunctions import prog8.ast.IMemSizer import prog8.ast.IStringEncoding -import prog8.ast.Program import prog8.ast.antlr.toAst import prog8.ast.base.DataType import prog8.ast.base.Position @@ -14,9 +13,13 @@ import prog8.ast.expressions.Expression import prog8.ast.expressions.InferredTypes import prog8.ast.expressions.NumericLiteralValue import prog8.ast.statements.Block -import prog8.parser.* +import prog8.parser.ParsingFailedError +import prog8.parser.prog8Lexer +import prog8.parser.prog8Parser import java.nio.file.Path -import kotlin.test.* +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertIs class TestAntlrParser { diff --git a/docs/source/programming.rst b/docs/source/programming.rst index ad6634869..153789229 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -641,9 +641,13 @@ Subroutines can be defined in a Block, but also nested inside another subroutine With ``asmsub`` you can define a low-level subroutine that is implemented in inline assembly and takes any parameters in registers directly. -Trivial subroutines can be tagged as ``inline`` to tell the compiler to copy their code +Trivial ``asmsub`` routines can be tagged as ``inline`` to tell the compiler to copy their code in-place to the locations where the subroutine is called, rather than inserting an actual call and return to the subroutine. This may increase code size significantly and can only be used in limited scenarios, so YMMV. +Note that the routine's code is copied verbatim into the place of the subroutine call in this case, +so pay attention to any jumps and rts instructions in the inlined code! + +At this time it is not yet possible to inline regular Prog8 subroutines, this may be added in the future. Calling a subroutine diff --git a/docs/source/syntaxreference.rst b/docs/source/syntaxreference.rst index 2b1e52fb5..8db69295c 100644 --- a/docs/source/syntaxreference.rst +++ b/docs/source/syntaxreference.rst @@ -33,13 +33,6 @@ This makes it easier to understand and relate the generated code. Examples:: Directives ----------- -.. data:: %target - - Level: module. - Global setting, specifies that this module can only work for the given compiler target. - If compiled with a different target, compilation is aborted with an error message. - - .. data:: %output Level: module. @@ -403,7 +396,7 @@ The following names are reserved, they have a special meaning:: Range expression ^^^^^^^^^^^^^^^^ -A special value is the *range expression* which represents a range of numbers or characters, +A special value is the *range expression* which represents a range of integer numbers or characters, from the starting value to (and including) the ending value:: to [ step ] @@ -413,7 +406,7 @@ You an provide a step value if you need something else than the default incremen in case of downto, a decrement of one). Because a step of minus one is so common you can just use the downto variant to avoid having to specify the step as well. -If used in the place of a literal value, it expands into the actual array of values:: +If used in the place of a literal value, it expands into the actual array of integer values:: byte[] array = 100 to 199 ; initialize array with [100, 101, ..., 198, 199] @@ -559,7 +552,7 @@ Subroutine definitions The syntax is:: - [inline] sub ( [parameters] ) [ -> returntype ] { + sub ( [parameters] ) [ -> returntype ] { ... statements ... } @@ -572,9 +565,6 @@ The open curly brace must immediately follow the subroutine result specification and can have nothing following it. The close curly brace must be on its own line as well. The parameters is a (possibly empty) comma separated list of " " pairs specifying the input parameters. The return type has to be specified if the subroutine returns a value. -The ``inline`` keyword makes their code copied in-place to the locations where the subroutine is called, -rather than having an actual call and return to the subroutine. This is meant for very small subroutines only -as it can increase code size significantly. Assembly / ROM subroutines diff --git a/examples/balloonflight.p8 b/examples/balloonflight.p8 index a39eac281..eb82e46bb 100644 --- a/examples/balloonflight.p8 +++ b/examples/balloonflight.p8 @@ -1,4 +1,3 @@ -%target c64 %import syslib %import textio %import test_stack diff --git a/examples/bdmusic-irq.p8 b/examples/bdmusic-irq.p8 index 2bb1fb30c..6ed3b0e0f 100644 --- a/examples/bdmusic-irq.p8 +++ b/examples/bdmusic-irq.p8 @@ -1,4 +1,3 @@ -%target c64 %import syslib %import textio %zeropage basicsafe diff --git a/examples/bdmusic.p8 b/examples/bdmusic.p8 index 29b443e38..b96bb83c7 100644 --- a/examples/bdmusic.p8 +++ b/examples/bdmusic.p8 @@ -1,4 +1,3 @@ -%target c64 %import textio %import syslib diff --git a/examples/charset.p8 b/examples/charset.p8 index 84214def7..71f10e252 100644 --- a/examples/charset.p8 +++ b/examples/charset.p8 @@ -1,4 +1,3 @@ -%target c64 %import syslib %import textio %zeropage basicsafe diff --git a/examples/cube3d-sprites.p8 b/examples/cube3d-sprites.p8 index 843d6f81f..46091e3e3 100644 --- a/examples/cube3d-sprites.p8 +++ b/examples/cube3d-sprites.p8 @@ -1,4 +1,3 @@ -%target c64 %import syslib %import textio %import test_stack diff --git a/examples/cube3d.p8 b/examples/cube3d.p8 index 65fd9b2e0..44c6cb45b 100644 --- a/examples/cube3d.p8 +++ b/examples/cube3d.p8 @@ -1,4 +1,3 @@ -%target c64 %import syslib %import test_stack %import textio diff --git a/examples/cx16/amiga.p8 b/examples/cx16/amiga.p8 index ddaf57713..47cd11496 100644 --- a/examples/cx16/amiga.p8 +++ b/examples/cx16/amiga.p8 @@ -1,4 +1,3 @@ -%target cx16 %import textio %import palette %import string diff --git a/examples/cx16/bobs.p8 b/examples/cx16/bobs.p8 index f4954e8c3..d15ed0f79 100644 --- a/examples/cx16/bobs.p8 +++ b/examples/cx16/bobs.p8 @@ -1,4 +1,3 @@ -%target cx16 %import palette %import conv %import textio diff --git a/examples/cx16/cobramk3-gfx.p8 b/examples/cx16/cobramk3-gfx.p8 index 2884f0dc3..c72abbcf1 100644 --- a/examples/cx16/cobramk3-gfx.p8 +++ b/examples/cx16/cobramk3-gfx.p8 @@ -1,4 +1,3 @@ -%target cx16 %import syslib %import test_stack %import conv diff --git a/examples/cx16/colorbars.p8 b/examples/cx16/colorbars.p8 index d78eb727e..7bd6dd501 100644 --- a/examples/cx16/colorbars.p8 +++ b/examples/cx16/colorbars.p8 @@ -1,27 +1,24 @@ -%import gfx2 -%import palette %import textio - -; TODO WORK IN PROGRESS... -; want to make Amiga 'copper' bars color cycling effects +; Amiga 'copper' bars color cycling effect main { sub start() { - palette.set_all_black() - gfx2.screen_mode(4) + ; make palette color 1 black so we can print black letters over the background color 0 + void cx16.screen_set_mode(0) + cx16.vpoke(1, $fa02, $0) + cx16.vpoke(1, $fa03, $0) + txt.color(1) + txt.plot(13,12) + txt.print("amiga-inspired") + txt.plot(10,14) + txt.print("raster blinds effect") + txt.plot(12,16) + txt.print("random gradients") - ubyte yy - for yy in 0 to 239 - gfx2.horizontal_line(0, yy, 320, yy & 63) - - repeat { - colors.random_bar() - colors.set_palette() - repeat 20 - sys.waitvsync() - } + irq.make_new_gradient() + cx16.set_rasterirq(&irq.irqhandler, irq.top_scanline) repeat { } @@ -29,99 +26,165 @@ main { } +irq { + const ubyte top_scanline = 0 + ubyte blinds_start_ix = 0 + ubyte color_ix = 0 + uword next_irq_line = top_scanline + ubyte shift_counter = 0 + + ubyte[32+32+16] blinds_lines_reds + ubyte[32+32+16] blinds_lines_greens + ubyte[32+32+16] blinds_lines_blues + + + sub irqhandler() { + set_scanline_color(color_ix) + color_ix++ + + next_irq_line += 2 ; code needs 2 scanlines per color transition + + if next_irq_line == 480 { + ; start over at top + next_irq_line = top_scanline + blinds_start_ix = 0 + color_ix = 0 + shift_counter++ + if shift_counter == 32+32+32 { + make_new_gradient() + shift_counter = 0 + } else if shift_counter & 1 { + shift_gradient() + } + } else if next_irq_line & 15 == 0 { + ; start next blinds + blinds_start_ix++ + color_ix = blinds_start_ix + } + + + + cx16.set_rasterline(next_irq_line) + } + + sub make_new_gradient() { + colors.random_half_bar() + colors.mirror_bar() + sys.memcopy(colors.reds, &blinds_lines_reds+32+16, len(colors.reds)) + sys.memcopy(colors.greens, &blinds_lines_greens+32+16, len(colors.greens)) + sys.memcopy(colors.blues, &blinds_lines_blues+32+16, len(colors.blues)) + } + + sub shift_gradient() { + sys.memcopy(&blinds_lines_reds+1, blinds_lines_reds, len(blinds_lines_reds)-1) + sys.memcopy(&blinds_lines_greens+1, blinds_lines_greens, len(blinds_lines_greens)-1) + sys.memcopy(&blinds_lines_blues+1, blinds_lines_blues, len(blinds_lines_blues)-1) + } + + asmsub set_scanline_color(ubyte color_ix @Y) { + ; uword color = mkword(reds[ix], (greens[ix] << 4) | blues[ix] ) + %asm {{ + lda blinds_lines_reds,y + pha + lda blinds_lines_greens,y + asl a + asl a + asl a + asl a + ora blinds_lines_blues,y + tay + + stz cx16.VERA_CTRL + lda #%00010001 + sta cx16.VERA_ADDR_H + lda #$fa + sta cx16.VERA_ADDR_M + ; lda #$02 + ; sta cx16.VERA_ADDR_L + stz cx16.VERA_ADDR_L + sty cx16.VERA_DATA0 ; gb + pla + sta cx16.VERA_DATA0 ; r + stz cx16.VERA_ADDR_H + rts + }} + } +} + + colors { - ubyte cr - ubyte cg - ubyte cb - ubyte[48+16] reds - ubyte[48+16] greens - ubyte[48+16] blues - ubyte bar_size + ubyte target_red + ubyte target_green + ubyte target_blue + ubyte[32] reds + ubyte[32] greens + ubyte[32] blues sub random_rgb12() { do { uword rr = rndw() - cr = msb(rr) & 15 - cg = lsb(rr) - cb = cg & 15 - cg >>= 4 - } until cr+cg+cb >= 12 + target_red = msb(rr) & 15 + target_green = lsb(rr) + target_blue = target_green & 15 + target_green >>= 4 + } until target_red+target_green+target_blue >= 12 } - sub random_bar() { + sub mirror_bar() { + ; mirror the top half bar into the bottom half + ubyte ix=14 + ubyte mix=16 + do { + reds[mix] = reds[ix] + greens[mix] = greens[ix] + blues[mix] = blues[ix] + mix++ + ix-- + } until ix==255 + reds[mix] = 0 + greens[mix] = 0 + blues[mix] = 0 + } + + sub random_half_bar() { ; fade black -> color then fade color -> white + ; gradient calculations in 8.8 bits fixed-point + ; could theoretically be 4.12 bits for even more fractional accuracy random_rgb12() - ubyte r=0 - ubyte g=0 - ubyte b=0 - ubyte different - bar_size = 0 + uword r = $000 + uword g = $000 + uword b = $000 + uword dr = target_red + uword dg = target_green + uword db = target_blue + ubyte ix = 1 - repeat { - different = false - if r != cr { - different = true - r++ - } - if g != cg { - different = true - g++ - } - if b != cb { - different = true - b++ - } - if not different - break - reds[bar_size] = r - greens[bar_size] = g - blues[bar_size] = b - bar_size++ - } - repeat { - different = false - if r != 15 { - different = true - r++ - } - if g != 15 { - different = true - g++ - } - if b != 15 { - different = true - b++ - } - if not different - break - reds[bar_size] = r - greens[bar_size] = g - blues[bar_size] = b - bar_size++ - } - ; mirror bottom half from top half - ubyte mi = bar_size-1 - repeat mi { - reds[bar_size] = reds[mi] - greens[bar_size] = greens[mi] - blues[bar_size] = blues[mi] - bar_size++ - mi-- - } - ; make rest of bar black (bars are not always the same length using the simplistic algorithm above...) - while bar_size != 48+16 { - reds[bar_size] = $0 - greens[bar_size] = $0 - blues[bar_size] = $0 - bar_size++ - } - } + ; gradient from black to halfway color + reds[0] = 0 + greens[0] = 0 + blues[0] = 0 + dr <<= 5 + dg <<= 5 + db <<= 5 + continue_gradient() - sub set_palette() { - ubyte ix - for ix in 0 to 48+15 { - uword color = mkword(reds[ix], (greens[ix] << 4) | blues[ix] ) - palette.set_color(ix, color) + ; gradient from halfway color to white + dr = (($f00 - r) >> 3) - 1 + dg = (($f00 - g) >> 3) - 1 + db = (($f00 - b) >> 3) - 1 + continue_gradient() + return + + sub continue_gradient() { + repeat 8 { + reds[ix] = msb(r) + greens[ix] = msb(g) + blues[ix] = msb(b) + r += dr + g += dg + b += db + ix++ + } } } } diff --git a/examples/cx16/cube3d.p8 b/examples/cx16/cube3d.p8 index d4b8a3d37..149e0e7fb 100644 --- a/examples/cx16/cube3d.p8 +++ b/examples/cx16/cube3d.p8 @@ -1,4 +1,3 @@ -%target cx16 %import textio main { diff --git a/examples/cx16/datetime.p8 b/examples/cx16/datetime.p8 index 0fa4887b4..8a4e40dd1 100644 --- a/examples/cx16/datetime.p8 +++ b/examples/cx16/datetime.p8 @@ -1,6 +1,5 @@ ; CommanderX16 text datetime example! -%target cx16 %import textio %zeropage basicsafe diff --git a/examples/cx16/highresbitmap.p8 b/examples/cx16/highresbitmap.p8 index 49d042e60..4a0f536d1 100644 --- a/examples/cx16/highresbitmap.p8 +++ b/examples/cx16/highresbitmap.p8 @@ -1,4 +1,3 @@ -%target cx16 %import gfx2 %import floats %import textio diff --git a/examples/cx16/kefrenbars.p8 b/examples/cx16/kefrenbars.p8 index a3c6ce6be..0b7b31306 100644 --- a/examples/cx16/kefrenbars.p8 +++ b/examples/cx16/kefrenbars.p8 @@ -1,4 +1,3 @@ -%target cx16 %import palette %option no_sysinit diff --git a/examples/cx16/mandelbrot-gfx-colors.p8 b/examples/cx16/mandelbrot-gfx-colors.p8 index 844faaef5..b386ee7de 100644 --- a/examples/cx16/mandelbrot-gfx-colors.p8 +++ b/examples/cx16/mandelbrot-gfx-colors.p8 @@ -1,4 +1,3 @@ -%target cx16 %import textio %import floats %zeropage basicsafe diff --git a/examples/cx16/mandelbrot.p8 b/examples/cx16/mandelbrot.p8 index a92e46529..58a1d5dba 100644 --- a/examples/cx16/mandelbrot.p8 +++ b/examples/cx16/mandelbrot.p8 @@ -1,4 +1,3 @@ -%target cx16 %import textio %import floats %zeropage basicsafe diff --git a/examples/cx16/multipalette.p8 b/examples/cx16/multipalette.p8 index a4801d102..28fe57af8 100644 --- a/examples/cx16/multipalette.p8 +++ b/examples/cx16/multipalette.p8 @@ -1,4 +1,3 @@ -%target cx16 %import palette %import gfx2 %option no_sysinit diff --git a/examples/cx16/rasterbars.p8 b/examples/cx16/rasterbars.p8 index df73756bc..94b2bf4b2 100644 --- a/examples/cx16/rasterbars.p8 +++ b/examples/cx16/rasterbars.p8 @@ -1,4 +1,3 @@ -%target cx16 %import textio %import palette diff --git a/examples/cx16/tehtriz.p8 b/examples/cx16/tehtriz.p8 index a33473236..32cfc5ff7 100644 --- a/examples/cx16/tehtriz.p8 +++ b/examples/cx16/tehtriz.p8 @@ -8,7 +8,6 @@ ; simplistic sound effects (Vera PSG) -%target cx16 %import syslib %import textio %import test_stack diff --git a/examples/cx16/testgfx2.p8 b/examples/cx16/testgfx2.p8 index be8b2a8d9..6317aaa76 100644 --- a/examples/cx16/testgfx2.p8 +++ b/examples/cx16/testgfx2.p8 @@ -1,4 +1,3 @@ -%target cx16 %import gfx2 %import textio %import test_stack diff --git a/examples/cx16/vtui/testvtui.p8 b/examples/cx16/vtui/testvtui.p8 index b161e1503..9eb1f6440 100644 --- a/examples/cx16/vtui/testvtui.p8 +++ b/examples/cx16/vtui/testvtui.p8 @@ -1,4 +1,3 @@ -%target cx16 %import textio %option no_sysinit %zeropage basicsafe diff --git a/examples/plasma.p8 b/examples/plasma.p8 index 9c1eaf37e..094765a82 100644 --- a/examples/plasma.p8 +++ b/examples/plasma.p8 @@ -1,4 +1,3 @@ -%target c64 %import syslib %import test_stack %import textio diff --git a/examples/rasterbars.p8 b/examples/rasterbars.p8 index 6057810de..505cc1d16 100644 --- a/examples/rasterbars.p8 +++ b/examples/rasterbars.p8 @@ -1,4 +1,3 @@ -%target c64 %import syslib main { diff --git a/examples/sprites.p8 b/examples/sprites.p8 index d336e6a65..b15f92efd 100644 --- a/examples/sprites.p8 +++ b/examples/sprites.p8 @@ -1,4 +1,3 @@ -%target c64 %import textio %import syslib %zeropage basicsafe diff --git a/examples/tehtriz.p8 b/examples/tehtriz.p8 index 3fdffd868..5f75d330f 100644 --- a/examples/tehtriz.p8 +++ b/examples/tehtriz.p8 @@ -8,7 +8,6 @@ ; some simple sound effects -%target c64 %import syslib %import textio %import test_stack diff --git a/examples/test.p8 b/examples/test.p8 index 860fab040..0475e7eeb 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -3,40 +3,68 @@ main { -label: sub start() { - sub2(&label) - sub2(&label_local) - sub2(&main.sub2.label_in_sub2) - uword xx = &label_local - txt.print_uwhex(xx, true) + uword v + v = test.get_value1() + txt.print_uw(v) txt.nl() - xx = &label - txt.print_uwhex(xx, true) + v = test.get_value2() + txt.print_uw(v) txt.nl() - xx = &main.label - txt.print_uwhex(xx, true) + v = test.get_value3() + txt.print_uw(v) txt.nl() - xx = &main.sub2.label_in_sub2 - txt.print_uwhex(xx, true) + v = test.get_value4() + txt.print_uw(v) + v = test.get_value4() + txt.print_uw(v) + v = test.get_value4() + txt.print_uw(v) + v = test.get_value4() + txt.print_uw(v) + v = test.get_value4() + txt.print_uw(v) + v = test.get_value4() + txt.print_uw(v) + v = test.get_value4() + txt.print_uw(v) + v = test.get_value4() + txt.print_uw(v) + v = test.get_value4() + txt.print_uw(v) + v = test.get_value4() + txt.print_uw(v) txt.nl() - xx = main.sub2.sub2var - txt.print_uwhex(xx, true) + v = test.get_value5() + txt.print_uw(v) txt.nl() - xx = &main.start.label_local - txt.print_uwhex(xx, true) - txt.nl() - -label_local: - return - } - - sub sub2(uword ad) { - uword sub2var = 42 - - txt.print_uwhex(ad,true) - txt.nl() -label_in_sub2: + v = test.get_value6() + txt.print_uw(v) txt.nl() } } + + +test { + uword[] arr = [1111,2222,3333] + uword value = 9999 + + sub get_value1() -> uword { + return &value + } + sub get_value2() -> uword { + return arr[2] + } + sub get_value3() -> ubyte { + return @($c000) + } + sub get_value4() -> uword { + return value + } + sub get_value5() -> uword { + return $c000 + } + sub get_value6() -> uword { + return "string" + } +} diff --git a/examples/turtle-gfx.p8 b/examples/turtle-gfx.p8 index bfefa7115..f3bf3224c 100644 --- a/examples/turtle-gfx.p8 +++ b/examples/turtle-gfx.p8 @@ -1,4 +1,3 @@ -%target c64 %import floats %import graphics %import test_stack diff --git a/examples/wizzine.p8 b/examples/wizzine.p8 index f50946f07..0af5abb4e 100644 --- a/examples/wizzine.p8 +++ b/examples/wizzine.p8 @@ -1,4 +1,3 @@ -%target c64 %import syslib %zeropage basicsafe diff --git a/parser/antlr/prog8.g4 b/parser/antlr/prog8.g4 index 9a2cc4fe4..e43e8f81b 100644 --- a/parser/antlr/prog8.g4 +++ b/parser/antlr/prog8.g4 @@ -135,7 +135,7 @@ unconditionaljump : 'goto' (integerliteral | scoped_identifier) ; directive : directivename=('%output' | '%launcher' | '%zeropage' | '%zpreserved' | '%address' | '%import' | - '%breakpoint' | '%asminclude' | '%asmbinary' | '%option' | '%target' ) + '%breakpoint' | '%asminclude' | '%asmbinary' | '%option' ) (directivearg? | directivearg (',' directivearg)*) ; diff --git a/syntax-files/IDEA/Prog8.xml b/syntax-files/IDEA/Prog8.xml index 0b5629951..6b7feb46e 100644 --- a/syntax-files/IDEA/Prog8.xml +++ b/syntax-files/IDEA/Prog8.xml @@ -12,7 +12,7 @@