Instructions

V jeziku LANG’24 uvedemo pravilo, po katerem prva komponenta unije, če in samo če je dejanskega tipa int, ni prekrita z ostalimi komponentami. Dodajte to pravilo v prevajalnik.

Test

fun putint(c: int): void
fun putchar(c: char): void

var union1: { comp1: int, comp2: int }
var union2: { comp1: char, comp2: int }

fun main(): int =
    union1.comp1 = 1,
    union1.comp2 = 2,
    union2.comp1 = 'a',
    union2.comp2 = 98,
    putint(union1.comp1),
    putchar('\0x0A'),
    putint(union1.comp2),
    putchar('\0x0A'),
    putchar(union2.comp1),
    putchar('\0x0A'),
    putint(union2.comp2),
    return 0

Out

Before

2
2
b
98

After

1
2
b
98

Code

/memory/MemEvaluator.java

public class MemEvaluator implements AST.FullVisitor<Object, MemEvaluator.Info> {
    // ... other code ...
 
    private static class Info {
        private long depth;
        private long offset;
 
        private boolean inUnion;
// --- ADDED: Track first component in union ---
        private boolean firstInUnion;
 
        private Long localsSize;
        private Long argsSize;
 
        public Info() {
            depth = 0;
            offset = 0;
 
            inUnion = false;
// --- ADDED: Initialize firstInUnion ---
            firstInUnion = false;
 
            localsSize = 0L;
            argsSize = 0L;
        }
    }
 
    // ... other code ...
 
    @Override
    public Object visit(AST.CompDefn compDefn, Info info) {
        long previousDepth = info.depth; info.depth = -1;
 
        compDefn.type.accept(this, info);
 
        TYP.Type type = compDefn.type.type;
        Long size = type.accept(sizeEvaluator, null);
 
        MEM.Access access = new MEM.RelAccess(size, info.offset, info.depth);
// --- CHANGED: Only increment offset for first int in union, or if not in union ---
        if (!info.inUnion || (info.firstInUnion && type instanceof TYP.IntType))
            info.offset = positiveOffset(info.offset, size);
 
        Memory.accesses.put(compDefn, access);
 
// --- ADDED: Reset after first union component ---
        info.firstInUnion = false;
        info.depth = previousDepth;
        return null;
    }
 
    // ... other code ...
 
    @Override
    public Object visit(AST.UniType uniType, Info info) {
        boolean previousInUnion = info.inUnion; info.inUnion = true;
// --- ADDED: Track first in union ---
        boolean previousFirstInUnion = info.firstInUnion; info.firstInUnion = true;
        long previousOffset = info.offset; info.offset = 0L;
 
        uniType.comps.accept(this, info);
 
        info.inUnion = previousInUnion;
// --- ADDED: Restore previous state ---
        info.firstInUnion = previousFirstInUnion;
        info.offset = previousOffset;
        return null;
    }
}

/memory/SizeEvaluator.java

public class SizeEvaluator extends TYP.FullVisitor<Long, Object> {
    // ... other code ...
 
    @Override
    public Long visit(TYP.UniType uniType, Object arg) {
// --- ADDED: Track size of first int component ---
        long startingIntSize = 0L;
        long size = 0L;
        for (int i = 0; i < uniType.compTypes.size(); i++) {
            TYP.Type compType = uniType.compTypes.get(i);
            final long compSize = compType.accept(this, arg);
// --- ADDED: Special handling for first int ---
            if (i == 0 && compType instanceof TYP.IntType) {
                startingIntSize += compSize;
            } else {
                size = Long.max(size, (compSize / 8L) * 8L + (compSize % 8L == 0 ? 0L : 8L));
            }
        }
// --- ADDED: Combine sizes ---
        return size + startingIntSize;
    }
 
    // ... other code ...
}