Как построить предоставленную грамматику antlr?

Я хотел бы создать синтаксический анализатор 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. Извините, если я не проясняю ситуацию или делаю какую-то глупую ошибку, это мой первый вопрос.

Пожалуйста, отредактируйте свой вопрос, указав точные действия, которые вы выполнили, и сообщения об ошибках, которые вы получили. «Пожалуйста, помогите мне» — это не вопрос, требующий действий.

Botje 01.07.2024 10:07

Имейте в виду, что хотя грамматики размещены в официальном репозитории Github проекта ANTLR, все грамматики созданы пользователями. Многие (большинство?) из них не очень хорошо протестированы.

Bart Kiers 01.07.2024 10:50

@Botje Хорошо, я отредактировал, извините за неподходящий формат вопросов, спасибо, что напомнили!

EggDi 01.07.2024 10:57

@BartKiers означает ли это, что я должен ожидать, что это может не работать, и просто использовать более старую версию?

EggDi 01.07.2024 10:59

Я нашел файлы CPP14ParserBase.h и .cpp, которые просто лежат в репозитории Вы забыли их скачать?

Botje 01.07.2024 11:15

Грамматики проверены очень хорошо для трёх разных ОС и многих целей. Но вы всегда должны проверять desc.xml, чтобы увидеть, указана ли нужная вам цель.

kaby76 01.07.2024 11:27

@Botje, на самом деле это мой вопрос, я их замечаю, но на самом деле я не знал, что с ними делать, поскольку предоставленная демо-версия и другая соответствующая документация кажутся устаревшими (о чем я также не нашел никакой соответствующей информации в сети). )

EggDi 01.07.2024 11:38

@kaby76, хорошо! Я видел ваш ответ и скоро проверю его, спасибо за оказанную помощь!

EggDi 01.07.2024 11:39

«Грамматики проверены очень хорошо», конечно, грамматики включают в себя различные источники входных данных, которые проверяются при сборке, но большинство из них не включают в себя нечетные угловые случаи анализируемого языка. Структура дерева разбора также не проверяется на предмет «правильности» дерева разбора. По моему опыту, когда я использую грамматику из «официального» репозитория, часто требуется немало настроек, чтобы она была правильной. Просто мои 2 цента. Это также зависит от популярности грамматики: возможно, CPP и различные грамматики SQL имеют лучшее качество, чем другие.

Bart Kiers 01.07.2024 11:44

Истинный. Тестирование по всем целям выполнено хорошо. Я потратил годы на то, чтобы очистить это, указать на ошибки Antlr4 во время выполнения и т. д. Тестирование синтаксиса оставляет желать лучшего, поскольку тестовые примеры предоставляются разработчиком грамматики. В некоторых грамматиках (например, yara) есть только один тест. Измерение грамматики правил синтаксического анализатора, проверенное как процентиль, выполняется для каждого PR с использованием trcover. При трассировке парсера не проводится CI-тестирование. Ближайшим для этого является тестирование дерева разбора, которое подходит лишь для нескольких случаев.

kaby76 01.07.2024 12:35
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
10
92
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Шаг 1 – клонируйте репозиторий

$ 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.

Шаг 2. Перейдите к cpp и проверьте desc.xml, чтобы узнать, доступна ли цель для грамматики.

$ 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, поэтому цель «работает».

Шаг 3 — скопируйте целевые файлы поддержки в каталог, содержащий грамматику.

$ cp Cpp/* .

Вам необходимо скопировать файлы в каталог. В противном случае вы получите ошибки компиляции.

Шаг 4. Преобразуйте грамматику с помощью предоставленного скрипта Python.

$ 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

Шаг 5. Напишите драйвер и создайте скрипт для грамматики.

Грамматика в репозитории содержит только грамматику. Он не содержит кода драйвера, поскольку люди хотят упаковать парсер разными способами. Вам нужно написать этот код самостоятельно. Кроме того, вам понадобится сценарий сборки, который позволит выполнять сборку повторяемым и безошибочным способом. Вот почему люди используют 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

Другие вопросы по теме