mirror of
https://github.com/irmen/prog8.git
synced 2024-12-25 23:29:55 +00:00
Merge branch 'v7.1' into testability_steps_1_2_3_again
# Conflicts: # compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt # compilerAst/src/prog8/parser/ModuleParsing.kt # compilerAst/test/TestAntlrParser.kt # parser/antlr/Prog8ANTLR.g4
This commit is contained in:
commit
f37fb82d53
2
.idea/compiler.xml
generated
2
.idea/compiler.xml
generated
@ -4,4 +4,4 @@
|
|||||||
<option name="BUILD_PROCESS_HEAP_SIZE" value="1200" />
|
<option name="BUILD_PROCESS_HEAP_SIZE" value="1200" />
|
||||||
<bytecodeTargetLevel target="11" />
|
<bytecodeTargetLevel target="11" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id "org.jetbrains.kotlin.jvm" version "1.5.20" apply false
|
id "org.jetbrains.kotlin.jvm" version "1.5.30" apply false
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
;
|
;
|
||||||
; indent format: TABS, size=8
|
; indent format: TABS, size=8
|
||||||
|
|
||||||
%target c64
|
|
||||||
%option enable_floats
|
%option enable_floats
|
||||||
|
|
||||||
floats {
|
floats {
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%target c64
|
|
||||||
%import textio
|
%import textio
|
||||||
|
|
||||||
; bitmap pixel graphics module for the C64
|
; bitmap pixel graphics module for the C64
|
||||||
|
@ -5,8 +5,6 @@
|
|||||||
;
|
;
|
||||||
; indent format: TABS, size=8
|
; indent format: TABS, size=8
|
||||||
|
|
||||||
%target c64
|
|
||||||
|
|
||||||
c64 {
|
c64 {
|
||||||
&ubyte TIME_HI = $a0 ; software jiffy clock, hi byte
|
&ubyte TIME_HI = $a0 ; software jiffy clock, hi byte
|
||||||
&ubyte TIME_MID = $a1 ; .. mid 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.
|
; --- 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.
|
; note: a more accurate way to wait for vsync is to set up a vsync irq handler instead.
|
||||||
%asm {{
|
%asm {{
|
||||||
- lda c64.RASTER
|
- bit c64.SCROLY
|
||||||
beq -
|
bpl -
|
||||||
- lda c64.RASTER
|
- bit c64.SCROLY
|
||||||
bne -
|
|
||||||
bit c64.SCROLY
|
|
||||||
bmi -
|
bmi -
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
;
|
;
|
||||||
; indent format: TABS, size=8
|
; indent format: TABS, size=8
|
||||||
|
|
||||||
%target c64
|
|
||||||
%import syslib
|
%import syslib
|
||||||
%import conv
|
%import conv
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
;
|
;
|
||||||
; indent format: TABS, size=8
|
; indent format: TABS, size=8
|
||||||
|
|
||||||
%target cx16
|
|
||||||
%option enable_floats
|
%option enable_floats
|
||||||
|
|
||||||
floats {
|
floats {
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
%target cx16
|
|
||||||
|
|
||||||
; Bitmap pixel graphics routines for the CommanderX16
|
; Bitmap pixel graphics routines for the CommanderX16
|
||||||
; Custom routines to use the full-screen 640x480 and 320x240 screen modes.
|
; Custom routines to use the full-screen 640x480 and 320x240 screen modes.
|
||||||
; (These modes are not supported by the documented GRAPH_xxxx kernal routines)
|
; (These modes are not supported by the documented GRAPH_xxxx kernal routines)
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%target cx16
|
|
||||||
%import syslib
|
%import syslib
|
||||||
%import textio
|
%import textio
|
||||||
|
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
%target cx16
|
|
||||||
|
|
||||||
; Manipulate the Commander X16's display color palette.
|
; Manipulate the Commander X16's display color palette.
|
||||||
; Should you want to restore the default palette, you have to reinitialize the Vera yourself.
|
; Should you want to restore the default palette, you have to reinitialize the Vera yourself.
|
||||||
|
|
||||||
@ -9,7 +7,7 @@ palette {
|
|||||||
ubyte c
|
ubyte c
|
||||||
|
|
||||||
sub set_color(ubyte index, uword color) {
|
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))
|
cx16.vpoke(1, vera_palette_ptr, lsb(color))
|
||||||
vera_palette_ptr++
|
vera_palette_ptr++
|
||||||
cx16.vpoke(1, vera_palette_ptr, msb(color))
|
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)
|
set_monochrome($000, $000)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline sub set_all_white() {
|
sub set_all_white() {
|
||||||
set_monochrome($fff, $fff)
|
set_monochrome($fff, $fff)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,9 +5,6 @@
|
|||||||
;
|
;
|
||||||
; indent format: TABS, size=8
|
; indent format: TABS, size=8
|
||||||
|
|
||||||
%target cx16
|
|
||||||
|
|
||||||
|
|
||||||
c64 {
|
c64 {
|
||||||
|
|
||||||
; ---- kernal routines, these are the same as on the Commodore-64 (hence the same block name) ----
|
; ---- kernal routines, these are the same as on the Commodore-64 (hence the same block name) ----
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
;
|
;
|
||||||
; indent format: TABS, size=8
|
; indent format: TABS, size=8
|
||||||
|
|
||||||
%target cx16
|
|
||||||
%import syslib
|
%import syslib
|
||||||
%import conv
|
%import conv
|
||||||
|
|
||||||
|
@ -301,17 +301,6 @@ private fun optimizeAst(programAst: Program, errors: IErrorReporter, functions:
|
|||||||
break
|
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()
|
errors.report()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,10 +270,11 @@ internal class AstChecker(private val program: Program,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// scope check
|
if(subroutine.inline && !subroutine.isAsmSubroutine)
|
||||||
if(subroutine.parent !is Block && subroutine.parent !is Subroutine) {
|
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")
|
err("subroutines can only be defined in the scope of a block or within another subroutine")
|
||||||
}
|
|
||||||
|
|
||||||
if(subroutine.isAsmSubroutine) {
|
if(subroutine.isAsmSubroutine) {
|
||||||
if(subroutine.asmParameterRegisters.size != subroutine.parameters.size)
|
if(subroutine.asmParameterRegisters.size != subroutine.parameters.size)
|
||||||
@ -715,14 +716,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 })
|
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)")
|
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)
|
else -> throw SyntaxError("invalid directive ${directive.directive}", directive.position)
|
||||||
}
|
}
|
||||||
super.visit(directive)
|
super.visit(directive)
|
||||||
|
@ -33,16 +33,6 @@ internal class AstIdentifiersChecker(private val program: Program, private val e
|
|||||||
super.visit(block)
|
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) {
|
override fun visit(decl: VarDecl) {
|
||||||
decl.datatypeErrors.forEach { errors.err(it.message, it.position) }
|
decl.datatypeErrors.forEach { errors.err(it.message, it.position) }
|
||||||
|
|
||||||
|
@ -864,7 +864,7 @@ internal class AsmGen(private val program: Program,
|
|||||||
|
|
||||||
if(sub.inline) {
|
if(sub.inline) {
|
||||||
if(options.optimize) {
|
if(options.optimize) {
|
||||||
if(sub.isAsmSubroutine ||callGraph.unused(sub))
|
if(sub.isAsmSubroutine || callGraph.unused(sub))
|
||||||
return
|
return
|
||||||
|
|
||||||
// from an inlined subroutine only the local variables are generated,
|
// from an inlined subroutine only the local variables are generated,
|
||||||
@ -873,7 +873,7 @@ internal class AsmGen(private val program: Program,
|
|||||||
onlyVariables = true
|
onlyVariables = true
|
||||||
}
|
}
|
||||||
else if(sub.amountOfRtsInAsm()==0) {
|
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))
|
sub.statements.add(Return(null, Position.DUMMY))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -750,7 +750,6 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
|||||||
|
|
||||||
// optimized simple case: swap two memory locations
|
// optimized simple case: swap two memory locations
|
||||||
if(first is DirectMemoryRead && second is DirectMemoryRead) {
|
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 addr1 = (first.addressExpression as? NumericLiteralValue)?.number?.toHex()
|
||||||
val addr2 = (second.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
|
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")
|
asmgen.out(" ldy $name1 | lda $name2 | sta $name1 | sty $name2")
|
||||||
return
|
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
|
sta P8ZP_SCRATCH_W2
|
||||||
lda #>(${arrayVarName2}+$index2)
|
lda #>(${arrayVarName2}+$index2)
|
||||||
sta P8ZP_SCRATCH_W2+1
|
sta P8ZP_SCRATCH_W2+1
|
||||||
jsr floats.swap_floats
|
jsr floats.func_swap_f
|
||||||
""")
|
""")
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("invalid aray elt type")
|
else -> throw AssemblyError("invalid aray elt type")
|
||||||
@ -961,7 +1004,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
|||||||
sta P8ZP_SCRATCH_W2
|
sta P8ZP_SCRATCH_W2
|
||||||
bcc +
|
bcc +
|
||||||
inc P8ZP_SCRATCH_W2+1
|
inc P8ZP_SCRATCH_W2+1
|
||||||
+ jsr floats.swap_floats
|
+ jsr floats.func_swap_f
|
||||||
""")
|
""")
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("invalid aray elt type")
|
else -> throw AssemblyError("invalid aray elt type")
|
||||||
@ -1019,7 +1062,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
|||||||
sta P8ZP_SCRATCH_W1
|
sta P8ZP_SCRATCH_W1
|
||||||
bcc +
|
bcc +
|
||||||
inc P8ZP_SCRATCH_W1+1
|
inc P8ZP_SCRATCH_W1+1
|
||||||
+ jsr floats.swap_floats
|
+ jsr floats.func_swap_f
|
||||||
""")
|
""")
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("invalid aray elt type")
|
else -> throw AssemblyError("invalid aray elt type")
|
||||||
@ -1077,7 +1120,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
|||||||
sta P8ZP_SCRATCH_W2
|
sta P8ZP_SCRATCH_W2
|
||||||
lda #>(${arrayVarName2}+$index2)
|
lda #>(${arrayVarName2}+$index2)
|
||||||
sta P8ZP_SCRATCH_W2+1
|
sta P8ZP_SCRATCH_W2+1
|
||||||
jsr floats.swap_floats
|
jsr floats.func_swap_f
|
||||||
""")
|
""")
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("invalid aray elt type")
|
else -> throw AssemblyError("invalid aray elt type")
|
||||||
|
@ -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.
|
// 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
|
// 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)
|
// (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}")
|
asmgen.out(" \t; inlined routine follows: ${sub.name}")
|
||||||
val statements = sub.statements.filter { it !is ParameterVarDecl && it !is Directive }
|
val assembly = sub.statements.single() as InlineAssembly
|
||||||
statements.forEach {
|
asmgen.translate(assembly)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
asmgen.out(" \t; inlined routine end: ${sub.name}")
|
asmgen.out(" \t; inlined routine end: ${sub.name}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1359,8 +1359,10 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun assignRegisterByte(target: AsmAssignTarget, register: CpuRegister) {
|
internal fun assignRegisterByte(target: AsmAssignTarget, register: CpuRegister) {
|
||||||
// we make an exception in the type check for assigning something to a cx16 virtual register
|
// we make an exception in the type check for assigning something to a cx16 virtual register, or a register pair
|
||||||
if(target.register !in Cx16VirtualRegisters) {
|
// 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) {
|
if(target.kind==TargetStorageKind.VARIABLE) {
|
||||||
val parts = target.asmVarname.split('.')
|
val parts = target.asmVarname.split('.')
|
||||||
if (parts.size != 2 || parts[0] != "cx16")
|
if (parts.size != 2 || parts[0] != "cx16")
|
||||||
|
@ -14,6 +14,7 @@ import prog8.compiler.astprocessing.toConstantIntegerRange
|
|||||||
import prog8.compiler.target.ICompilationTarget
|
import prog8.compiler.target.ICompilationTarget
|
||||||
|
|
||||||
// Fix up the literal value's type to match that of the vardecl
|
// 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() {
|
internal class VarConstantValueTypeAdjuster(private val program: Program, private val errors: IErrorReporter) : AstWalker() {
|
||||||
|
|
||||||
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
|
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
|
||||||
@ -54,6 +55,35 @@ internal class VarConstantValueTypeAdjuster(private val program: Program, privat
|
|||||||
}
|
}
|
||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun after(range: RangeExpr, parent: Node): Iterable<IAstModification> {
|
||||||
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,6 +40,41 @@ internal class StatementOptimizer(private val program: Program,
|
|||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun before(functionCall: FunctionCall, parent: Node): Iterable<IAstModification> {
|
||||||
|
// 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<IAstModification> {
|
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
|
||||||
if(functionCallStatement.target.nameInSource.size==1 && functionCallStatement.target.nameInSource[0] in functions.names) {
|
if(functionCallStatement.target.nameInSource.size==1 && functionCallStatement.target.nameInSource[0] in functions.names) {
|
||||||
val functionName = functionCallStatement.target.nameInSource[0]
|
val functionName = functionCallStatement.target.nameInSource[0]
|
||||||
@ -102,19 +137,19 @@ internal class StatementOptimizer(private val program: Program,
|
|||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun before(functionCall: FunctionCall, parent: Node): Iterable<IAstModification> {
|
// override fun before(functionCall: FunctionCall, parent: Node): Iterable<IAstModification> {
|
||||||
// if the first instruction in the called subroutine is a return statement with constant value, replace with the constant value
|
// // 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)
|
// val subroutine = functionCall.target.targetSubroutine(program)
|
||||||
if(subroutine!=null) {
|
// if(subroutine!=null) {
|
||||||
val first = subroutine.statements.asSequence().filterNot { it is VarDecl || it is Directive }.firstOrNull()
|
// val first = subroutine.statements.asSequence().filterNot { it is VarDecl || it is Directive }.firstOrNull()
|
||||||
if(first is Return && first.value!=null) {
|
// if(first is Return && first.value!=null) {
|
||||||
val constval = first.value?.constValue(program)
|
// val constval = first.value?.constValue(program)
|
||||||
if(constval!=null)
|
// if(constval!=null)
|
||||||
return listOf(IAstModification.ReplaceNode(functionCall, constval, parent))
|
// return listOf(IAstModification.ReplaceNode(functionCall, constval, parent))
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return noModifications
|
// return noModifications
|
||||||
}
|
// }
|
||||||
|
|
||||||
override fun after(ifStatement: IfStatement, parent: Node): Iterable<IAstModification> {
|
override fun after(ifStatement: IfStatement, parent: Node): Iterable<IAstModification> {
|
||||||
// remove empty if statements
|
// remove empty if statements
|
||||||
|
@ -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<Pair<IFunctionCall, Node>>()
|
|
||||||
|
|
||||||
fun fixCallsToInlinedSubroutines() {
|
|
||||||
for((call, parent) in callsToInlinedSubroutines) {
|
|
||||||
val sub = call.target.targetSubroutine(program)!!
|
|
||||||
val intermediateReturnValueVar = sub.statements.filterIsInstance<VarDecl>().singleOrNull { it.name.endsWith(retvarName) }
|
|
||||||
if(intermediateReturnValueVar!=null) {
|
|
||||||
val scope = parent.definingScope()
|
|
||||||
if(!scope.statements.filterIsInstance<VarDecl>().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<IAstModification> {
|
|
||||||
return if(compilerOptions.optimize && subroutine.inline && !subroutine.isAsmSubroutine)
|
|
||||||
annotateInlinedSubroutineIdentifiers(subroutine)
|
|
||||||
else
|
|
||||||
noModifications
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
|
|
||||||
return after(functionCallStatement as IFunctionCall, parent, functionCallStatement.position)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun after(functionCall: FunctionCall, parent: Node): Iterable<IAstModification> {
|
|
||||||
return after(functionCall as IFunctionCall, parent, functionCall.position)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun after(functionCall: IFunctionCall, parent: Node, position: Position): Iterable<IAstModification> {
|
|
||||||
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<IAstModification> {
|
|
||||||
// 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<IAstModification> {
|
|
||||||
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<IAstModification> {
|
|
||||||
numReturns++
|
|
||||||
if(parent !== sub || sub.indexOfChild(returnStmt)<sub.statements.size-1)
|
|
||||||
errors.err("return statement must be the very last statement in the inlined subroutine", sub.position)
|
|
||||||
return noModifications
|
|
||||||
}
|
|
||||||
|
|
||||||
fun theModifications(): List<IAstModification> {
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -12,6 +12,14 @@ import prog8.parser.Prog8ANTLRParser
|
|||||||
|
|
||||||
private data class NumericLiteral(val number: Number, val datatype: DataType)
|
private data class NumericLiteral(val number: Number, val datatype: DataType)
|
||||||
|
|
||||||
|
// TODO [merge conflict]: not sure if this should be kept?? Is it double??
|
||||||
|
internal fun Prog8ANTLRParser.ModuleContext.toAst(name: String, source: Path, encoding: IStringEncoding) : Module {
|
||||||
|
val nameWithoutSuffix = if(name.endsWith(".p8")) name.substringBeforeLast('.') else name
|
||||||
|
val directives = this.directive().map { it.toAst() }
|
||||||
|
val blocks = this.block().map { it.toAst(Module.isLibrary(source), encoding) }
|
||||||
|
return Module(nameWithoutSuffix, (directives + blocks).toMutableList(), toPosition(), source)
|
||||||
|
}
|
||||||
|
|
||||||
private fun ParserRuleContext.toPosition() : Position {
|
private fun ParserRuleContext.toPosition() : Position {
|
||||||
/*
|
/*
|
||||||
val customTokensource = this.start.tokenSource as? CustomLexer
|
val customTokensource = this.start.tokenSource as? CustomLexer
|
||||||
|
@ -347,7 +347,7 @@ class DirectMemoryRead(var addressExpression: Expression, override val position:
|
|||||||
this.addressExpression.linkParents(this)
|
this.addressExpression.linkParents(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val isSimple = true
|
override val isSimple = addressExpression is NumericLiteralValue || addressExpression is IdentifierReference
|
||||||
|
|
||||||
override fun replaceChildNode(node: Node, replacement: Node) {
|
override fun replaceChildNode(node: Node, replacement: Node) {
|
||||||
require(replacement is Expression && node===addressExpression)
|
require(replacement is Expression && node===addressExpression)
|
||||||
@ -365,8 +365,6 @@ class DirectMemoryRead(var addressExpression: Expression, override val position:
|
|||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "DirectMemoryRead($addressExpression)"
|
return "DirectMemoryRead($addressExpression)"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun copy() = DirectMemoryRead(addressExpression, position)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class NumericLiteralValue(val type: DataType, // only numerical types allowed
|
class NumericLiteralValue(val type: DataType, // only numerical types allowed
|
||||||
@ -375,6 +373,7 @@ class NumericLiteralValue(val type: DataType, // only numerical types allowed
|
|||||||
override lateinit var parent: Node
|
override lateinit var parent: Node
|
||||||
|
|
||||||
override val isSimple = true
|
override val isSimple = true
|
||||||
|
fun copy() = NumericLiteralValue(type, number, position)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun fromBoolean(bool: Boolean, position: Position) =
|
fun fromBoolean(bool: Boolean, position: Position) =
|
||||||
@ -539,6 +538,7 @@ class StringLiteralValue(val value: String,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override val isSimple = true
|
override val isSimple = true
|
||||||
|
fun copy() = StringLiteralValue(value, altEncoding, position)
|
||||||
|
|
||||||
override fun replaceChildNode(node: Node, replacement: Node) {
|
override fun replaceChildNode(node: Node, replacement: Node) {
|
||||||
throw FatalAstException("can't replace here")
|
throw FatalAstException("can't replace here")
|
||||||
|
@ -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
|
With ``asmsub`` you can define a low-level subroutine that is implemented in inline assembly and takes any parameters
|
||||||
in registers directly.
|
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
|
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.
|
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
|
Calling a subroutine
|
||||||
|
@ -33,13 +33,6 @@ This makes it easier to understand and relate the generated code. Examples::
|
|||||||
Directives
|
Directives
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
.. data:: %target <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 <type>
|
.. data:: %output <type>
|
||||||
|
|
||||||
Level: module.
|
Level: module.
|
||||||
@ -403,7 +396,7 @@ The following names are reserved, they have a special meaning::
|
|||||||
Range expression
|
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::
|
from the starting value to (and including) the ending value::
|
||||||
|
|
||||||
<start> to <end> [ step <step> ]
|
<start> to <end> [ step <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
|
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.
|
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]
|
byte[] array = 100 to 199 ; initialize array with [100, 101, ..., 198, 199]
|
||||||
|
|
||||||
@ -559,7 +552,7 @@ Subroutine definitions
|
|||||||
|
|
||||||
The syntax is::
|
The syntax is::
|
||||||
|
|
||||||
[inline] sub <identifier> ( [parameters] ) [ -> returntype ] {
|
sub <identifier> ( [parameters] ) [ -> returntype ] {
|
||||||
... statements ...
|
... 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.
|
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 "<datatype> <parametername>" pairs specifying the input parameters.
|
The parameters is a (possibly empty) comma separated list of "<datatype> <parametername>" pairs specifying the input parameters.
|
||||||
The return type has to be specified if the subroutine returns a value.
|
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
|
Assembly / ROM subroutines
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%target c64
|
|
||||||
%import syslib
|
%import syslib
|
||||||
%import textio
|
%import textio
|
||||||
%import test_stack
|
%import test_stack
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%target c64
|
|
||||||
%import syslib
|
%import syslib
|
||||||
%import textio
|
%import textio
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%target c64
|
|
||||||
%import textio
|
%import textio
|
||||||
%import syslib
|
%import syslib
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%target c64
|
|
||||||
%import syslib
|
%import syslib
|
||||||
%import textio
|
%import textio
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%target c64
|
|
||||||
%import syslib
|
%import syslib
|
||||||
%import textio
|
%import textio
|
||||||
%import test_stack
|
%import test_stack
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%target c64
|
|
||||||
%import syslib
|
%import syslib
|
||||||
%import test_stack
|
%import test_stack
|
||||||
%import textio
|
%import textio
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%target cx16
|
|
||||||
%import textio
|
%import textio
|
||||||
%import palette
|
%import palette
|
||||||
%import string
|
%import string
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%target cx16
|
|
||||||
%import palette
|
%import palette
|
||||||
%import conv
|
%import conv
|
||||||
%import textio
|
%import textio
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%target cx16
|
|
||||||
%import syslib
|
%import syslib
|
||||||
%import test_stack
|
%import test_stack
|
||||||
%import conv
|
%import conv
|
||||||
|
@ -1,27 +1,24 @@
|
|||||||
%import gfx2
|
|
||||||
%import palette
|
|
||||||
%import textio
|
%import textio
|
||||||
|
|
||||||
|
; Amiga 'copper' bars color cycling effect
|
||||||
; TODO WORK IN PROGRESS...
|
|
||||||
; want to make Amiga 'copper' bars color cycling effects
|
|
||||||
|
|
||||||
|
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
palette.set_all_black()
|
; make palette color 1 black so we can print black letters over the background color 0
|
||||||
gfx2.screen_mode(4)
|
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
|
irq.make_new_gradient()
|
||||||
for yy in 0 to 239
|
cx16.set_rasterirq(&irq.irqhandler, irq.top_scanline)
|
||||||
gfx2.horizontal_line(0, yy, 320, yy & 63)
|
|
||||||
|
|
||||||
repeat {
|
|
||||||
colors.random_bar()
|
|
||||||
colors.set_palette()
|
|
||||||
repeat 20
|
|
||||||
sys.waitvsync()
|
|
||||||
}
|
|
||||||
|
|
||||||
repeat {
|
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 {
|
colors {
|
||||||
ubyte cr
|
ubyte target_red
|
||||||
ubyte cg
|
ubyte target_green
|
||||||
ubyte cb
|
ubyte target_blue
|
||||||
ubyte[48+16] reds
|
ubyte[32] reds
|
||||||
ubyte[48+16] greens
|
ubyte[32] greens
|
||||||
ubyte[48+16] blues
|
ubyte[32] blues
|
||||||
ubyte bar_size
|
|
||||||
|
|
||||||
sub random_rgb12() {
|
sub random_rgb12() {
|
||||||
do {
|
do {
|
||||||
uword rr = rndw()
|
uword rr = rndw()
|
||||||
cr = msb(rr) & 15
|
target_red = msb(rr) & 15
|
||||||
cg = lsb(rr)
|
target_green = lsb(rr)
|
||||||
cb = cg & 15
|
target_blue = target_green & 15
|
||||||
cg >>= 4
|
target_green >>= 4
|
||||||
} until cr+cg+cb >= 12
|
} 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
|
; 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()
|
random_rgb12()
|
||||||
ubyte r=0
|
uword r = $000
|
||||||
ubyte g=0
|
uword g = $000
|
||||||
ubyte b=0
|
uword b = $000
|
||||||
ubyte different
|
uword dr = target_red
|
||||||
bar_size = 0
|
uword dg = target_green
|
||||||
|
uword db = target_blue
|
||||||
|
ubyte ix = 1
|
||||||
|
|
||||||
repeat {
|
; gradient from black to halfway color
|
||||||
different = false
|
reds[0] = 0
|
||||||
if r != cr {
|
greens[0] = 0
|
||||||
different = true
|
blues[0] = 0
|
||||||
r++
|
dr <<= 5
|
||||||
}
|
dg <<= 5
|
||||||
if g != cg {
|
db <<= 5
|
||||||
different = true
|
continue_gradient()
|
||||||
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++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub set_palette() {
|
; gradient from halfway color to white
|
||||||
ubyte ix
|
dr = (($f00 - r) >> 3) - 1
|
||||||
for ix in 0 to 48+15 {
|
dg = (($f00 - g) >> 3) - 1
|
||||||
uword color = mkword(reds[ix], (greens[ix] << 4) | blues[ix] )
|
db = (($f00 - b) >> 3) - 1
|
||||||
palette.set_color(ix, color)
|
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++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%target cx16
|
|
||||||
%import textio
|
%import textio
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
; CommanderX16 text datetime example!
|
; CommanderX16 text datetime example!
|
||||||
|
|
||||||
%target cx16
|
|
||||||
%import textio
|
%import textio
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%target cx16
|
|
||||||
%import gfx2
|
%import gfx2
|
||||||
%import floats
|
%import floats
|
||||||
%import textio
|
%import textio
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%target cx16
|
|
||||||
%import palette
|
%import palette
|
||||||
%option no_sysinit
|
%option no_sysinit
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%target cx16
|
|
||||||
%import textio
|
%import textio
|
||||||
%import floats
|
%import floats
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%target cx16
|
|
||||||
%import textio
|
%import textio
|
||||||
%import floats
|
%import floats
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%target cx16
|
|
||||||
%import palette
|
%import palette
|
||||||
%import gfx2
|
%import gfx2
|
||||||
%option no_sysinit
|
%option no_sysinit
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%target cx16
|
|
||||||
%import textio
|
%import textio
|
||||||
%import palette
|
%import palette
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
; simplistic sound effects (Vera PSG)
|
; simplistic sound effects (Vera PSG)
|
||||||
|
|
||||||
|
|
||||||
%target cx16
|
|
||||||
%import syslib
|
%import syslib
|
||||||
%import textio
|
%import textio
|
||||||
%import test_stack
|
%import test_stack
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%target cx16
|
|
||||||
%import gfx2
|
%import gfx2
|
||||||
%import textio
|
%import textio
|
||||||
%import test_stack
|
%import test_stack
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%target cx16
|
|
||||||
%import textio
|
%import textio
|
||||||
%option no_sysinit
|
%option no_sysinit
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%target c64
|
|
||||||
%import syslib
|
%import syslib
|
||||||
%import test_stack
|
%import test_stack
|
||||||
%import textio
|
%import textio
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%target c64
|
|
||||||
%import syslib
|
%import syslib
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%target c64
|
|
||||||
%import textio
|
%import textio
|
||||||
%import syslib
|
%import syslib
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
; some simple sound effects
|
; some simple sound effects
|
||||||
|
|
||||||
|
|
||||||
%target c64
|
|
||||||
%import syslib
|
%import syslib
|
||||||
%import textio
|
%import textio
|
||||||
%import test_stack
|
%import test_stack
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%target c64
|
|
||||||
%import floats
|
%import floats
|
||||||
%import graphics
|
%import graphics
|
||||||
%import test_stack
|
%import test_stack
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%target c64
|
|
||||||
%import syslib
|
%import syslib
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ NOTES:
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// -> java classes Prog8ANTLRParser and Prog8ANTLRLexer,
|
// -> java classes Prog8ANTLRParser and Prog8ANTLRLexer,
|
||||||
// both NOT to be used from Kotlin code, but ONLY through Kotlin class Prog8Parser
|
// both NOT to be used from Kotlin code, but ONLY through Kotlin class Prog8Parser
|
||||||
grammar Prog8ANTLR;
|
grammar Prog8ANTLR;
|
||||||
|
|
||||||
@ -137,7 +137,7 @@ unconditionaljump : 'goto' (integerliteral | scoped_identifier) ;
|
|||||||
|
|
||||||
directive :
|
directive :
|
||||||
directivename=('%output' | '%launcher' | '%zeropage' | '%zpreserved' | '%address' | '%import' |
|
directivename=('%output' | '%launcher' | '%zeropage' | '%zpreserved' | '%address' | '%import' |
|
||||||
'%breakpoint' | '%asminclude' | '%asmbinary' | '%option' | '%target' )
|
'%breakpoint' | '%asminclude' | '%asmbinary' | '%option' )
|
||||||
(directivearg? | directivearg (',' directivearg)*)
|
(directivearg? | directivearg (',' directivearg)*)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<option name="HAS_STRING_ESCAPES" value="true" />
|
<option name="HAS_STRING_ESCAPES" value="true" />
|
||||||
</options>
|
</options>
|
||||||
<keywords keywords="&;->;@;\$;and;as;asmsub;break;clobbers;do;downto;else;false;for;goto;if;if_cc;if_cs;if_eq;if_mi;if_ne;if_neg;if_nz;if_pl;if_pos;if_vc;if_vs;if_z;in;inline;not;or;repeat;return;romsub;step;sub;to;true;until;when;while;xor;~" ignore_case="false" />
|
<keywords keywords="&;->;@;\$;and;as;asmsub;break;clobbers;do;downto;else;false;for;goto;if;if_cc;if_cs;if_eq;if_mi;if_ne;if_neg;if_nz;if_pl;if_pos;if_vc;if_vs;if_z;in;inline;not;or;repeat;return;romsub;step;sub;to;true;until;when;while;xor;~" ignore_case="false" />
|
||||||
<keywords2 keywords="%address;%asm;%asmbinary;%asminclude;%breakpoint;%import;%launcher;%option;%output;%target;%zeropage;%zpreserved" />
|
<keywords2 keywords="%address;%asm;%asmbinary;%asminclude;%breakpoint;%import;%launcher;%option;%output;%zeropage;%zpreserved" />
|
||||||
<keywords3 keywords="byte;const;float;shared;str;ubyte;uword;void;word;zp" />
|
<keywords3 keywords="byte;const;float;shared;str;ubyte;uword;void;word;zp" />
|
||||||
<keywords4 keywords="abs;acos;all;any;asin;atan;avg;callfar;callrom;ceil;cmp;cos;cos16;cos16u;cos8;cos8u;deg;floor;len;ln;log2;lsb;lsl;lsr;max;memory;min;mkword;msb;peek;peekw;poke;pokew;rad;reverse;rnd;rndf;rndw;rol;rol2;ror;ror2;round;sgn;sin;sin16;sin16u;sin8;sin8u;sizeof;sort;sqrt;sqrt16;sum;swap;tan" />
|
<keywords4 keywords="abs;acos;all;any;asin;atan;avg;callfar;callrom;ceil;cmp;cos;cos16;cos16u;cos8;cos8u;deg;floor;len;ln;log2;lsb;lsl;lsr;max;memory;min;mkword;msb;peek;peekw;poke;pokew;rad;reverse;rnd;rndf;rndw;rol;rol2;ror;ror2;round;sgn;sin;sin16;sin16u;sin8;sin8u;sizeof;sort;sqrt;sqrt16;sum;swap;tan" />
|
||||||
</highlighting>
|
</highlighting>
|
||||||
@ -20,4 +20,4 @@
|
|||||||
<mapping ext="p8" />
|
<mapping ext="p8" />
|
||||||
<mapping ext="prog8" />
|
<mapping ext="prog8" />
|
||||||
</extensionMap>
|
</extensionMap>
|
||||||
</filetype>
|
</filetype>
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
<Keywords name="Folders in comment, middle"></Keywords>
|
<Keywords name="Folders in comment, middle"></Keywords>
|
||||||
<Keywords name="Folders in comment, close"></Keywords>
|
<Keywords name="Folders in comment, close"></Keywords>
|
||||||
<Keywords name="Keywords1">void const
str
byte ubyte
word uword
float
zp shared</Keywords>
|
<Keywords name="Keywords1">void const
str
byte ubyte
word uword
float
zp shared</Keywords>
|
||||||
<Keywords name="Keywords2">%address
%asm
%asmbinary
%asminclude
%breakpoint
%import
%launcher
%option
%output
%target
%zeropage
%zpreserved</Keywords>
|
<Keywords name="Keywords2">%address
%asm
%asmbinary
%asminclude
%breakpoint
%import
%launcher
%option
%output
%zeropage
%zpreserved</Keywords>
|
||||||
<Keywords name="Keywords3">inline sub asmsub romsub
clobbers
asm
if
when else
if_cc if_cs if_eq if_mi if_neg if_nz if_pl if_pos if_vc if_vs if_z
for in step do while repeat
break return goto</Keywords>
|
<Keywords name="Keywords3">inline sub asmsub romsub
clobbers
asm
if
when else
if_cc if_cs if_eq if_mi if_neg if_nz if_pl if_pos if_vc if_vs if_z
for in step do while repeat
break return goto</Keywords>
|
||||||
<Keywords name="Keywords4">abs acos all any asin atan avg callfar callrom ceil cmp cos cos16 cos16u cos8 cos8u deg floor len ln log2 lsb lsl lsr max memory min mkword msb peek peekw poke pokew rad reverse rnd rndf rndw rol rol2 ror ror2 round sgn sin sin16 sin16u sin8 sin8u sizeof sort sqrt sqrt16 sum swap tan
</Keywords>
|
<Keywords name="Keywords4">abs acos all any asin atan avg callfar callrom ceil cmp cos cos16 cos16u cos8 cos8u deg floor len ln log2 lsb lsl lsr max memory min mkword msb peek peekw poke pokew rad reverse rnd rndf rndw rol rol2 ror ror2 round sgn sin sin16 sin16u sin8 sin8u sizeof sort sqrt sqrt16 sum swap tan
</Keywords>
|
||||||
<Keywords name="Keywords5">true false
not and or xor
as to downto</Keywords>
|
<Keywords name="Keywords5">true false
not and or xor
as to downto</Keywords>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%target cx16
|
|
||||||
%import textio
|
%import textio
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
%option no_sysinit
|
%option no_sysinit
|
||||||
|
@ -33,7 +33,7 @@ syn keyword prog8Repeat for while in do until repeat
|
|||||||
syn match prog8Label "\<\w\+\>:"
|
syn match prog8Label "\<\w\+\>:"
|
||||||
syn keyword prog8Operator and or to downto as void
|
syn keyword prog8Operator and or to downto as void
|
||||||
|
|
||||||
syn match prog8Directive "\(^\|\s\)%\(target\|output\|launcher\|zeropage\)\>"
|
syn match prog8Directive "\(^\|\s\)%\(output\|launcher\|zeropage\)\>"
|
||||||
syn match prog8Directive "\(^\|\s\)%\(zpreserved\|address\|import\|option\)\>"
|
syn match prog8Directive "\(^\|\s\)%\(zpreserved\|address\|import\|option\)\>"
|
||||||
syn match prog8Directive "\(^\|\s\)%\(asmbinary\|asminclude\|breakpoint\)\>"
|
syn match prog8Directive "\(^\|\s\)%\(asmbinary\|asminclude\|breakpoint\)\>"
|
||||||
syn match prog8Directive "\(^\|\s\)%asm\>"
|
syn match prog8Directive "\(^\|\s\)%asm\>"
|
||||||
|
Loading…
Reference in New Issue
Block a user