我想使用 cpp 构建一个 cpp 解析器,并且我正在使用 ANTLR4。我注意到官方 github antlr 语法 github 中有一个“语法”部分,我已经下载了它。打开里面的CPP文件时,我注意到有一个CPP14Parser和一个CPP14Lexer,还有另一个CPP文件,里面有一个CPPParser。我已经浏览了这些文档好几天了,但它似乎已经过时了。我尝试过运行antlr-4,但后来在尝试编译它时不断出现错误。但是,我编写的 CMakeLists.txt 和 main(基本上是所有其他文件)确实可以在旧版本上工作,其中的内容更干净我成功构建的版本。有人可以教我如何构建最新版本的当前语法吗?如果需要更多具体背景,请告诉我!预先感谢!
编辑: 我所做的步骤如下所示,我安装了旧版本的CPP14.g4(如上面的描述中所写),并写了我自己写的CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project(CPPparser)
set(CMAKE_CXX_STANDARD 17)
include_directories(
${PROJECT_SOURCE_DIR}/generated/
${PROJECT_SOURCE_DIR}/cppruntime/src/
${PROJECT_SOURCE_DIR}/src/
)
set(src_dir
${PROJECT_SOURCE_DIR}/generated/CPP14Lexer.cpp
${PROJECT_SOURCE_DIR}/generated/CPP14Parser.cpp
${PROJECT_SOURCE_DIR}/generated/CPP14Visitor.cpp
${PROJECT_SOURCE_DIR}/generated/CPP14BaseVisitor.cpp
)
file(GLOB antlr4-cpp-src
${PROJECT_SOURCE_DIR}/cppruntime/src/*.cpp
${PROJECT_SOURCE_DIR}/cppruntime/src/atn/*.cpp
${PROJECT_SOURCE_DIR}/cppruntime/src/dfa/*.cpp
${PROJECT_SOURCE_DIR}/cppruntime/src/internal/*.cpp
${PROJECT_SOURCE_DIR}/cppruntime/src/misc/*.cpp
${PROJECT_SOURCE_DIR}/cppruntime/src/support/*.cpp
${PROJECT_SOURCE_DIR}/cppruntime/src/tree/*.cpp
${PROJECT_SOURCE_DIR}/cppruntime/src/tree/pattern/*.cpp
${PROJECT_SOURCE_DIR}/cppruntime/src/tree/xpath/*.cpp
)
add_library (antlr4-cpp-runtime ${antlr4-cpp-src})
add_executable(CPPparser ${src_dir} src/main.cpp)
target_link_libraries(CPPparser antlr4-cpp-runtime)
我将 main.cpp 写在 /src 文件夹中,/generate 具有在运行 antlr4 -Dlanguage=Cpp -visitor 后生成的文件,/cppruntime 用于来自官方 antlr github 的运行时。所以我将在 ubuntu 上运行以下命令
mkdir build && cd build
cmake ..
make
它确实工作得很好,但是,当我尝试使用相同的步骤编译 github 上提供的最新文件时,在运行 make 命令时出现大量错误。 错误如下所示
: error: expected class-name before ‘{’ token
12 | class CPP14Parser : public CPP14ParserBase {
| ^
/home/user/CPnew/generated/CPP14Parser.h:118:3: error: ‘CPP14Parser::~CPP14Parser()’ marked ‘override’, but does not override
118 | ~CPP14Parser() override;
| ^
/home/user/CPnew/generated/CPP14Parser.h:120:15: error: ‘std::string CPP14Parser::getGrammarFileName() const’ marked ‘override’, but does not override
120 | std::string getGrammarFileName() const override;
| ^~~~~~~~~~~~~~~~~~
/home/user/CPnew/generated/CPP14Parser.h:122:27: error: ‘const antlr4::atn::ATN& CPP14Parser::getATN() const’ marked ‘override’, but does not override
122 | const antlr4::atn::ATN& getATN() const override;
| ^~~~~~
/home/user/CPnew/generated/CPP14Parser.h:124:35: error: ‘const std::vector<std::__cxx11::basic_string<char> >& CPP14Parser::getRuleNames() const’ marked ‘override’, but does not override
124 | const std::vector<std::string>& getRuleNames() const override;
| ^~~~~~~~~~~~
/home/user/CPnew/generated/CPP14Parser.h:126:34: error: ‘const antlr4::dfa::Vocabulary& CPP14Parser::getVocabulary() const’ marked ‘override’, but does not override
126 | const antlr4::dfa::Vocabulary& getVocabulary() const override;
| ^~~~~~~~~~~~~
/home/user/CPnew/generated/CPP14Parser.h:128:34: error: ‘antlr4::atn::SerializedATNView CPP14Parser::getSerializedATN() const’ marked ‘override’, but does not override
128 | antlr4::atn::SerializedATNView getSerializedATN() const override;
| ^~~~~~~~~~~~~~~~
/home/user/CPnew/generated/CPP14Parser.h:3895:8: error: ‘bool CPP14Parser::sempred(antlr4::RuleContext*, size_t, size_t)’ marked ‘override’, but does not override
3895 | bool sempred(antlr4::RuleContext *_localctx, size_t ruleIndex, size_t predicateIndex) override;
| ^~~~~~~
/home/user/CPnew/cppruntime/src/CPP14ParserBase.cpp:5:6: error: ‘CPP14ParserBase’ has not been declared
5 | bool CPP14ParserBase::IsPureSpecifierAllowed()
| ^~~~~~~~~~~~~~~
/home/user/CPnew/cppruntime/src/CPP14ParserBase.cpp: In function ‘bool IsPureSpecifierAllowed()’:
/home/user/CPnew/cppruntime/src/CPP14ParserBase.cpp:9:18: error: invalid use of ‘this’ in non-member function
9 | auto x = this->getRuleContext(); // memberDeclarator
| ^~~~
如果需要的话,我的main.cpp如下
#include <iostream>
#include "CPP14Lexer.h"
#include "CPP14Parser.h"
using namespace antlr4;
int main(int argc, const char* argv[]) {
const char* filepath = argv[1];
std::ifstream ifs;
ifs.open(filepath);
ANTLRInputStream input(ifs);
CPP14Lexer lexer(&input);
CommonTokenStream tokens(&lexer);
CPP14Parser parser(&tokens);
tree::ParseTree* tree = parser.translationunit();
if (parser.getNumberOfSyntaxErrors() > 0) {
std::cout<<"File syntax error"<<std::endl;
return 0;
}
tokens.fill();
for (auto t : tokens.getTokens()) {
std::cout<<t->toString()<<std::endl;
}
std::cout << tree->toStringTree(&parser) << std::endl << std::endl;
ifs.close();
return 0;
}
TLDR:如果可能的话,请指导我如何构建最新版本的antlr语法。 抱歉,如果我没有说清楚或犯了任何愚蠢的错误,这是我的第一个问题。
$ git clone https://github.com/antlr/grammars-v4.git
Cloning into 'grammars-v4'...
remote: Enumerating objects: 50618, done.
remote: Counting objects: 100% (1907/1907), done.
remote: Compressing objects: 100% (1285/1285), done.
remote: Total 50618 (delta 686), reused 1618 (delta 510), pack-reused 48711
Receiving objects: 100% (50618/50618), 47.50 MiB | 23.79 MiB/s, done.
Resolving deltas: 100% (27107/27107), done.
Updating files: 100% (9413/9413), done.
$ cd grammars-v4/cpp/
$ cat desc.xml
<?xml version="1.0" encoding="UTF-8" ?>
<desc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../_scripts/desc.xsd">
<targets>Cpp;CSharp;Dart;Go;Java;JavaScript;Python3;Antlr4ng</targets>
</desc>
desc.xml 描述了构建的目标以及正在“工作”的目标。有时可以看到可用于目标的目标文件,但它们可能无法构建,或者语法太慢而无法在实践中使用。
对于 cpp 语法,列出了 Cpp 目标,因此该目标“有效”。
$ cp Cpp/* .
您必须将文件复制到目录中。否则,你会得到编译错误。
$ python transformGrammar.py
Altering .\CPP14Lexer.g4
Writing ...
Altering .\CPP14Parser.g4
Writing ...
语法包含“动作”,这是特定于目标的代码,专门针对Java。您必须将
this.
转换为 C++ 语法,this->
。
$ grep this *.g4
CPP14Lexer.g4:This: 'this';
CPP14Parser.g4: * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
CPP14Parser.g4: * The above copyright notice and this permission notice shall be included in all copies or
CPP14Parser.g4: | { this->IsPureSpecifierAllowed() }? pureSpecifier
CPP14Parser.g4: | { this->IsPureSpecifierAllowed() }? virtualSpecifierSeq pureSpecifier
存储库中的语法仅包含语法。它不包含任何驱动程序代码,因为人们希望以多种不同的方式打包解析器。您需要自己编写这段代码。此外,您还需要一个构建脚本来以可重复、无错误的方式进行构建。这就是人们使用 CMake 的原因。
除此之外,您可以运行以下命令来编译代码。您仍然需要编写驱动程序。
a) 克隆 antlr4 存储库
pushd ../../
$ git clone https://github.com/antlr/antlr4.git
Cloning into 'antlr4'...
remote: Enumerating objects: 134889, done.
remote: Counting objects: 100% (158/158), done.
remote: Compressing objects: 100% (82/82), done.
remote: Total 134889 (delta 62), reused 110 (delta 47), pack-reused 134731
Receiving objects: 100% (134889/134889), 68.26 MiB | 23.52 MiB/s, done.
Resolving deltas: 100% (79495/79495), done.
Updating files: 100% (2273/2273), done.
$ popd
b) 运行antlr4工具生成解析器源代码
$ antlr4 -Dlanguage=Cpp CPP14Lexer.g4 CPP14Parser.g4
c) 使用 GNU 编译器进行编译
$ g++ -std='c++17' -pthread -c -I../../antlr4/runtime/Cpp/runtime/src/ -g *.cpp