mirror of
				https://github.com/irmen/prog8.git
				synced 2025-11-03 19:16:13 +00:00 
			
		
		
		
	add if-expression versions for the conditionals if_cc, if_cs, if_vc etc
This commit is contained in:
		@@ -860,7 +860,7 @@ class AsmGen6502Internal (
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun branchInstruction(condition: BranchCondition, complement: Boolean) =
 | 
			
		||||
    internal fun branchInstruction(condition: BranchCondition, complement: Boolean) =
 | 
			
		||||
            if(complement) {
 | 
			
		||||
                when (condition) {
 | 
			
		||||
                    BranchCondition.CS -> "bcc"
 | 
			
		||||
@@ -1698,6 +1698,10 @@ $repeatLabel""")
 | 
			
		||||
        ifExpressionAsmgen.assignIfExpression(target, value)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    internal fun assignBranchCondExpression(target: AsmAssignTarget, value: PtBranchCondExpression) {
 | 
			
		||||
        ifExpressionAsmgen.assignBranchCondExpression(target, value)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    internal fun cmpAwithByteValue(value: PtExpression, useSbc: Boolean) {
 | 
			
		||||
        val compare = if(useSbc) "sec |  sbc" else "cmp"
 | 
			
		||||
        fun cmpViaScratch() {
 | 
			
		||||
 
 | 
			
		||||
@@ -44,6 +44,69 @@ internal class IfExpressionAsmGen(private val asmgen: AsmGen6502Internal, privat
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    internal fun assignBranchCondExpression(target: AsmAssignTarget, expr: PtBranchCondExpression) {
 | 
			
		||||
        require(target.datatype==expr.type ||
 | 
			
		||||
                target.datatype.isUnsignedWord && (expr.type.isString || expr.type.isPointer) ||
 | 
			
		||||
                target.datatype.isPointer && (expr.type.isUnsignedWord || expr.type.isPointer || expr.type.isString))
 | 
			
		||||
 | 
			
		||||
        if(target.kind==TargetStorageKind.REGISTER && target.datatype.isUnsignedByte && target.register==RegisterOrPair.A) {
 | 
			
		||||
            if(expr.condition==BranchCondition.CC) {
 | 
			
		||||
                if(expr.truevalue.asConstInteger()==0 && expr.falsevalue.asConstInteger()==1) {
 | 
			
		||||
                    asmgen.out("  lda  #0 |  rol a")
 | 
			
		||||
                    return
 | 
			
		||||
                }
 | 
			
		||||
                else if(expr.truevalue.asConstInteger()==1 && expr.falsevalue.asConstInteger()==0) {
 | 
			
		||||
                    asmgen.out("  lda  #0 |  rol a |  eor  #1")
 | 
			
		||||
                    return
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else if(expr.condition==BranchCondition.CS) {
 | 
			
		||||
                if(expr.truevalue.asConstInteger()==0 && expr.falsevalue.asConstInteger()==1) {
 | 
			
		||||
                    asmgen.out("  lda  #0 |  rol a |  eor  #1")
 | 
			
		||||
                    return
 | 
			
		||||
                }
 | 
			
		||||
                else if(expr.truevalue.asConstInteger()==1 && expr.falsevalue.asConstInteger()==0) {
 | 
			
		||||
                    asmgen.out("  lda  #0 |  rol a")
 | 
			
		||||
                    return
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val trueLabel = asmgen.makeLabel("branchexpr_true")
 | 
			
		||||
        val endLabel = asmgen.makeLabel("branchexpr_end")
 | 
			
		||||
        val branch = asmgen.branchInstruction(expr.condition, false)
 | 
			
		||||
 | 
			
		||||
        asmgen.out("  $branch  $trueLabel")
 | 
			
		||||
 | 
			
		||||
        when {
 | 
			
		||||
            expr.type.isByteOrBool -> {
 | 
			
		||||
                asmgen.assignExpressionToRegister(expr.falsevalue, RegisterOrPair.A)
 | 
			
		||||
                asmgen.jmp(endLabel)
 | 
			
		||||
                asmgen.out(trueLabel)
 | 
			
		||||
                asmgen.assignExpressionToRegister(expr.truevalue, RegisterOrPair.A)
 | 
			
		||||
                asmgen.out(endLabel)
 | 
			
		||||
                assignmentAsmGen.assignRegisterByte(target, CpuRegister.A, false, false)
 | 
			
		||||
            }
 | 
			
		||||
            expr.type.isWord || expr.type.isString -> {
 | 
			
		||||
                asmgen.assignExpressionToRegister(expr.falsevalue, RegisterOrPair.AY)
 | 
			
		||||
                asmgen.jmp(endLabel)
 | 
			
		||||
                asmgen.out(trueLabel)
 | 
			
		||||
                asmgen.assignExpressionToRegister(expr.truevalue, RegisterOrPair.AY)
 | 
			
		||||
                asmgen.out(endLabel)
 | 
			
		||||
                assignmentAsmGen.assignRegisterpairWord(target, RegisterOrPair.AY)
 | 
			
		||||
            }
 | 
			
		||||
            expr.type.isFloat -> {
 | 
			
		||||
                asmgen.assignExpressionToRegister(expr.falsevalue, RegisterOrPair.FAC1, true)
 | 
			
		||||
                asmgen.jmp(endLabel)
 | 
			
		||||
                asmgen.out(trueLabel)
 | 
			
		||||
                asmgen.assignExpressionToRegister(expr.truevalue, RegisterOrPair.FAC1, true)
 | 
			
		||||
                asmgen.out(endLabel)
 | 
			
		||||
                asmgen.assignRegister(RegisterOrPair.FAC1, target)
 | 
			
		||||
            }
 | 
			
		||||
            else -> throw AssemblyError("weird dt")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun evalIfExpressionConditonAndBranchWhenFalse(condition: PtExpression, falseLabel: String) {
 | 
			
		||||
        when (condition) {
 | 
			
		||||
            is PtBinaryExpression -> {
 | 
			
		||||
 
 | 
			
		||||
@@ -526,6 +526,7 @@ internal class AssignmentAsmGen(
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            is PtIfExpression -> asmgen.assignIfExpression(assign.target, value)
 | 
			
		||||
            is PtBranchCondExpression -> asmgen.assignBranchCondExpression(assign.target, value)
 | 
			
		||||
            is PtPointerDeref -> pointergen.assignPointerDerefExpression(assign.target, value)
 | 
			
		||||
            else -> throw AssemblyError("weird assignment value type $value")
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -83,6 +83,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
 | 
			
		||||
            is PtArrayIndexer -> translate(expr)
 | 
			
		||||
            is PtBinaryExpression -> translate(expr)
 | 
			
		||||
            is PtIfExpression -> translate(expr)
 | 
			
		||||
            is PtBranchCondExpression -> translate(expr)
 | 
			
		||||
            is PtBuiltinFunctionCall -> codeGen.translateBuiltinFunc(expr)
 | 
			
		||||
            is PtFunctionCall -> translate(expr)
 | 
			
		||||
            is PtContainmentCheck -> translate(expr)
 | 
			
		||||
@@ -253,6 +254,69 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun translate(branchExpr: PtBranchCondExpression): ExpressionCodeResult {
 | 
			
		||||
        val result = mutableListOf<IRCodeChunkBase>()
 | 
			
		||||
        val trueTr = translateExpression(branchExpr.truevalue)
 | 
			
		||||
        val falseTr = translateExpression(branchExpr.falsevalue)
 | 
			
		||||
        val trueLabel = codeGen.createLabelName()
 | 
			
		||||
        val endLabel = codeGen.createLabelName()
 | 
			
		||||
        val irDt = irType(branchExpr.type)
 | 
			
		||||
 | 
			
		||||
        if(branchExpr.condition==BranchCondition.CC && irDt==IRDataType.BYTE) {
 | 
			
		||||
            if(branchExpr.truevalue.asConstInteger()==0 && branchExpr.falsevalue.asConstInteger()==1) {
 | 
			
		||||
                result.add(IRCodeChunk(null, null).also {
 | 
			
		||||
                    it += IRInstruction(Opcode.LOAD, irDt, reg1=trueTr.resultReg, immediate = 0)
 | 
			
		||||
                    it += IRInstruction(Opcode.ROXL, irDt, reg1=trueTr.resultReg)
 | 
			
		||||
                })
 | 
			
		||||
                return ExpressionCodeResult(result, irDt, trueTr.resultReg, -1)
 | 
			
		||||
            }
 | 
			
		||||
            else if(branchExpr.truevalue.asConstInteger()==1 && branchExpr.falsevalue.asConstInteger()==0) {
 | 
			
		||||
                result.add(IRCodeChunk(null, null).also {
 | 
			
		||||
                    it += IRInstruction(Opcode.LOAD, irDt, reg1=trueTr.resultReg, immediate = 0)
 | 
			
		||||
                    it += IRInstruction(Opcode.ROXL, irDt, reg1=trueTr.resultReg)
 | 
			
		||||
                    it += IRInstruction(Opcode.XOR, irDt, reg1=trueTr.resultReg, immediate = 1)
 | 
			
		||||
                })
 | 
			
		||||
                return ExpressionCodeResult(result, irDt, trueTr.resultReg, -1)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else if(branchExpr.condition==BranchCondition.CS) {
 | 
			
		||||
            if(branchExpr.truevalue.asConstInteger()==0 && branchExpr.falsevalue.asConstInteger()==1) {
 | 
			
		||||
                result.add(IRCodeChunk(null, null).also {
 | 
			
		||||
                    it += IRInstruction(Opcode.LOAD, irDt, reg1=trueTr.resultReg, immediate = 0)
 | 
			
		||||
                    it += IRInstruction(Opcode.ROXL, irDt, reg1=trueTr.resultReg)
 | 
			
		||||
                    it += IRInstruction(Opcode.XOR, irDt, reg1=trueTr.resultReg, immediate = 1)
 | 
			
		||||
                })
 | 
			
		||||
                return ExpressionCodeResult(result, irDt, trueTr.resultReg, -1)
 | 
			
		||||
            }
 | 
			
		||||
            else if(branchExpr.truevalue.asConstInteger()==1 && branchExpr.falsevalue.asConstInteger()==0) {
 | 
			
		||||
                result.add(IRCodeChunk(null, null).also {
 | 
			
		||||
                    it += IRInstruction(Opcode.LOAD, irDt, reg1=trueTr.resultReg, immediate = 0)
 | 
			
		||||
                    it += IRInstruction(Opcode.ROXL, irDt, reg1=trueTr.resultReg)
 | 
			
		||||
                })
 | 
			
		||||
                return ExpressionCodeResult(result, irDt, trueTr.resultReg, -1)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val branchInstr = codeGen.IRBranchInstr(branchExpr.condition, trueLabel)
 | 
			
		||||
        addInstr(result, branchInstr, null)
 | 
			
		||||
 | 
			
		||||
        if (irDt != IRDataType.FLOAT) {
 | 
			
		||||
            addToResult(result, falseTr, trueTr.resultReg, -1)
 | 
			
		||||
            addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = endLabel), null)
 | 
			
		||||
            result += IRCodeChunk(trueLabel, null)
 | 
			
		||||
            addToResult(result, trueTr, trueTr.resultReg, -1)
 | 
			
		||||
            result += IRCodeChunk(endLabel, null)
 | 
			
		||||
            return ExpressionCodeResult(result, irDt, trueTr.resultReg, -1)
 | 
			
		||||
        } else {
 | 
			
		||||
            addToResult(result, falseTr, -1, trueTr.resultFpReg)
 | 
			
		||||
            addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = endLabel), null)
 | 
			
		||||
            result += IRCodeChunk(trueLabel, null)
 | 
			
		||||
            addToResult(result, trueTr, -1, trueTr.resultFpReg)
 | 
			
		||||
            result += IRCodeChunk(endLabel, null)
 | 
			
		||||
            return ExpressionCodeResult(result, irDt, -1, trueTr.resultFpReg)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun translate(expr: PtAddressOf): ExpressionCodeResult {
 | 
			
		||||
        val vmDt = irType(expr.type)
 | 
			
		||||
        // note: LOAD <symbol>  gets you the address of the symbol, whereas LOADM <symbol> would get you the value stored at that location
 | 
			
		||||
 
 | 
			
		||||
@@ -336,7 +336,7 @@ class IRCodeGen(
 | 
			
		||||
        return result
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun IRBranchInstr(condition: BranchCondition, label: String?=null, address: Int?=null): IRInstruction {
 | 
			
		||||
    internal fun IRBranchInstr(condition: BranchCondition, label: String?=null, address: Int?=null): IRInstruction {
 | 
			
		||||
        if(label!=null)
 | 
			
		||||
            return when(condition) {
 | 
			
		||||
                BranchCondition.CS -> IRInstruction(Opcode.BSTCS, labelSymbol = label)
 | 
			
		||||
 
 | 
			
		||||
@@ -54,6 +54,7 @@ class IRPeepholeOptimizer(private val irprog: IRProgram) {
 | 
			
		||||
                                || removeDoubleSecClc(chunk1, indexedInstructions)
 | 
			
		||||
                                || cleanupPushPop(chunk1, indexedInstructions)
 | 
			
		||||
                                || simplifyConstantReturns(chunk1, indexedInstructions)
 | 
			
		||||
                                || removeNeedlessLoads(chunk1, indexedInstructions)
 | 
			
		||||
                    } while (changed)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -353,6 +354,29 @@ class IRPeepholeOptimizer(private val irprog: IRProgram) {
 | 
			
		||||
        return changed
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun removeNeedlessLoads(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<IRInstruction>>): Boolean {
 | 
			
		||||
        /*
 | 
			
		||||
load.b r2,#2
 | 
			
		||||
loadr.b r1,r2
 | 
			
		||||
jump p8_label_gen_2
 | 
			
		||||
         */
 | 
			
		||||
        var changed=false
 | 
			
		||||
        indexedInstructions.reversed().forEach { (idx, ins) ->
 | 
			
		||||
            if(idx>=2 && ins.opcode in OpcodesThatJump) {
 | 
			
		||||
                val previous = indexedInstructions[idx-1].value
 | 
			
		||||
                val previous2 = indexedInstructions[idx-2].value
 | 
			
		||||
                if(previous.opcode==Opcode.LOADR && previous2.opcode in OpcodesThatLoad) {
 | 
			
		||||
                    if(previous.reg2==previous2.reg1) {
 | 
			
		||||
                        chunk.instructions[idx-2] = previous2.copy(reg1=previous.reg1)
 | 
			
		||||
                        chunk.instructions.removeAt(idx-1)
 | 
			
		||||
                        changed=true
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return changed
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun removeUselessArithmetic(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<IRInstruction>>): Boolean {
 | 
			
		||||
        // note: this is hard to solve for the non-immediate instructions atm because the values are loaded into registers first
 | 
			
		||||
        var changed = false
 | 
			
		||||
 
 | 
			
		||||
@@ -100,6 +100,7 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
 | 
			
		||||
            is StringLiteral -> transform(expr)
 | 
			
		||||
            is TypecastExpression -> transform(expr)
 | 
			
		||||
            is IfExpression -> transform(expr)
 | 
			
		||||
            is BranchConditionExpression -> transform(expr)
 | 
			
		||||
            is PtrDereference -> transform(expr)
 | 
			
		||||
            is StaticStructInitializer -> transform(expr)
 | 
			
		||||
            is ArrayIndexedPtrDereference -> throw FatalAstException("this should have been converted to some other ast nodes")
 | 
			
		||||
@@ -141,6 +142,14 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
 | 
			
		||||
        return ifexpr
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun transform(branchExpr: BranchConditionExpression): PtBranchCondExpression {
 | 
			
		||||
        val type = branchExpr.inferType(program).getOrElse { throw FatalAstException("unknown dt") }
 | 
			
		||||
        val bexpr = PtBranchCondExpression(branchExpr.condition, type, branchExpr.position)
 | 
			
		||||
        bexpr.add(transformExpression(branchExpr.truevalue))
 | 
			
		||||
        bexpr.add(transformExpression(branchExpr.falsevalue))
 | 
			
		||||
        return bexpr
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun transform(srcDefer: Defer): PtDefer {
 | 
			
		||||
        val defer = PtDefer(srcDefer.position)
 | 
			
		||||
        srcDefer.scope.statements.forEach {
 | 
			
		||||
 
 | 
			
		||||
@@ -66,6 +66,13 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program:
 | 
			
		||||
        ifExpr.falsevalue.accept(this)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun visit(branchExpr: BranchConditionExpression) {
 | 
			
		||||
        output("if_${branchExpr.condition.name.lowercase()} ")
 | 
			
		||||
        branchExpr.truevalue.accept(this)
 | 
			
		||||
        output(" else ")
 | 
			
		||||
        branchExpr.falsevalue.accept(this)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun visit(continueStmt: Continue) {
 | 
			
		||||
        output("continue")
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -551,10 +551,10 @@ class Antlr2KotlinVisitor(val source: SourceCode): AbstractParseTreeVisitor<Node
 | 
			
		||||
        return IfExpression(condition, truevalue, falsevalue, ctx.toPosition())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun visitBranchcondition_expression(ctx: Branchcondition_expressionContext): IfExpression {
 | 
			
		||||
        val branchcondition = branchCondition(ctx.branchcondition())
 | 
			
		||||
    override fun visitBranchcondition_expression(ctx: Branchcondition_expressionContext): BranchConditionExpression {
 | 
			
		||||
        val condition = branchCondition(ctx.branchcondition())
 | 
			
		||||
        val (truevalue, falsevalue) = ctx.expression().map { it.accept(this) as Expression }
 | 
			
		||||
        throw SyntaxError("branchcondition expression not yet supported", ctx.toPosition())
 | 
			
		||||
        return BranchConditionExpression(condition, truevalue, falsevalue, ctx.toPosition())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun visitBranch_stmt(ctx: Branch_stmtContext): ConditionalBranch {
 | 
			
		||||
 
 | 
			
		||||
@@ -1660,6 +1660,42 @@ class IfExpression(var condition: Expression, var truevalue: Expression, var fal
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class BranchConditionExpression(var condition: BranchCondition, var truevalue: Expression, var falsevalue: Expression, override val position: Position) : Expression() {
 | 
			
		||||
 | 
			
		||||
    override lateinit var parent: Node
 | 
			
		||||
 | 
			
		||||
    override fun linkParents(parent: Node) {
 | 
			
		||||
        this.parent = parent
 | 
			
		||||
        truevalue.linkParents(this)
 | 
			
		||||
        falsevalue.linkParents(this)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override val isSimple: Boolean = truevalue.isSimple && falsevalue.isSimple
 | 
			
		||||
 | 
			
		||||
    override fun constValue(program: Program) = null
 | 
			
		||||
    override fun toString() = "BranchExpr(cond=$condition, true=$truevalue, false=$falsevalue, pos=$position)"
 | 
			
		||||
    override fun accept(visitor: IAstVisitor) = visitor.visit(this)
 | 
			
		||||
    override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
 | 
			
		||||
    override fun referencesIdentifier(nameInSource: List<String>): Boolean = truevalue.referencesIdentifier(nameInSource) || falsevalue.referencesIdentifier(nameInSource)
 | 
			
		||||
    override fun inferType(program: Program): InferredTypes.InferredType {
 | 
			
		||||
        val t1 = truevalue.inferType(program)
 | 
			
		||||
        val t2 = falsevalue.inferType(program)
 | 
			
		||||
        if(t1==t2) return t1
 | 
			
		||||
        if(t1.isPointer && t2.isUnsignedWord || t1.isUnsignedWord && t2.isPointer) return InferredTypes.knownFor(BaseDataType.UWORD)
 | 
			
		||||
        return InferredTypes.unknown()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun copy(): Expression = BranchConditionExpression(condition, truevalue.copy(), falsevalue.copy(), position)
 | 
			
		||||
 | 
			
		||||
    override fun replaceChildNode(node: Node, replacement: Node) {
 | 
			
		||||
        if(replacement !is Expression)
 | 
			
		||||
            throw FatalAstException("invalid replace")
 | 
			
		||||
        else if(node===truevalue) truevalue=replacement
 | 
			
		||||
        else if(node===falsevalue) falsevalue=replacement
 | 
			
		||||
        else throw FatalAstException("invalid replace")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class PtrDereference(
 | 
			
		||||
    val chain: List<String>,
 | 
			
		||||
    val derefLast: Boolean,
 | 
			
		||||
 
 | 
			
		||||
@@ -114,6 +114,7 @@ abstract class AstWalker {
 | 
			
		||||
    open fun before(expr: BinaryExpression, parent: Node): Iterable<IAstModification> = noModifications
 | 
			
		||||
    open fun before(expr: PrefixExpression, parent: Node): Iterable<IAstModification> = noModifications
 | 
			
		||||
    open fun before(ifExpr: IfExpression, parent: Node): Iterable<IAstModification> = noModifications
 | 
			
		||||
    open fun before(branchExpr: BranchConditionExpression, parent: Node): Iterable<IAstModification> = noModifications
 | 
			
		||||
    open fun before(forLoop: ForLoop, parent: Node): Iterable<IAstModification> = noModifications
 | 
			
		||||
    open fun before(repeatLoop: RepeatLoop, parent: Node): Iterable<IAstModification> = noModifications
 | 
			
		||||
    open fun before(unrollLoop: UnrollLoop, parent: Node): Iterable<IAstModification> = noModifications
 | 
			
		||||
@@ -165,6 +166,7 @@ abstract class AstWalker {
 | 
			
		||||
    open fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> = noModifications
 | 
			
		||||
    open fun after(expr: PrefixExpression, parent: Node): Iterable<IAstModification> = noModifications
 | 
			
		||||
    open fun after(ifExpr: IfExpression, parent: Node): Iterable<IAstModification> = noModifications
 | 
			
		||||
    open fun after(branchExpr: BranchConditionExpression, parent: Node): Iterable<IAstModification> = noModifications
 | 
			
		||||
    open fun after(forLoop: ForLoop, parent: Node): Iterable<IAstModification> = noModifications
 | 
			
		||||
    open fun after(repeatLoop: RepeatLoop, parent: Node): Iterable<IAstModification> = noModifications
 | 
			
		||||
    open fun after(unrollLoop: UnrollLoop, parent: Node): Iterable<IAstModification> = noModifications
 | 
			
		||||
@@ -510,6 +512,13 @@ abstract class AstWalker {
 | 
			
		||||
        track(after(ifExpr, parent), ifExpr, parent)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun visit(branchExpr: BranchConditionExpression, parent: Node) {
 | 
			
		||||
        track(before(branchExpr, parent), branchExpr, parent)
 | 
			
		||||
        branchExpr.truevalue.accept(this, branchExpr)
 | 
			
		||||
        branchExpr.falsevalue.accept(this, branchExpr)
 | 
			
		||||
        track(after(branchExpr, parent), branchExpr, parent)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun visit(inlineAssembly: InlineAssembly, parent: Node) {
 | 
			
		||||
        track(before(inlineAssembly, parent), inlineAssembly, parent)
 | 
			
		||||
        track(after(inlineAssembly, parent), inlineAssembly, parent)
 | 
			
		||||
 
 | 
			
		||||
@@ -100,6 +100,11 @@ interface IAstVisitor {
 | 
			
		||||
        ifExpr.falsevalue.accept(this)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun visit(branchExpr: BranchConditionExpression) {
 | 
			
		||||
        branchExpr.truevalue.accept(this)
 | 
			
		||||
        branchExpr.falsevalue.accept(this)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun visit(label: Label) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -742,6 +742,12 @@ An example, to select the number of cards to use depending on what game is playe
 | 
			
		||||
    else
 | 
			
		||||
        numcards = 52
 | 
			
		||||
 | 
			
		||||
The expression form is also available for the conditionals ``if_cc``, ``if_cs``, ``if_z`` etc.
 | 
			
		||||
(These particular variants for checking the value of the Carry status bit actually compile into very efficient branchless assembly code)::
 | 
			
		||||
 | 
			
		||||
    ubyte carryvalue = if_cs 1 else 0
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
on .. goto / on .. call statement (jump table)
 | 
			
		||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | 
			
		||||
 
 | 
			
		||||
@@ -78,7 +78,6 @@ STRUCTS and TYPED POINTERS
 | 
			
		||||
Future Things and Ideas
 | 
			
		||||
^^^^^^^^^^^^^^^^^^^^^^^
 | 
			
		||||
 | 
			
		||||
- add if-expression versions for the conditionals if_cc, if_cs, if_vc etc etc   so you can write  a = b + if_cs 1 else 0   (make sure it gets compiled to nice instructions lda #0; rol a etc.)  See visitBranchcondition_expression()
 | 
			
		||||
- %breakpoint after an assignment is parsed as part of the expression (x % breakpoint), that should not happen
 | 
			
		||||
- when a complete block is removed because unused, suppress all info messages about everything in the block being removed
 | 
			
		||||
- fix the line, cols in Position, sometimes they count from 0 sometimes from 1
 | 
			
		||||
 
 | 
			
		||||
@@ -1,19 +1,42 @@
 | 
			
		||||
%import textio
 | 
			
		||||
%zeropage basicsafe
 | 
			
		||||
 | 
			
		||||
main {
 | 
			
		||||
    struct Node {
 | 
			
		||||
        ubyte id
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ^^byte @shared bptr = 2000
 | 
			
		||||
    ^^word @shared swptr = 2000
 | 
			
		||||
    ^^uword @shared uwptr = 2000
 | 
			
		||||
    ^^Node @shared node = 2000
 | 
			
		||||
 | 
			
		||||
    sub start() {
 | 
			
		||||
        alias nid = node.id
 | 
			
		||||
        cx16.r0 = mkword(0, cx16.r9L)
 | 
			
		||||
        swptr^^ = mkword(0, cx16.r9L) as word
 | 
			
		||||
        uwptr^^ = mkword(0, cx16.r9L)
 | 
			
		||||
        sys.set_carry()
 | 
			
		||||
        txt.print_ub(if_cc 0 else 1)
 | 
			
		||||
        txt.nl()
 | 
			
		||||
        sys.clear_carry()
 | 
			
		||||
        txt.print_ub(if_cc 0 else 1)
 | 
			
		||||
        txt.nl()
 | 
			
		||||
        sys.set_carry()
 | 
			
		||||
        txt.print_ub(if_cs 0 else 1)
 | 
			
		||||
        txt.nl()
 | 
			
		||||
        sys.clear_carry()
 | 
			
		||||
        txt.print_ub(if_cs 0 else 1)
 | 
			
		||||
        txt.nl()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
;%import textio
 | 
			
		||||
;%zeropage basicsafe
 | 
			
		||||
;
 | 
			
		||||
;main {
 | 
			
		||||
;    struct Node {
 | 
			
		||||
;        ubyte id
 | 
			
		||||
;        str name
 | 
			
		||||
;        uword array
 | 
			
		||||
;    }
 | 
			
		||||
;
 | 
			
		||||
;    ^^Node @shared @zp node = 2000
 | 
			
		||||
;
 | 
			
		||||
;    sub start() {
 | 
			
		||||
;        txt.print_uw(node)
 | 
			
		||||
;        txt.spc()
 | 
			
		||||
;        cx16.r0 = &node.array       ; TODO don't clobber node pointer itself!!
 | 
			
		||||
;        txt.print_uw(cx16.r0)
 | 
			
		||||
;        txt.spc()
 | 
			
		||||
;        txt.print_uw(node)
 | 
			
		||||
;        txt.nl()
 | 
			
		||||
;    }
 | 
			
		||||
;}
 | 
			
		||||
 
 | 
			
		||||
@@ -514,6 +514,23 @@ val OpcodesThatDependOnCarry = arrayOf(
 | 
			
		||||
    Opcode.ROXRM
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
val OpcodesThatLoad = arrayOf(
 | 
			
		||||
    Opcode.LOAD,
 | 
			
		||||
    Opcode.LOADM,
 | 
			
		||||
    Opcode.LOADI,
 | 
			
		||||
    Opcode.LOADX,
 | 
			
		||||
    Opcode.LOADIX,
 | 
			
		||||
    Opcode.LOADR,
 | 
			
		||||
    Opcode.LOADHA,
 | 
			
		||||
    Opcode.LOADHX,
 | 
			
		||||
    Opcode.LOADHY,
 | 
			
		||||
    Opcode.LOADHAX,
 | 
			
		||||
    Opcode.LOADHAY,
 | 
			
		||||
    Opcode.LOADHXY,
 | 
			
		||||
    Opcode.LOADFIELD,
 | 
			
		||||
    Opcode.LOADHFACZERO,
 | 
			
		||||
    Opcode.LOADHFACONE
 | 
			
		||||
)
 | 
			
		||||
val OpcodesThatSetStatusbits = OpcodesThatSetStatusbitsButNotCarry + OpcodesThatSetStatusbitsIncludingCarry
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -141,6 +141,7 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit
 | 
			
		||||
            is PtPointerDeref -> false
 | 
			
		||||
            is PtTypeCast -> value.isSimple()
 | 
			
		||||
            is PtIfExpression -> condition.isSimple() && truevalue.isSimple() && falsevalue.isSimple()
 | 
			
		||||
            is PtBranchCondExpression -> truevalue.isSimple() && falsevalue.isSimple()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -259,6 +260,12 @@ class PtIfExpression(type: DataType, position: Position): PtExpression(type, pos
 | 
			
		||||
        get() = children[2] as PtExpression
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class PtBranchCondExpression(val condition: BranchCondition, type: DataType, position: Position): PtExpression(type, position) {
 | 
			
		||||
    val truevalue: PtExpression
 | 
			
		||||
        get() = children[0] as PtExpression
 | 
			
		||||
    val falsevalue: PtExpression
 | 
			
		||||
        get() = children[1] as PtExpression
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class PtContainmentCheck(position: Position): PtExpression(DataType.BOOL, position) {
 | 
			
		||||
    val needle: PtExpression
 | 
			
		||||
 
 | 
			
		||||
@@ -188,6 +188,7 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni
 | 
			
		||||
            }
 | 
			
		||||
            is PtDefer -> "<defer>"
 | 
			
		||||
            is PtIfExpression -> "<ifexpr>"
 | 
			
		||||
            is PtBranchCondExpression -> "<branchexpr> if_${node.condition.name.lowercase()}"
 | 
			
		||||
            is PtJmpTable -> "<jmptable>"
 | 
			
		||||
            is PtStructDecl -> {
 | 
			
		||||
                "struct ${node.name} { " + node.fields.joinToString("  ") { "${it.first} ${it.second}" } + " }"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user