visual-decaf / decaf-compiler

Compiler of decaf language
1 stars 3 forks source link

Int类型常量池 #31

Closed DistinctWind closed 1 year ago

DistinctWind commented 1 year ago

让我们的程序能存储大于1字节(255)的无符号整数

DistinctWind commented 1 year ago

目前有个问题,IntConstant常量池是逐个比较相等的。

如果说我们换了一个IntConstant的实现方式,那原来的代码都得改过了。

所以我们要不要使用逻辑比较(根据程序中出现GetIntConstant的index获得常量,比较获得的常量是否相同)来判断程序的相等性?

i-iling commented 1 year ago

有点不理解为什么换个IntConstant的实现,代码就都得改?IntConstant是ast的终结符,与ast直接耦合的不是compiler吗,而program里面的IntConstant和ast并无联系

DistinctWind commented 1 year ago

我的意思是,Program是才是一个整体。IntConstantPool中记录的含义(即索引对应的常量)是否相同,跟Program这个整体的含义是否相同是两回事。

考虑这个单元测试

TEST_CASE("compiler_int_constant_pool", "[compiler]") {
    using namespace decaf;
    auto input_ast = new ast::ArithmeticBinary(
        new ast::IntConstant(10000),
        ast::ArithmeticBinary::Operation::PLUS,
        new ast::IntConstant(2345));

    decaf::Compiler compiler{input_ast};
    compiler.compile();

    using Instruction = ByteCode::Instruction;
    auto result = compiler.get_program();
    auto expect = Program{
        ByteCode{
            Instruction ::GET_INT_CONSTANT,
            0,
            Instruction ::GET_INT_CONSTANT,
            1,
            Instruction ::PLUS,
        },
        IntConstantPool{
            10000,
            2345,
        }};

    REQUIRE(expect == result);
    delete input_ast;
}

我们自己写一个带常量池的程序expect,但是这个IntConstantPool中记录的含义(即索引对应的常量)跟Program这个整体的含义是两回事。也就是说,如果我们换了一种IntConstantPool的实现方式,情况可能会变成这样:

TEST_CASE("compiler_int_constant_pool", "[compiler]") {
    using namespace decaf;
    auto input_ast = new ast::ArithmeticBinary(
        new ast::IntConstant(10000),
        ast::ArithmeticBinary::Operation::PLUS,
        new ast::IntConstant(2345));

    decaf::Compiler compiler{input_ast};
    compiler.compile();

    using Instruction = ByteCode::Instruction;
    auto result = compiler.get_program();
    auto expect = Program{
        ByteCode{
            Instruction ::GET_INT_CONSTANT,
            1,
            Instruction ::GET_INT_CONSTANT,
            0,
            Instruction ::PLUS,
        },
        IntConstantPool{
            2345,
            10000,
        }};

    REQUIRE(expect == result);
    delete input_ast;
}

虽然常量池不一样了,但是程序中引用的index也不一样了,最后两个Program的效果是等价的。但是由于IntConstantPool不再逐记录相同,所以现在我们的Program判断相等函数就会认为这两个程序是不同的:

    bool operator==(const Program& rhs) {
        return this->code == rhs.code && this->i_pool == rhs.i_pool;
    }
i-iling commented 1 year ago

那要不还是换吧?以后出问题再换确实有可能会麻烦很多

DistinctWind commented 1 year ago

我目前的想法是,写一个小型的ByteCodeVisitor实现IntConstantDetector,这个实现类似于VirtualMachine,也会读取字节码和常量池,区别就在于,这个IntConstantDetector的功能是依照字节码中GetIntConstant出现的顺序,生成一个vector<int>,储存Program依次引用int常量池的结果。

这样,比较两个生成的vector<int>是否相同,就可以实现逻辑上比较两个常量池是否相等了。