所以我用C ++编写了一个编译器。目前在扫描仪部分。
扫描仪内的方法声明是
Token * Scanner::next_token()
{
string * test = new string("Test");
IdToken * testToken = new IdToken(test);
return testToken;
}
IdToken类有一个方法get_attribute(),它返回私有变量attr的值(在本例中是一个字符串,在创建时传入的字符串)。令牌(抽象类)没有这种方法。
在测试的主要内容中,我有这个:
IdToken * testToken = testScanner->next_token();
但是g ++并不喜欢这样,并说这是从Token *到IdToken *的无效转换。
我需要将方法返回的标记转换为IdToken以获取属性,因为当我尝试直接调用返回的标记上的get_attribute()时,它告诉我Token :: get_attribute()不存在
我不确定如何解决这个问题,因为我对C ++继承的了解正在挣扎。我做了所有可能的研究,但我找不到任何我理解的东西并解决了我的问题。
这是Scanner.cc
Scanner::Scanner (char * filename)
{
buf = new Buffer(filename);
}
//Destroy new things
Scanner::~Scanner()
{
delete buf;
}
//The huge DFA turned into code
Token * Scanner::next_token()
{
string * test = new string("Test");
IdToken * testToken = new IdToken(test);
return testToken;
}
这是IdToken.cc
IdToken::IdToken() : Token()
{
set_token_type (TOKEN_ID);
attribute = new string("UNINITIALIZED IDENTIFIER ATTRIBUTE");
}
IdToken::IdToken (string *attr) : Token()
{
set_token_type (TOKEN_ID);
attribute = new string(*attr);
}
IdToken::~IdToken()
{ if (attribute != NULL) {
delete attribute;
}
}
string *IdToken::get_attribute() const
{
string *attr = new string(*attribute);
return attr;
}
void IdToken::set_attribute(string *attr)
{
if (attribute != NULL) {
delete attribute;
}
attribute = new string (*attr);
}
string *IdToken::to_string()
{
string *attribute_name = new string ("ID:" + *attribute);
return attribute_name;
}
最后是token.cc
#include "token.h"
Token::Token()
{
type = TOKEN_NO_TYPE;
}
Token::~Token()
{}
void Token::set_token_type (token_type_type type)
{
this->type = type;
}
token_type_type Token::get_token_type() const
{
return type;
}
它还没有完成,我只需要帮助找出如何访问get_attribute。
答案 0 :(得分:1)
几个选项:
在virtual
中创建Token
成员函数。
virtual std::string get_attribute() const = 0;
适当地实施Token
的子类。用它作为:
Token * testToken = testScanner->next_token();
std::string attr = testToken->get_attribute();
使用dynamic_cast
从IdToken*
获取Token*
。如果演员表演成功,请致电get_attribute()
。在IdToken*
。
Token * testToken = testScanner->next_token();
IdToken * testIdToken = dynamic_cast<IdToken*>(testToken);
if ( testIdToken )
{
std::string attr = testIdToken->get_attribute();
}
答案 1 :(得分:0)
您可以使用dynamic_cast
struct Token {
virtual ~Token() {}
};
struct IdToken : public Token {
int getAttribute() {return 1;}
};
int main(int argc, char** argv} {
Token* token = new IdToken();
dynamic_cast<IdToken*>(token)->getAttribute();
delete token;
}
不幸的是,dynamic_cast
往往相当慢,您可能希望避免频繁调用它。然而,它是安全的。失败时返回nullptr
。您也可以使用reinterpret_cast
,这更快,但不安全。
答案 2 :(得分:0)
我个人不会为代币制作类层次结构。有一组相对较小的属性和参数,如果你真的需要,你可以使用一个联合来存储它们。
但如果必须,请使用dynamic_cast
来致电get_attribute
:
Token* token = testScanner->next_token()
IdToken *idToken = dynamic_cast<IdToken*>(token);
if(idToken)
{
idToken->get_attribute();
}
请注意,您确实需要if
,否则如果您获得的令牌不是IdToken
[或来自IdToken
],您的程序就会崩溃。
哦,dynamic_cast
并不是一个简单的操作,根本不需要时间。因此,避免它优先于基类虚函数几乎总是更好。对于来自解析器的AST,我的编译器使用了几十个llvm::dyn_cast
,因为做了一个完全通用的AST类,它可以处理变量表达式,for循环和函数声明的所有特殊情况。同一个类会产生一个具有几十个虚函数的类的怪物,其中大部分都需要单个实现一个派生类,但是一个&#34; null&#34;大多数其他人的价值 - 大部分时间我都需要知道它实际上是什么类......
这里是我的Token class - 我确定那里也有错误,我不是编译专家,这是我的第三语言,我已经参与过,并且第一个实际编译为机器代码,并且我使用llvm作为后端作弊。
不要string *something = new string;
使用空的或未知的&#34;字符串表示&#34;尚未设置&#34;
也不要使用if (pointer) delete pointer;
- delete
在NULL
的指针上工作正常 - 如果编译器可能没有删除冗余的话,因为它很小调用delete
的额外开销是值得保存的 - 但不是在析构函数中。如果你在一个大型项目中到处都有一个额外的if (pointer)
,它很快就会增加几千字节的额外代码 - 如果析构函数恰好是内联的,那么它会乘以它所拥有的内联数量,在你的项目中可能会有很多无用的代码。编译器代码往往变得足够大而没有无用的膨胀。