我尝试实现一个简单的C / C ++解析器,它尝试部分解析C ++语言。所以我需要创建一个Lexer,一个预处理器和一个Parser类。
我正在考虑从这三层传递信息所需的数据类型是什么。通常,这里需要一个Token类,现在,我的Token类如下所示:
struct Token
{
TokenKind id;
std::string lexeme;
int fileIndex;
int line;
int column;
}
我认为最重要的部分是TokenKind(它可以是IDENTIFIER
或CLASS_KEYWORD
或任何其他标点符号,如LPAREN
),有时候,词汇也很重要,因为它通常包含类型名称或变量名称信息。
我查看了一些关于如何将令牌传递给Parsers的实现。
1,我看到Clang
在其预处理器类中有一些函数,如Preprocessor.cpp:739
void Preprocessor::Lex(Token &Result)
你看,引用是作为函数参数传递的,函数用结果填充对象,请参阅这里的Clang教程的另一个参考:Clang-tutorial/CItutorial3.cpp at master · loarabia/Clang-tutorial,这里是实例tok
在循环中重复使用。
Token tok;
do {
ci.getPreprocessor().Lex(tok);
if( ci.getDiagnostics().hasErrorOccurred())
break;
ci.getPreprocessor().DumpToken(tok);
std::cerr << std::endl;
} while ( tok.isNot(clang::tok::eof));
2,对于某些词法分析器生成器,我看到函数yylex()
只返回一个int
类型,实际上是一个TokenKind,以及其他信息,如实际的lexeme string存储在全局变量中,如yylval
。
3,对于GCC A tiny GCC front end – Part 3 | Think In Geek的小语言,我看到Lexer返回std::shared_ptr<Token>
,即:
static TokenPtr
make_identifier (location_t locus, const std::string& str)
{
return TokenPtr(new Token (IDENTIFIER, locus, str));
}
Lexer将令牌对象的智能指针TokenPtr返回给Parser,因此整个令牌将返回到Parser。
4, GCC的cpp库有一些cpp_get_token()
函数的接口,如下所示:
const cpp_token *token = cpp_get_token (pfile);
然后token->type
就像TokenKind字段一样。
所以,我的问题是:这些实现的优点和缺点是什么。上面提到的一些方法甚至没有预处理层,对我来说,我需要三层(词法分析器,预处理器和解析器)。
请注意,我的解析器不会像clang
或GCC
的解析器那么大。我的主要想法是我的解析器只能解析非常有限的C ++语言部分,我想把它们全部用手写。
编辑类似的问题在这里What should be the datatype of the tokens a lexer returns to its parser?,我也在几天前在那里发表了一些评论,但这个问题不涉及三层。