Closed DistinctWind closed 1 year ago
目前有个问题,IntConstant
常量池是逐个比较相等的。
如果说我们换了一个IntConstant
的实现方式,那原来的代码都得改过了。
所以我们要不要使用逻辑比较(根据程序中出现GetIntConstant的index获得常量,比较获得的常量是否相同)来判断程序的相等性?
有点不理解为什么换个IntConstant的实现,代码就都得改?IntConstant是ast的终结符,与ast直接耦合的不是compiler吗,而program里面的IntConstant和ast并无联系
我的意思是,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;
}
那要不还是换吧?以后出问题再换确实有可能会麻烦很多
我目前的想法是,写一个小型的ByteCodeVisitor
实现IntConstantDetector
,这个实现类似于VirtualMachine
,也会读取字节码和常量池,区别就在于,这个IntConstantDetector
的功能是依照字节码中GetIntConstant
出现的顺序,生成一个vector<int>
,储存Program
依次引用int常量池的结果。
这样,比较两个生成的vector<int>
是否相同,就可以实现逻辑上比较两个常量池是否相等了。
让我们的程序能存储大于1字节(255)的无符号整数