我正在为类似c的自定义语言(我们称其为mylang)进行解释。 另外,我知道“编译”是一个错误的词,可用于解释器,但在引用文本解析和稍后执行的抽象语法树的构造时,我会使用它。
我已经制作了分词器,有一个生成ast的解析器,最终会出现解析错误。 现在,所有ast语句类都继承一个“ exec”函数,而所有与表达式相关的类(运算符,操作数,变量名,函数调用)都继承一个“ eval”函数,该函数返回一个“变量”类实例。 变量分为两部分:包含其类型的枚举(该语言将具有许多c ++类型,它们都将在枚举中以“ t_”命名),例如t_int,t_float,t_string,t_unsigned_long等;以及该类型的实际值。
运行mylang程序分为2个步骤: -解析文件(随着解析器的进行,逐个令牌地使用令牌生成器)。 -调用exec作为ast的根。包含表达式的语句将调用其持有的表达式的eval。
这很简单,但是它会导致很多错误,而这些错误只会在运行时发生,而我宁愿在编译时进行。 现在,二进制操作元素的“ eval”函数是一个很长的“ if-else”链,它调用其操作数的exec,然后检查返回变量的类型以查看它们是否相同,static_cast对该类型执行操作,或者如果它们不同,则抛出错误,这是我希望在编译时遇到的错误。当前的工作方式也迫使我首先对两个操作数求值,以便知道我应该执行哪个操作,而这又使我无法对布尔表达式执行延迟求值。
//inte namespace has interpreter classes
//var namespace contains the virtual var::root, from which a class for each type inherits. var::_float has type = t_float and space for a float.
//bin is the binary operator class
//function scope is passed to all evals so that should a variable name appear, that element of the ast can retrive that variable's value from the current scope.
inte::var::root * bin::eval(inte::function_scope * fs)
{
//here i'm evaluating the 2 operands
inte::var::root* ll = left->eval(fs);
inte::var::root* rr = right->eval(fs);
//if both operands are of type int
if ((ll->t == inte::var::t_int) && (rr->t == inte::var::t_int))
{
//cast the operands to int type value class (based on var::root, with an added int value).
auto lln = static_cast<inte::var::_int*>(ll);
auto rrn = static_cast<inte::var::_int*>(rr);
//the operation will return an int type value
auto ret = new inte::var::_int();
//check the operation's operand, perform the operation and return
switch (op.t)
{
case tok::sum: ret->value = lln->value + rrn->value; return ret;
case tok::mul: ret->value = lln->value * rrn->value; return ret;
case tok::mod: ret->value = lln->value % rrn->value; return ret;
case tok::assign: ret->value = lln->value = rrn->value; return ret;
...
}
}
else if (ll->t == inte::var::t_float && rr->t == inte::var::t_float)
{...}
else if (ll->t == inte::var::t_str && rr->t == inte::var::t_str)
{...}
//if the operands are of different type, OR, given these types the switch doesn't have that operation for these types (for instance t_float's switch doesn't have % operation)
//runtime error (which i'd rather have at compile time)
mylang::inte::error_op(op, ll, rr, nullptr);
return nullptr;
}
现在有实际问题: