Я хотел бы создать синтаксический анализатор cpp, используя cpp, и я использую ANTLR4. Я заметил, что на официальном github antlr grammar 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, /generated, содержащий файлы, созданные после запуска antlr4 -Dlanguage=Cpp -visitor, /cppruntime для среды выполнения из официального github antlr. Итак, я запустил следующую команду в 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. Извините, если я не проясняю ситуацию или делаю какую-то глупую ошибку, это мой первый вопрос.
Имейте в виду, что хотя грамматики размещены в официальном репозитории Github проекта ANTLR, все грамматики созданы пользователями. Многие (большинство?) из них не очень хорошо протестированы.
@Botje Хорошо, я отредактировал, извините за неподходящий формат вопросов, спасибо, что напомнили!
@BartKiers означает ли это, что я должен ожидать, что это может не работать, и просто использовать более старую версию?
Я нашел файлы CPP14ParserBase.h и .cpp, которые просто лежат в репозитории Вы забыли их скачать?
Грамматики проверены очень хорошо для трёх разных ОС и многих целей. Но вы всегда должны проверять desc.xml, чтобы увидеть, указана ли нужная вам цель.
@Botje, на самом деле это мой вопрос, я их замечаю, но на самом деле я не знал, что с ними делать, поскольку предоставленная демо-версия и другая соответствующая документация кажутся устаревшими (о чем я также не нашел никакой соответствующей информации в сети). )
@kaby76, хорошо! Я видел ваш ответ и скоро проверю его, спасибо за оказанную помощь!
«Грамматики проверены очень хорошо», конечно, грамматики включают в себя различные источники входных данных, которые проверяются при сборке, но большинство из них не включают в себя нечетные угловые случаи анализируемого языка. Структура дерева разбора также не проверяется на предмет «правильности» дерева разбора. По моему опыту, когда я использую грамматику из «официального» репозитория, часто требуется немало настроек, чтобы она была правильной. Просто мои 2 цента. Это также зависит от популярности грамматики: возможно, CPP и различные грамматики SQL имеют лучшее качество, чем другие.
Истинный. Тестирование по всем целям выполнено хорошо. Я потратил годы на то, чтобы очистить это, указать на ошибки Antlr4 во время выполнения и т. д. Тестирование синтаксиса оставляет желать лучшего, поскольку тестовые примеры предоставляются разработчиком грамматики. В некоторых грамматиках (например, yara) есть только один тест. Измерение грамматики правил синтаксического анализатора, проверенное как процентиль, выполняется для каждого PR с использованием trcover. При трассировке парсера не проводится CI-тестирование. Ближайшим для этого является тестирование дерева разбора, которое подходит лишь для нескольких случаев.





$ 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.
Вместо этого вы можете запустить следующие команды, чтобы скомпилировать код. Вам все равно нужно будет написать драйвер, решить, как вы хотите упаковать и связать среду выполнения Antlr Cpp (статические или динамические библиотеки и т. д.).
а) Клонировать репозиторий 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
б) Запустите инструмент antlr4 для генерации исходного кода парсера.
$ antlr4 -Dlanguage=Cpp CPP14Lexer.g4 CPP14Parser.g4
в) Скомпилируйте с помощью компилятора GNU.
$ g++ -std='c++17' -pthread -c -I../../antlr4/runtime/Cpp/runtime/src/ -g *.cpp
Пожалуйста, отредактируйте свой вопрос, указав точные действия, которые вы выполнили, и сообщения об ошибках, которые вы получили. «Пожалуйста, помогите мне» — это не вопрос, требующий действий.