Instructions

Spremenite prevajalnik tako, da za operatorja or in and v pogojui if ali while stavka velja kratkostični izračun, torej

Z drugimi besedami, če se da rezultat operacije ugotoviti samo na osnovi vrednosti levega operanda, se vrednosti desnega operanda ne računa. Če sta tovrstna operatorja uporabljena drugje, zanje velja običajni način izračuna.

Test

fun puts(s: ^char): void
fun putchar(c: char): void

fun returnTrue(): bool =
	puts("True"),
	putchar('\0x0A'),
	return true

fun returnFalse(): bool =
	puts("False"),
	putchar('\0x0A'),
	return false

fun main(): int =
	if
		returnTrue() | returnTrue()
	then
		return 0
	end,
	return 1

Out

Before

After

Code

/imclin/LinearizeImc.java

public class LinearizeImc implements IMC.FullVisitor<IMC.Expr, LinearizeImc.Info> {
    // ... other code ...
 
    @Override
    public IMC.Expr visit(IMC.CJUMP cjump, Info info) {
        info.allowCall = false;
 
        IMC.Expr linearizedPosAddr = cjump.posAddr.accept(this, info);
        IMC.Expr linearizedNegAddr = cjump.negAddr.accept(this, info);
 
// --- CHANGED: Special handling for short-circuit AND/OR in CJUMP ---
        if (cjump.cond instanceof IMC.BINOP condBinop && condBinop.oper == IMC.BINOP.Oper.AND) {
            // Short-circuit AND: if first is false, jump to neg; if true, check second
            IMC.Expr linearizedCondFst = condBinop.fstExpr.accept(this, info);
 
            MEM.Label fstFalse = new MEM.Label();
            MEM.Label fstTrue = new MEM.Label();
            info.linearizedImcStmts.addLast(
                new IMC.CJUMP(linearizedCondFst, new IMC.NAME(fstTrue), new IMC.NAME(fstFalse))
            );
 
            info.linearizedImcStmts.addLast(new IMC.LABEL(fstFalse));
            info.linearizedImcStmts.addLast(new IMC.JUMP(linearizedNegAddr));
 
            info.linearizedImcStmts.addLast(new IMC.LABEL(fstTrue));
            IMC.Expr linearizedCondSnd = condBinop.sndExpr.accept(this, info);
            info.linearizedImcStmts.addLast(new IMC.CJUMP(linearizedCondSnd, linearizedPosAddr, linearizedNegAddr));
        }
        else if (cjump.cond instanceof IMC.BINOP condBinop && condBinop.oper == IMC.BINOP.Oper.OR) {
            // Short-circuit OR: if first is true, jump to pos; if false, check second
            IMC.Expr linearizedCondFst = condBinop.fstExpr.accept(this, info);
 
            MEM.Label fstFalse = new MEM.Label();
            MEM.Label fstTrue = new MEM.Label();
            info.linearizedImcStmts.addLast(
                new IMC.CJUMP(linearizedCondFst, new IMC.NAME(fstTrue), new IMC.NAME(fstFalse))
            );
 
            info.linearizedImcStmts.addLast(new IMC.LABEL(fstFalse));
            IMC.Expr linearizedCondSnd = condBinop.sndExpr.accept(this, info);
            info.linearizedImcStmts.addLast(new IMC.CJUMP(linearizedCondSnd, linearizedPosAddr, linearizedNegAddr));
 
            info.linearizedImcStmts.addLast(new IMC.LABEL(fstTrue));
            info.linearizedImcStmts.addLast(new IMC.JUMP(linearizedNegAddr));
        }
        else {
// --- DEFAULT: Standard CJUMP linearization ---
            IMC.Expr linearizedCond = cjump.cond.accept(this, info);
 
            MEM.Label newNegLabel = new MEM.Label();
            info.linearizedImcStmts.addLast(new IMC.CJUMP(linearizedCond, linearizedPosAddr, new IMC.NAME(newNegLabel)));
            info.linearizedImcStmts.addLast(new IMC.LABEL(newNegLabel));
        }
// --- END CHANGED ---
 
        info.linearizedImcStmts.addLast(new IMC.JUMP(linearizedNegAddr));
        return null;
    }
 
    // ... other code ...
}