Instructions

V jeziku LANG’24 uvedemo pravilo, po katerem nobena funkcija v nobenem trenutku izvajanja programa ne sme biti klicana več kot desetkrat (a če je recimo klicana osemkrat in se vsi klici zaključijo, sme biti spet klicana dvakrat). V primeru, ko je pravilo kršeno, naj se izvajanje programa takoj konča. Dodajte to pravilo v prevajalnik.

Test

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

fun rec(x: int): int =
	putint(x),
	putchar('\0x0A'),
    if
	    x < 1
	then
		return 1
	end,
	return rec(x-1)

fun main(): int =
    puts("Testing 5"),
    putchar('\0x0A'),
    rec(5),
    puts("Testing 9"),
    putchar('\0x0A'),
    rec(9),
    puts("Testing 10"),
    putchar('\0x0A'),
    rec(10),
    puts("Testing 11"),
    putchar('\0x0A'),
    rec(11)

Out

Before

After

Code

/imclin/ChunkGenerator.java

public class ChunkGenerator implements AST.FullVisitor<IMC.Instr, ChunkGenerator.Info> {
    // ... other code ...
 
    @Override
    public IMC.Instr visit(AST.FunDefn defFunDefn, Info info) {
        // ... other code ...
        defFunDefn.stmts.accept(this, info);
 
        Vector<IMC.Stmt> stmts = new Vector<>();
 
// --- ADDED: Function counter logic ---
        MEM.Label funCounterLabel = new MEM.Label(defFunDefn.name + "_counter");
        for (IMC.Stmt stmtImc : funCounterStmts(funCounterLabel)) {
            Vector<IMC.Stmt> linearizedImcStmts = new Vector<>();
            stmtImc.accept(new LinearizeImc(), new LinearizeImc.Info(linearizedImcStmts));
            stmts.addAll(linearizedImcStmts);
        }
// --- END ADDED ---
 
        for (AST.Stmt stmtAst : defFunDefn.stmts) {
            IMC.Stmt stmtImc = ImcGen.stmt.get(stmtAst);
            Vector<IMC.Stmt> linearizedImcStmts = new Vector<>();
            stmtImc.accept(new LinearizeImc(), new LinearizeImc.Info(linearizedImcStmts));
            stmts.addAll(linearizedImcStmts);
        }
 
        stmts.addFirst(new IMC.LABEL(entryLabel));
        stmts.addLast(new IMC.LABEL(exitLabel));
 
// --- ADDED: Decrement function counter at function exit ---
        stmts.add(new IMC.MOVE(
            new IMC.MEM8(new IMC.NAME(funCounterLabel)),
            new IMC.BINOP(IMC.BINOP.Oper.SUB,
                new IMC.MEM8(new IMC.NAME(funCounterLabel)),
                new IMC.CONST(1)
            )
        ));
// --- END ADDED ---
 
// --- ADDED: New exit label ---
        MEM.Label newExitLabel = new MEM.Label(defFunDefn.name + "_exit");
        stmts.addLast(new IMC.LABEL(newExitLabel));
// --- END ADDED ---
 
        LIN.CodeChunk codeChunk = new LIN.CodeChunk(
            Memory.frames.get(defFunDefn),
            stmts,
            entryLabel,
            newExitLabel // CHANGED: use new exit label
        );
        ImcLin.addCodeChunk(codeChunk);
 
        return null;
    }
 
// --- ADDED: Function counter statements ---
    private List<IMC.Stmt> funCounterStmts(MEM.Label funCounterLabel) {
        List<IMC.Stmt> stmts = new ArrayList<>();
        byte[] funCounterInit = new byte[8];
        MEM.AbsAccess funCounterAccess = new MEM.AbsAccess(8L, funCounterLabel, "0", funCounterInit);
        ImcLin.addDataChunk(new LIN.DataChunk(funCounterAccess));
 
        MEM.Label exitProgramLabel = new MEM.Label();
        MEM.Label continueProgramLabel = new MEM.Label();
 
        // Increment function counter
        stmts.add(new IMC.MOVE(
            new IMC.MEM8(new IMC.NAME(funCounterLabel)),
            new IMC.BINOP(IMC.BINOP.Oper.ADD,
                new IMC.MEM8(new IMC.NAME(funCounterLabel)),
                new IMC.CONST(1)
            )
        ));
        // If counter <= 10, continue; else, call die
        stmts.add(new IMC.CJUMP(
            new IMC.BINOP(IMC.BINOP.Oper.LEQ,
                new IMC.MEM8(new IMC.NAME(funCounterLabel)),
                new IMC.CONST(10L)
            ),
            new IMC.NAME(continueProgramLabel),
            new IMC.NAME(exitProgramLabel)
        ));
 
        stmts.add(new IMC.LABEL(exitProgramLabel));
        stmts.add(new IMC.ESTMT(
            new IMC.CALL(
                new IMC.NAME(new MEM.Label("die")),
                new Vector<>(),
                new Vector<>()
            )
        ));
 
        stmts.add(new IMC.LABEL(continueProgramLabel));
 
        return stmts;
    }
// --- END ADDED ---
}