removed postIncrDecr (still allow ++/-- to be parsed into +=1/-=1)

This commit is contained in:
Irmen de Jong 2024-02-06 18:50:08 +01:00
parent f874942075
commit 358215e4dd
22 changed files with 52 additions and 604 deletions

View File

@ -123,7 +123,6 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni
}
is PtNodeGroup -> "<group>"
is PtNop -> "nop"
is PtPostIncrDecr -> "<post> ${node.operator}"
is PtProgram -> "PROGRAM ${node.name}"
is PtRepeatLoop -> "repeat"
is PtReturn -> "return"

View File

@ -110,12 +110,6 @@ class PtJump(val identifier: PtIdentifier?, // note: even ad-hoc labels are
}
class PtPostIncrDecr(val operator: String, position: Position) : PtNode(position) {
val target: PtAssignTarget
get() = children.single() as PtAssignTarget
}
class PtRepeatLoop(position: Position) : PtNode(position) {
val count: PtExpression
get() = children[0] as PtExpression

View File

@ -227,7 +227,6 @@ class AsmGen6502Internal (
private val assembly = mutableListOf<String>()
private val breakpointLabels = mutableListOf<String>()
private val forloopsAsmGen = ForLoopsAsmGen(this, zeropage)
private val postincrdecrAsmGen = PostIncrDecrAsmGen(program, this)
private val functioncallAsmGen = FunctionCallAsmGen(program, this)
private val programGen = ProgramAndVarsGen(program, options, errors, symbolTable, functioncallAsmGen, this, allocator, zeropage)
private val anyExprGen = AnyExprAsmGen(this)
@ -535,7 +534,6 @@ class AsmGen6502Internal (
val (asmLabel, indirect) = getJumpTarget(stmt)
jmp(asmLabel, indirect)
}
is PtPostIncrDecr -> postincrdecrAsmGen.translate(stmt)
is PtLabel -> translate(stmt)
is PtConditionalBranch -> translate(stmt)
is PtIfElse -> translate(stmt)

View File

@ -1,191 +0,0 @@
package prog8.codegen.cpu6502
import prog8.code.ast.*
import prog8.code.core.*
internal class PostIncrDecrAsmGen(private val program: PtProgram, private val asmgen: AsmGen6502Internal) {
internal fun translate(stmt: PtPostIncrDecr) {
val incr = stmt.operator=="++"
val targetIdent = stmt.target.identifier
val targetMemory = stmt.target.memory
val targetArrayIdx = stmt.target.array
when {
targetIdent!=null -> {
val what = asmgen.asmVariableName(targetIdent)
when (stmt.target.type) {
in ByteDatatypes -> asmgen.out(if (incr) " inc $what" else " dec $what")
in WordDatatypes -> {
if(incr)
asmgen.out(" inc $what | bne + | inc $what+1 |+")
else
asmgen.out("""
lda $what
bne +
dec $what+1
+ dec $what
""")
}
DataType.FLOAT -> {
asmgen.out(" lda #<$what | ldy #>$what")
asmgen.out(if(incr) " jsr floats.inc_var_f" else " jsr floats.dec_var_f")
}
else -> throw AssemblyError("need numeric type")
}
}
targetMemory!=null -> {
fun incDecViaExprEval() {
asmgen.assignExpressionToRegister(targetMemory.address, RegisterOrPair.AY)
asmgen.out(" sta (+) + 1 | sty (+) + 2")
if(incr)
asmgen.out("+\tinc ${'$'}ffff\t; modified")
else
asmgen.out("+\tdec ${'$'}ffff\t; modified")
}
fun tryOptimizedPointerIncDec(address: PtBinaryExpression): Boolean {
if(address.operator=="+") {
val offset = address.right.asConstInteger()
if(offset!=null && offset<256) {
// we have @(ptr + 255) ++ , or @(ptr+255)--
asmgen.assignExpressionToRegister(address.left, RegisterOrPair.AY, false)
asmgen.out("""
sta (+) + 1
sty (+) + 2
ldx #$offset""")
if(incr)
asmgen.out("+\tinc ${'$'}ffff,x\t; modified")
else
asmgen.out("+\tdec ${'$'}ffff,x\t; modified")
return true
} else if(address.right.type in ByteDatatypes) {
// we have @(ptr + bytevar) ++ , or @(ptr+bytevar)--
asmgen.assignExpressionToRegister(address.left, RegisterOrPair.AY, false)
asmgen.out(" sta (+) + 1 | sty (+) + 2")
asmgen.assignExpressionToRegister(address.right, RegisterOrPair.X, false)
if(incr)
asmgen.out("+\tinc ${'$'}ffff,x\t; modified")
else
asmgen.out("+\tdec ${'$'}ffff,x\t; modified")
return true
} else if((address.right as? PtTypeCast)?.value?.type in ByteDatatypes) {
// we have @(ptr + bytevar) ++ , or @(ptr+bytevar)--
asmgen.assignExpressionToRegister(address.left, RegisterOrPair.AY, false)
asmgen.out(" sta (+) + 1 | sty (+) + 2")
asmgen.assignExpressionToRegister((address.right as PtTypeCast).value, RegisterOrPair.X, false)
if(incr)
asmgen.out("+\tinc ${'$'}ffff,x\t; modified")
else
asmgen.out("+\tdec ${'$'}ffff,x\t; modified")
return true
}
}
return false
}
when (val addressExpr = targetMemory.address) {
is PtNumber -> {
val what = addressExpr.number.toHex()
asmgen.out(if(incr) " inc $what" else " dec $what")
}
is PtIdentifier -> {
val what = asmgen.asmVariableName(addressExpr)
asmgen.out(" lda $what | sta (+) +1 | lda $what+1 | sta (+) +2")
if(incr)
asmgen.out("+\tinc ${'$'}ffff\t; modified")
else
asmgen.out("+\tdec ${'$'}ffff\t; modified")
}
is PtBinaryExpression -> {
if(!tryOptimizedPointerIncDec(addressExpr)) {
incDecViaExprEval()
}
}
else -> {
incDecViaExprEval()
}
}
}
targetArrayIdx!=null -> {
val asmArrayvarname = asmgen.asmVariableName(targetArrayIdx.variable)
val elementDt = targetArrayIdx.type
val constIndex = targetArrayIdx.index.asConstInteger()
if(targetArrayIdx.splitWords) {
if(constIndex!=null) {
if(incr)
asmgen.out(" inc ${asmArrayvarname}_lsb+$constIndex | bne + | inc ${asmArrayvarname}_msb+$constIndex |+")
else
asmgen.out("""
lda ${asmArrayvarname}_lsb+$constIndex
bne +
dec ${asmArrayvarname}_msb+$constIndex
+ dec ${asmArrayvarname}_lsb+$constIndex""")
} else {
asmgen.loadScaledArrayIndexIntoRegister(targetArrayIdx, CpuRegister.X)
if(incr)
asmgen.out(" inc ${asmArrayvarname}_lsb,x | bne + | inc ${asmArrayvarname}_msb,x |+")
else
asmgen.out("""
lda ${asmArrayvarname}_lsb,x
bne +
dec ${asmArrayvarname}_msb,x
+ dec ${asmArrayvarname}_lsb,x""")
}
return
}
if(constIndex!=null) {
val indexValue = constIndex * program.memsizer.memorySize(elementDt)
when(elementDt) {
in ByteDatatypes -> {
asmgen.out(if (incr) " inc $asmArrayvarname+$indexValue" else " dec $asmArrayvarname+$indexValue")
}
in WordDatatypes -> {
if(incr)
asmgen.out(" inc $asmArrayvarname+$indexValue | bne + | inc $asmArrayvarname+$indexValue+1 |+")
else
asmgen.out("""
lda $asmArrayvarname+$indexValue
bne +
dec $asmArrayvarname+$indexValue+1
+ dec $asmArrayvarname+$indexValue""")
}
DataType.FLOAT -> {
asmgen.out(" lda #<($asmArrayvarname+$indexValue) | ldy #>($asmArrayvarname+$indexValue)")
asmgen.out(if(incr) " jsr floats.inc_var_f" else " jsr floats.dec_var_f")
}
else -> throw AssemblyError("need numeric type")
}
}
else
{
asmgen.loadScaledArrayIndexIntoRegister(targetArrayIdx, CpuRegister.X)
when(elementDt) {
in ByteDatatypes -> {
asmgen.out(if (incr) " inc $asmArrayvarname,x" else " dec $asmArrayvarname,x")
}
in WordDatatypes -> {
if(incr)
asmgen.out(" inc $asmArrayvarname,x | bne + | inc $asmArrayvarname+1,x |+")
else
asmgen.out("""
lda $asmArrayvarname,x
bne +
dec $asmArrayvarname+1,x
+ dec $asmArrayvarname,x""")
}
DataType.FLOAT -> {
asmgen.out("""
ldy #>$asmArrayvarname
clc
adc #<$asmArrayvarname
bcc +
iny
+ jsr floats.inc_var_f""")
}
else -> throw AssemblyError("weird array elt dt")
}
}
}
}
}
}

View File

@ -241,7 +241,6 @@ class IRCodeGen(
is PtWhen -> translate(node)
is PtForLoop -> translate(node)
is PtIfElse -> translate(node)
is PtPostIncrDecr -> translate(node)
is PtRepeatLoop -> translate(node)
is PtLabel -> listOf(IRCodeChunk(node.name, null))
is PtBreakpoint -> {
@ -1431,164 +1430,6 @@ class IRCodeGen(
}
}
private fun translate(postIncrDecr: PtPostIncrDecr): IRCodeChunks {
val result = mutableListOf<IRCodeChunkBase>()
val array = postIncrDecr.target.array
if(array?.splitWords==true) {
val variable = array.variable.name
val fixedIndex = constIntValue(array.index)
if(fixedIndex!=null) {
val skipLabel = createLabelName()
when(postIncrDecr.operator) {
"++" -> {
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.INCM, IRDataType.BYTE, labelSymbol = "${variable}_lsb", symbolOffset = fixedIndex)
it += IRInstruction(Opcode.BSTNE, labelSymbol = skipLabel)
it += IRInstruction(Opcode.INCM, IRDataType.BYTE, labelSymbol = "${variable}_msb", symbolOffset = fixedIndex)
}
result += IRCodeChunk(skipLabel, null)
}
"--" -> {
val valueReg=registers.nextFree()
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOADM, IRDataType.BYTE, reg1=valueReg, labelSymbol = "${variable}_lsb", symbolOffset = fixedIndex)
it += IRInstruction(Opcode.BSTNE, labelSymbol = skipLabel)
it += IRInstruction(Opcode.DECM, IRDataType.BYTE, labelSymbol = "${variable}_msb", symbolOffset = fixedIndex)
}
result += IRCodeChunk(skipLabel, null).also {
it += IRInstruction(Opcode.DECM, IRDataType.BYTE, labelSymbol = "${variable}_lsb", symbolOffset = fixedIndex)
}
}
else -> throw AssemblyError("weird operator")
}
} else {
val indexTr = expressionEval.translateExpression(array.index)
addToResult(result, indexTr, indexTr.resultReg, -1)
val incReg = registers.nextFree()
val skipLabel = createLabelName()
when(postIncrDecr.operator) {
"++" -> {
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, labelSymbol = "${variable}_lsb")
it += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=incReg)
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, labelSymbol = "${variable}_lsb")
it += IRInstruction(Opcode.BSTNE, labelSymbol = skipLabel)
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, labelSymbol = "${variable}_msb")
it += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=incReg)
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, labelSymbol = "${variable}_msb")
}
result += IRCodeChunk(skipLabel, null)
}
"--" -> {
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, labelSymbol = "${variable}_lsb")
it += IRInstruction(Opcode.BSTNE, labelSymbol = skipLabel)
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, labelSymbol = "${variable}_msb")
it += IRInstruction(Opcode.DEC, IRDataType.BYTE, reg1=incReg)
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, labelSymbol = "${variable}_msb")
}
result += IRCodeChunk(skipLabel, null).also {
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, labelSymbol = "${variable}_lsb")
it += IRInstruction(Opcode.DEC, IRDataType.BYTE, reg1=incReg)
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=incReg, reg2=indexTr.resultReg, labelSymbol = "${variable}_lsb")
}
}
else -> throw AssemblyError("weird operator")
}
}
} else {
val ident = postIncrDecr.target.identifier
val memory = postIncrDecr.target.memory
val irDt = irType(postIncrDecr.target.type)
val operationMem: Opcode
val operationRegister: Opcode
when(postIncrDecr.operator) {
"++" -> {
operationMem = Opcode.INCM
operationRegister = Opcode.INC
}
"--" -> {
operationMem = Opcode.DECM
operationRegister = Opcode.DEC
}
else -> throw AssemblyError("weird operator")
}
if(ident!=null) {
addInstr(result, IRInstruction(operationMem, irDt, labelSymbol = ident.name), null)
} else if(memory!=null) {
val constAddress = memory.address as? PtNumber
if(constAddress!=null) {
addInstr(result, IRInstruction(operationMem, irDt, address = constAddress.number.toInt()), null)
return result
}
val ptrWithOffset = memory.address as? PtBinaryExpression
if(ptrWithOffset!=null && ptrWithOffset.operator=="+" && ptrWithOffset.left is PtIdentifier) {
if((ptrWithOffset.right as? PtNumber)?.number?.toInt() in 0..255) {
// LOADIX only works with byte index.
val ptrName = (ptrWithOffset.left as PtIdentifier).name
val offsetReg = registers.nextFree()
val incReg = registers.nextFree()
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=offsetReg, immediate = ptrWithOffset.right.asConstInteger())
it += IRInstruction(Opcode.LOADIX, IRDataType.BYTE, reg1=incReg, reg2=offsetReg, labelSymbol = ptrName)
it += IRInstruction(operationRegister, irDt, reg1 = incReg)
it += IRInstruction(Opcode.STOREIX, IRDataType.BYTE, reg1=incReg, reg2=offsetReg, labelSymbol = ptrName)
}
return result
}
}
val offsetTypecast = ptrWithOffset?.right as? PtTypeCast
if(ptrWithOffset!=null && ptrWithOffset.operator=="+" && ptrWithOffset.left is PtIdentifier
&& (ptrWithOffset.right.type in ByteDatatypes || offsetTypecast?.value?.type in ByteDatatypes)) {
// LOADIX only works with byte index.
val tr = if(offsetTypecast?.value?.type in ByteDatatypes)
expressionEval.translateExpression(offsetTypecast!!.value)
else
expressionEval.translateExpression(ptrWithOffset.right)
addToResult(result, tr, tr.resultReg, -1)
val ptrName = (ptrWithOffset.left as PtIdentifier).name
result += IRCodeChunk(null, null).also {
val incReg = registers.nextFree()
it += IRInstruction(Opcode.LOADIX, IRDataType.BYTE, reg1=incReg, reg2=tr.resultReg, labelSymbol = ptrName)
it += IRInstruction(operationRegister, irDt, reg1 = incReg)
it += IRInstruction(Opcode.STOREIX, IRDataType.BYTE, reg1=incReg, reg2=tr.resultReg, labelSymbol = ptrName)
}
return result
}
val tr = expressionEval.translateExpression(memory.address)
addToResult(result, tr, tr.resultReg, -1)
result += IRCodeChunk(null, null).also {
val incReg = registers.nextFree()
it += IRInstruction(Opcode.LOADI, irDt, reg1 = incReg, reg2 = tr.resultReg)
it += IRInstruction(operationRegister, irDt, reg1 = incReg)
it += IRInstruction(Opcode.STOREI, irDt, reg1 = incReg, reg2 = tr.resultReg)
}
return result
} else if (array!=null) {
val variable = array.variable.name
val itemsize = program.memsizer.memorySize(array.type)
val fixedIndex = constIntValue(array.index)
if(fixedIndex!=null) {
addInstr(result, IRInstruction(operationMem, irDt, labelSymbol = variable, symbolOffset = fixedIndex*itemsize), null)
} else {
val indexTr = expressionEval.translateExpression(array.index)
addToResult(result, indexTr, indexTr.resultReg, -1)
if(itemsize>1)
result += multiplyByConst(IRDataType.BYTE, indexTr.resultReg, itemsize)
result += IRCodeChunk(null, null).also {
val incReg = registers.nextFree()
it += IRInstruction(Opcode.LOADX, irDt, reg1=incReg, reg2=indexTr.resultReg, labelSymbol=variable)
it += IRInstruction(operationRegister, irDt, reg1=incReg)
it += IRInstruction(Opcode.STOREX, irDt, reg1=incReg, reg2=indexTr.resultReg, labelSymbol=variable)
}
}
} else
throw AssemblyError("weird assigntarget")
}
return result
}
private fun translate(repeat: PtRepeatLoop): IRCodeChunks {
when (constIntValue(repeat.count)) {
0 -> return emptyList()

View File

@ -107,18 +107,6 @@ class Inliner(private val program: Program, private val options: CompilationOpti
inline
}
is PostIncrDecr -> {
if (stmt.target.identifier != null) {
makeFullyScoped(stmt.target.identifier!!)
true
} else if (stmt.target.memoryAddress?.addressExpression is NumericLiteral || stmt.target.memoryAddress?.addressExpression is IdentifierReference) {
if (stmt.target.memoryAddress?.addressExpression is IdentifierReference)
makeFullyScoped(stmt.target.memoryAddress?.addressExpression as IdentifierReference)
true
} else
false
}
is Jump -> true
else -> false
}

View File

@ -5,9 +5,11 @@ import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.code.core.*
import prog8.code.core.AssociativeOperators
import prog8.code.core.CompilationOptions
import prog8.code.core.DataType
import prog8.code.core.IErrorReporter
import prog8.code.target.VMTarget
import kotlin.math.floor
class StatementOptimizer(private val program: Program,
@ -185,13 +187,21 @@ class StatementOptimizer(private val program: Program,
val loopvarDt = forLoop.loopVarDt(program)
if(loopvarDt.istype(DataType.UWORD) || loopvarDt.istype(DataType.UBYTE)) {
fun incOrDec(inc: Boolean): Assignment {
val pos = forLoop.position
val loopVar = forLoop.loopVar
val addSubOne = BinaryExpression(loopVar.copy(), if(inc) "+" else "-", NumericLiteral.optimalInteger(1, pos), pos, false)
return Assignment(AssignTarget(loopVar.copy(), null, null, pos), addSubOne, AssignmentOrigin.USERCODE, pos)
}
if (range != null && range.from.constValue(program)?.number == 0.0 && range.step.constValue(program)?.number==1.0) {
val toBinExpr = range.to as? BinaryExpression
if(toBinExpr!=null && toBinExpr.operator=="-" && toBinExpr.right.constValue(program)?.number==1.0) {
// FOR var IN 0 TO X-1 .... ---> var=0, DO {... , var++} UNTIL var==X
val pos = forLoop.position
val condition = BinaryExpression(forLoop.loopVar.copy(), "==", toBinExpr.left, pos)
val incOne = PostIncrDecr(AssignTarget(forLoop.loopVar.copy(), null, null, pos), "++", pos)
val incOne = incOrDec(true)
forLoop.body.statements.add(incOne)
val replacement = AnonymousScope(mutableListOf(
Assignment(AssignTarget(forLoop.loopVar.copy(), null, null, pos),
@ -208,7 +218,7 @@ class StatementOptimizer(private val program: Program,
if (toConst == null) {
// FOR var in 0 TO X ... ---> var=0, REPEAT { ... , IF var==X break , var++ }
val pos = forLoop.position
val incOne = PostIncrDecr(AssignTarget(forLoop.loopVar.copy(), null, null, pos), "++", pos)
val incOne = incOrDec(true)
val breakCondition = IfElse(
BinaryExpression(forLoop.loopVar, "==", range.to, pos),
AnonymousScope(mutableListOf(Break(pos)), pos),
@ -235,7 +245,7 @@ class StatementOptimizer(private val program: Program,
val pos = forLoop.position
val checkValue = NumericLiteral(loopvarDt.getOr(DataType.UNDEFINED), if(loopvarDt.istype(DataType.UBYTE)) 255.0 else 65535.0, pos)
val condition = BinaryExpression(forLoop.loopVar.copy(), "==", checkValue, pos)
val decOne = PostIncrDecr(AssignTarget(forLoop.loopVar.copy(), null, null, pos), "--", pos)
val decOne = incOrDec(false)
forLoop.body.statements.add(decOne)
val replacement = AnonymousScope(mutableListOf(
Assignment(AssignTarget(forLoop.loopVar.copy(), null, null, pos),
@ -390,35 +400,15 @@ class StatementOptimizer(private val program: Program,
// assignments of the form: X = X <operator> <expr>
// remove assignments that have no effect (such as X=X+0)
// optimize/rewrite some other expressions
val targetDt = targetIDt.getOr(DataType.UNDEFINED)
val vardeclDt = (assignment.target.identifier?.targetVarDecl(program))?.type
when (bexpr.operator) {
"+" -> {
if (rightCv == 0.0) {
return listOf(IAstModification.Remove(assignment, parent as IStatementContainer))
} else if (targetDt in IntegerDatatypes && floor(rightCv) == rightCv) {
if (vardeclDt != VarDeclType.MEMORY && rightCv in 1.0..3.0 && options.compTarget.name!=VMTarget.NAME) {
// replace by several INCs if it's not a memory address (inc on a memory mapped register doesn't work very well)
val incs = AnonymousScope(mutableListOf(), assignment.position)
repeat(rightCv.toInt()) {
incs.statements.add(PostIncrDecr(assignment.target.copy(), "++", assignment.position))
}
return listOf(IAstModification.ReplaceNode(assignment, if(incs.statements.size==1) incs.statements[0] else incs, parent))
}
}
}
"-" -> {
if (rightCv == 0.0) {
return listOf(IAstModification.Remove(assignment, parent as IStatementContainer))
} else if (targetDt in IntegerDatatypes && floor(rightCv) == rightCv) {
if (vardeclDt != VarDeclType.MEMORY && rightCv in 1.0..3.0 && options.compTarget.name!=VMTarget.NAME) {
// replace by several DECs if it's not a memory address (dec on a memory mapped register doesn't work very well)
val decs = AnonymousScope(mutableListOf(), assignment.position)
repeat(rightCv.toInt()) {
decs.statements.add(PostIncrDecr(assignment.target.copy(), "--", assignment.position))
}
return listOf(IAstModification.ReplaceNode(assignment, decs, parent))
}
}
}
"*" -> if (rightCv == 1.0) return listOf(IAstModification.Remove(assignment, parent as IStatementContainer))

View File

@ -5,11 +5,11 @@ package prog8.buildversion
*/
const val MAVEN_GROUP = "prog8"
const val MAVEN_NAME = "compiler"
const val VERSION = "10.0"
const val GIT_REVISION = -1
const val GIT_SHA = "cc22861719e36ed842d00d6ca7c29792c2c37b9f"
const val GIT_DATE = "2024-01-19T18:26:41Z"
const val GIT_BRANCH = "master"
const val BUILD_DATE = "2024-01-19T18:58:11Z"
const val BUILD_UNIX_TIME = 1705690691084L
const val VERSION = "10.1"
const val GIT_REVISION = 4443
const val GIT_SHA = "f87494207574000a25174fcf5db973885f49b1b9"
const val GIT_DATE = "2024-02-04T15:22:43Z"
const val GIT_BRANCH = "UNKNOWN"
const val BUILD_DATE = "2024-02-06T17:41:04Z"
const val BUILD_UNIX_TIME = 1707241264826L
const val DIRTY = 1

View File

@ -92,7 +92,7 @@ internal class AstChecker(private val program: Program,
if (iterations < 0 || iterations > 65535)
errors.err("invalid number of unrolls", unrollLoop.position)
unrollLoop.body.statements.forEach {
if (it !is InlineAssembly && it !is Assignment && it !is BuiltinFunctionCallStatement && it !is FunctionCallStatement && it !is PostIncrDecr)
if (it !is InlineAssembly && it !is Assignment && it !is BuiltinFunctionCallStatement && it !is FunctionCallStatement)
errors.err("invalid statement in unroll loop", it.position)
}
if (iterations * unrollLoop.body.statements.size > 256) {
@ -1329,41 +1329,6 @@ internal class AstChecker(private val program: Program,
}
}
override fun visit(postIncrDecr: PostIncrDecr) {
if(postIncrDecr.target.identifier != null) {
val targetName = postIncrDecr.target.identifier!!.nameInSource
val target = postIncrDecr.definingScope.lookup(targetName)
if(target==null) {
val symbol = postIncrDecr.target.identifier!!
errors.undefined(symbol.nameInSource, symbol.position)
} else {
if(target !is VarDecl || target.type== VarDeclType.CONST) {
errors.err("can only increment or decrement a variable", postIncrDecr.position)
} else if(target.datatype !in NumericDatatypes) {
errors.err("cannot increment/decrement this", postIncrDecr.position)
}
}
} else if(postIncrDecr.target.arrayindexed != null) {
val indexed = postIncrDecr.target.arrayindexed!!
val target = indexed.arrayvar.targetStatement(program)
if(target==null) {
errors.undefined(indexed.arrayvar.nameInSource, indexed.arrayvar.position)
}
else {
val dt = (target as VarDecl).datatype
if(dt !in NumericDatatypes && dt !in ArrayDatatypes && dt!=DataType.STR)
errors.err("cannot increment/decrement this", postIncrDecr.position)
}
}
// else if(postIncrDecr.target.memoryAddress != null) { } // a memory location can always be ++/--
if(postIncrDecr.target.inferType(program) istype DataType.BOOL) {
errors.err("can't use boolean operand with this operator ${postIncrDecr.operator}", postIncrDecr.position)
}
super.visit(postIncrDecr)
}
override fun visit(arrayIndexedExpression: ArrayIndexedExpression) {
checkLongType(arrayIndexedExpression)
val target = arrayIndexedExpression.arrayvar.targetStatement(program)

View File

@ -52,7 +52,6 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr
is InlineAssembly -> transform(statement)
is Jump -> transform(statement)
is Label -> transform(statement)
is PostIncrDecr -> transform(statement)
is RepeatLoop -> transform(statement)
is UnrollLoop -> transform(statement)
is Return -> transform(statement)
@ -397,12 +396,6 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr
private fun transform(label: Label): PtLabel =
PtLabel(label.name, label.position)
private fun transform(src: PostIncrDecr): PtPostIncrDecr {
val post = PtPostIncrDecr(src.operator, src.position)
post.add(transform(src.target))
return post
}
private fun transform(srcRepeat: RepeatLoop): PtRepeatLoop {
if(srcRepeat.iterations==null)
throw FatalAstException("repeat-forever loop should have been replaced with label+jump")

View File

@ -149,12 +149,6 @@ internal class ParentNodeChecker: AstWalker() {
return noModifications
}
override fun before(postIncrDecr: PostIncrDecr, parent: Node): Iterable<IAstModification> {
if(postIncrDecr.parent!==parent)
throw FatalAstException("parent node mismatch at $postIncrDecr")
return noModifications
}
override fun before(range: RangeExpression, parent: Node): Iterable<IAstModification> {
if(range.parent!==parent)
throw FatalAstException("parent node mismatch at $range")

View File

@ -225,7 +225,7 @@ class TestOptimization: FunSpec({
uword yy ; to be removed
yy=99 ; to be removed
cx16.r0 = 0
cx16.r0++
rol(cx16.r0)
}
}
}"""

View File

@ -39,7 +39,7 @@ class TestScoping: FunSpec({
sub start() {
repeat 10 {
ubyte xx = 99
xx++
rol(xx)
}
}
}
@ -68,7 +68,7 @@ class TestScoping: FunSpec({
withClue("vardecl in repeat should be replaced by init assignment") {
(initassign?.value as? NumericLiteral)?.number?.toInt() shouldBe 99
}
repeatbody.statements[1] shouldBe instanceOf<PostIncrDecr>()
repeatbody.statements[1] shouldBe instanceOf<FunctionCallStatement>()
}
test("labels with anon scopes") {

View File

@ -8,7 +8,10 @@ import prog8.ast.expressions.AddressOf
import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.NumericLiteral
import prog8.ast.expressions.PrefixExpression
import prog8.ast.statements.*
import prog8.ast.statements.Assignment
import prog8.ast.statements.Block
import prog8.ast.statements.Subroutine
import prog8.ast.statements.VarDecl
import prog8.code.core.Position
import prog8.code.core.SourceCode
import prog8.parser.Prog8Parser
@ -56,7 +59,7 @@ class TestIdentifierRef: FunSpec({
program.addModule(module)
val mstmts = (module.statements.single() as Block).statements
val stmts = mstmts.filterIsInstance<Subroutine>().single().statements
val wwref = (stmts[0] as PostIncrDecr).target.identifier!!
val wwref = (stmts[0] as Assignment).target.identifier!!
val mainref = ((stmts[1] as Assignment).value as AddressOf).identifier
wwref.nameInSource shouldBe listOf("ww")
wwref.wasStringLiteral(program) shouldBe false

View File

@ -653,7 +653,7 @@ class TestProg8Parser: FunSpec( {
sub start() {
repeat {
ubyte xx = 99
xx++
rol(xx)
}
}
}
@ -673,7 +673,7 @@ class TestProg8Parser: FunSpec( {
}
val initvalue = (repeatbody.statements[0] as VarDecl).value as? NumericLiteral
initvalue?.number?.toInt() shouldBe 99
repeatbody.statements[1] shouldBe instanceOf<PostIncrDecr>()
repeatbody.statements[1] shouldBe instanceOf<FunctionCallStatement>()
// the ast processing steps used in the compiler, will eventually move the var up to the containing scope (subroutine).
}

View File

@ -358,11 +358,6 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program:
chainedAssignment.nested.accept(this)
}
override fun visit(postIncrDecr: PostIncrDecr) {
postIncrDecr.target.accept(this)
output(postIncrDecr.operator)
}
override fun visit(breakStmt: Break) {
output("break")
}

View File

@ -93,7 +93,13 @@ private fun StatementContext.toAst() : Statement {
if(augassign!=null) return augassign
postincrdecr()?.let {
return PostIncrDecr(it.assign_target().toAst(), it.operator.text, it.toPosition())
val tgt = it.assign_target().toAst()
val operator = it.operator.text
val pos = it.toPosition()
print("\u001b[92mINFO\u001B[0m ") // bright green
println("${pos}: ++ and -- will be removed in a future version, please use +=1 or -=1 instead.")
val addSubOne = BinaryExpression(tgt.toExpression(), if(operator=="++") "+" else "-", NumericLiteral.optimalInteger(1, pos), pos, false)
return Assignment(tgt, addSubOne, AssignmentOrigin.USERCODE, pos)
}
val directive = directive()?.toAst()

View File

@ -630,27 +630,6 @@ data class AssignTarget(var identifier: IdentifierReference?,
}
class PostIncrDecr(var target: AssignTarget, val operator: String, override val position: Position) : Statement() {
override lateinit var parent: Node
override fun linkParents(parent: Node) {
this.parent = parent
target.linkParents(this)
}
override fun replaceChildNode(node: Node, replacement: Node) {
require(replacement is AssignTarget && node===target)
target = replacement
replacement.parent = this
}
override fun referencesIdentifier(nameInSource: List<String>): Boolean = target.referencesIdentifier(nameInSource)
override fun copy() = PostIncrDecr(target.copy(), operator, position)
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun toString() = "PostIncrDecr(op: $operator, target: $target, pos=$position)"
}
class Jump(var address: UInt?,
val identifier: IdentifierReference?,
val generatedLabel: String?, // can be used in code generation scenarios

View File

@ -122,7 +122,6 @@ abstract class AstWalker {
open fun before(memwrite: DirectMemoryWrite, parent: Node): Iterable<IAstModification> = noModifications
open fun before(module: Module, parent: Node): Iterable<IAstModification> = noModifications
open fun before(numLiteral: NumericLiteral, parent: Node): Iterable<IAstModification> = noModifications
open fun before(postIncrDecr: PostIncrDecr, parent: Node): Iterable<IAstModification> = noModifications
open fun before(program: Program): Iterable<IAstModification> = noModifications
open fun before(range: RangeExpression, parent: Node): Iterable<IAstModification> = noModifications
open fun before(untilLoop: UntilLoop, parent: Node): Iterable<IAstModification> = noModifications
@ -167,7 +166,6 @@ abstract class AstWalker {
open fun after(memwrite: DirectMemoryWrite, parent: Node): Iterable<IAstModification> = noModifications
open fun after(module: Module, parent: Node): Iterable<IAstModification> = noModifications
open fun after(numLiteral: NumericLiteral, parent: Node): Iterable<IAstModification> = noModifications
open fun after(postIncrDecr: PostIncrDecr, parent: Node): Iterable<IAstModification> = noModifications
open fun after(program: Program): Iterable<IAstModification> = noModifications
open fun after(range: RangeExpression, parent: Node): Iterable<IAstModification> = noModifications
open fun after(untilLoop: UntilLoop, parent: Node): Iterable<IAstModification> = noModifications
@ -367,12 +365,6 @@ abstract class AstWalker {
track(after(assignment, parent), assignment, parent)
}
fun visit(postIncrDecr: PostIncrDecr, parent: Node) {
track(before(postIncrDecr, parent), postIncrDecr, parent)
postIncrDecr.target.accept(this, postIncrDecr)
track(after(postIncrDecr, parent), postIncrDecr, parent)
}
fun visit(breakStmt: Break, parent: Node) {
track(before(breakStmt, parent), breakStmt, parent)
track(after(breakStmt, parent), breakStmt, parent)

View File

@ -108,10 +108,6 @@ interface IAstVisitor {
assignment.value.accept(this)
}
fun visit(postIncrDecr: PostIncrDecr) {
postIncrDecr.target.accept(this)
}
fun visit(breakStmt: Break) {
}

View File

@ -1,6 +1,10 @@
TODO
====
- remove ++/-- (just use Pythonesque x+=1): optimize codegen for +=1/-=1
- eventually remove ++/-- from the parser? Or keep it?
(after merge in boolean): move all "OperatorXinplace" from expressionGen to AssignmentGen, see if we can get rid of the Result return type.
...
@ -80,7 +84,6 @@ What if we were to re-introduce Structs in prog8? Some thoughts:
Other language/syntax features to think about
---------------------------------------------
- remove ++/-- (just use Pythonesque x+=1) OR make ++/-- into a postfix expression (but then we need a prefix variant of them too?) maybe via a new builtin function like postincr__w() etc?
- support for assigning multiple return values from romsub/asmsub to multiple variables.
- add (rom/ram)bank support to romsub. A call will then automatically switch banks, use callfar and something else when in banked ram.
challenges: how to not make this too X16 specific? How does the compiler know what bank to switch (ram/rom)?

View File

@ -1,115 +1,18 @@
%import textio
%import floats
%import math
%zeropage basicsafe
%option no_sysinit
main {
sub start() {
; ubyte[10] az
ubyte @shared offset=4
uword @shared az = $4000
ubyte @shared value = 22
ubyte @shared xx
ubyte @shared yy
az[20] |= 99
az[21] &= 99
az[22] ^= 99
az[23] += 99
az[24] -= 99
; az[2000] |= 99
; az[value] |= 99
; az[cx16.r0] |= 99
xx++
yy++
xx--
yy--
; cx16.r0L = az[200]
; cx16.r1L = az[2000]
; cx16.r0L = az[value]
; cx16.r0H = value*4 + az[value]
; cx16.r0L = az[value] + value*4
;
; @($4004) = 99
; az[4]--
; @(az + offset)--
; txt.print_ub(@($4004))
; txt.nl()
; az[4]++
; @(az+offset)++
; txt.print_ub(@($4004))
; txt.nl()
; cx16.r0L = az[4] + value*5
; cx16.r1L = value*5 + az[4]
; ubyte @shared xx
; ubyte[3] ubarr
; uword[3] @split uwarr
; byte[3] sbarr
; bool[3] barr
; float[3] flarr
; bool @shared bb
; uword ptr = &ubarr
;
; ptr[1]++
; ptr[1]++
; ptr[1]--
; txt.print_ub(ubarr[1])
; txt.nl()
; ptr[1]+=4
; ptr[1]-=3
; txt.print_ub(ubarr[1])
; txt.nl()
; sbarr[1] = sbarr[1] == 0
; sbarr[1] = sbarr[1] != 0
; sbarr[1] = sbarr[1] < 0
; sbarr[1] = sbarr[1] <= 0
; sbarr[1] = sbarr[1] > 0
; sbarr[1] = sbarr[1] >= 0
;
; xx = 1
;
; sbarr[xx] = sbarr[xx] == 0
; sbarr[xx] = sbarr[xx] != 0
; sbarr[xx] = sbarr[xx] < 0
; sbarr[xx] = sbarr[xx] <= 0
; sbarr[xx] = sbarr[xx] > 0
; sbarr[xx] = sbarr[xx] >= 0
; sbarr[1] = sbarr[1] == 2
; sbarr[1] = sbarr[1] != 2
; sbarr[1] = sbarr[1] < 2
; sbarr[1] = sbarr[1] <= 2
; sbarr[1] = sbarr[1] > 2
; sbarr[1] = sbarr[1] >= 2
; xx = 1
; sbarr[xx] = sbarr[xx] == 2
; sbarr[xx] = sbarr[xx] != 2
; sbarr[xx] = sbarr[xx] < 2
; sbarr[xx] = sbarr[xx] <= 2
; sbarr[xx] = sbarr[xx] > 2
; sbarr[xx] = sbarr[xx] >= 2
; ubarr[1] = ubarr[1] == 2
; ubarr[1] = ubarr[1] < 2
; ubarr[1] = ubarr[1] <= 2
; ubarr[1] = ubarr[1] > 3
; ubarr[1] = ubarr[1] >= 3
; barr[1] = barr[0] and barr[2]
; barr[1] = barr[0] or barr[2]
; barr[1] = barr[0] xor barr[2]
; barr[1] = not barr[0]
;
; ubarr[1] = 999
; ubarr[1] = ubarr[1]==999
; txt.print_uw(ubarr[1])
;
; barr[1] = barr[1] and bb
; barr[1] = barr[1] or bb
; barr[1] = barr[1] xor bb
;
; bb = bb and barr[1]
; bb = bb or barr[1]
; bb = bb xor barr[1]
; bb = not bb
xx+=1
yy-=1
}
}