我想像现在所有解释器一样发出动态错误消息,例如:
Name error: Undefined variable
会不变,但我想达到的是:
Name error: Undefined variable 'X', in line 1
好。行号确实没问题:每条错误消息都必须有行号,所以我将它添加到错误发射器功能中:
Error( ErrType type, string msg, int line );
那我的问题在哪里?
如何将'X'
转换为Undefined variable *
?
Error()
如何整理动态错误消息?
例如:Error( Name, sprintf("Undefined variable %s", myVariableName ), lineNum );
(但myVariableName
是一个字符串,sprintf
会搞砸了)
答案 0 :(得分:3)
您可以通过调用myVariableName
从c_str
获取以空字符结尾的C字符串:
myVariableName.c_str()
请注意,您对sprintf
的使用不正确; sprintf
的第一个参数将缓冲区放入其中以放置格式化字符串。如果您在计划中使用std::string
,为什么要使用sprintf
?如果Error
需要std::string
,那么您可以使用字符串连接:
Error(Name, "Undefined variable " + myVariableName, lineNum);
答案 1 :(得分:3)
Clang解决方法是让他们的诊断程序operator<<
重载,流式传输我在编译器中采用的必需参数
DiagnosticBuilder Error( ErrType type, string msg, int line );
然后您可以将其称为
Error(Serious, "Variable % is not known", lineNumber) << var;
调用诊断构建器的析构函数时,会发出错误。
struct DiagnosticBuilder {
DiagnosticBuilder(std::string const& format)
:m_emit(true), m_format(format)
{ }
DiagnosticBuilder(DiagnosticBuilder const& other)
:m_emit(true), m_format(other.m_format), m_args(other.m_args) {
other.m_emit = false;
}
~DiagnosticBuilder() {
if(m_emit) {
/* iterate over m_format, and print the next arg
everytime you hit '%' */
}
}
DiagnosticBuilder &operator<<(string const& s) {
m_args.push_back(s);
return *this;
}
DiagnosticBuilder &operator<<(int n) {
std::ostringstream oss; oss << n;
m_args.push_back(oss.str());
return *this;
}
// ...
private:
mutable bool m_emit;
std::string m_format;
std::vector<std::string> m_args;
};
我发现这种做法非常方便。您可以通过对参数占位符进行编号来扩展它以支持多种语言,例如"Variable %2 isn't found in scope %1"
。