我编写自己的编译(或解释?)语言只是为了好玩,主要作为一个学习项目。我确信我还可以进行许多其他优化领域,但我当前遇到的问题是关于左侧和右侧的实际计算运算符(二元运算)。我必须假设我对此过度思考或过度设计。
下面是我遇到的问题的简单重现。我想避免的是对每种类型组合到处都硬编码
std::holds_alternative
和 std::get
。您可以对整数、浮点数、字符串、布尔值运行任何基本运算符(假设组合实际上有效),而无需手动写出每个组合。
#include <string>
#include <variant>
#include <vector>
#include <iostream>
using namespace std;
typedef variant<int, float> Variant; // Could have any number of basic types.. string, bool, etc.
Variant Execute(Variant* Left, Variant* Right)
{
if (std::holds_alternative<float>(*Left) && std::holds_alternative<float>(*Right))
{
float L = std::get<float>(*Left);
float R = std::get<float>(*Right);
return L + R;
}
else if (std::holds_alternative<int>(*Left) && std::holds_alternative<int>(*Right))
{
int L = std::get<int>(*Left);
int R = std::get<int>(*Right);
return L + R;
}
else if (std::holds_alternative<float>(*Left) && std::holds_alternative<int>(*Right))
{
float L = std::get<float>(*Left);
int R = std::get<int>(*Right);
return L + R;
}
else if (std::holds_alternative<int>(*Left) && std::holds_alternative<float>(*Right))
{
int L = std::get<int>(*Left);
float R = std::get<float>(*Right);
return L + R;
}
}
int main()
{
// Evaluating 5 + 5.0 + 10 + 10.0
auto A = new Variant(5);
auto B = new Variant(5.0f);
auto C = new Variant(10);
auto D = new Variant(20.0f);
std::vector<Variant*> Values;
Values.push_back(A);
Values.push_back(B);
Values.push_back(C);
Values.push_back(D);
Variant* Result;
int Index = 0;
for (auto V : Values)
{
// Equivalent of operator overloading?
Result = &Execute(Result, V);
Index++;
}
// Should come out as a float value 40.0f
if (std::holds_alternative<int>(*Result))
{
std::cout << std::get<int>(*Result) << std::endl;
}
else
{
std::cout << std::get<float>(*Result) << std::endl;
}
return 0;
}
很高兴发布更多上下文代码!感谢您的帮助!
我在我编写的 lisp 解释器中解决了这个问题,使用 std::unordered_map
对于大多数数学运算,我有单独的映射,但有一个用于比较的统一映射,仅使用元组而不是对,操作类型作为元组的一部分。
这允许我的解释器加载定义附加类型的 DLL,这些类型可以简单地插入评估系统。
它确实需要编写大量相当重复的函数(例如 bool_bool_add、bool_int_add、int_bool_add、int_int_add,...)。