4
Copyright (c) 2021 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,
6
https://bmstu.codes/lsx/simodo/loom
9
/*! \file Синтаксический анализ
11
* Утилита синтаксического анализа текста на любом языке, заданном грамматикой на языке SIMODO fuze.
16
#include "simodo/inout/reporter/ConsoleReporter.h"
17
#include "simodo/inout/convert/functions.h"
18
#include "simodo/LibVersion.h"
19
#include "simodo/inout/token/InputStream.h"
20
#include "simodo/parser/fuze/fuze_file_extension.h"
21
#include "simodo/parser/Grammar.h"
22
#include "simodo/engine/utility/grammatize.h"
23
#include "simodo/engine/utility/generateDotFile.h"
24
#include "simodo/parser/automaton/PushdownAutomaton.h"
25
#include "simodo/variable/json/LexicalParametersLoader.h"
26
#include "simodo/loom/Loom.h"
27
#include "simodo/interpret/SemanticOperationsEnumsLoader.h"
28
#include "simodo/interpret/builtins/AstFormationBuilder.h"
29
#include "simodo/interpret/builtins/hosts/base/BaseRunning.h"
30
#include "simodo/interpret/builtins/modules/LexicalParametersModule.h"
31
#include "simodo/variable/json/Serialization.h"
32
#include "simodo/variable/convert/Ast.h"
33
#include "simodo/interpret/Interpret.h"
41
#if __cplusplus >= __cpp_2017
43
namespace fs = std::filesystem;
45
#include <experimental/filesystem>
46
namespace fs = std::filesystem::experimental;
50
using namespace simodo;
52
int main(int argc, char *argv[])
54
vector<std::string> arguments(argv + 1, argv + argc);
56
string file_name = "";
57
string json_file_name = "";
58
string st_dot_file_name = "";
59
string dot_file_name = "";
61
string grammar_file = "";
62
string grammar_path = "data/grammar";
63
string grammar_builder_method_string = "";
64
bool need_time_intervals = false;
65
bool need_state_transitions_info = false;
66
bool need_rules_info = false;
67
bool need_st_info = false;
71
bool need_silence = true;
72
bool need_build_grammar = false;
73
bool need_load_grammar = false;
75
for(size_t i=0; i < arguments.size(); ++i)
77
const string & arg = arguments[i];
81
if (arg == "--help" || arg == "-h")
83
else if (arg == "--version" || arg == "-v")
85
else if (arg == "--grammar-builder-method" || arg == "-z")
87
if (i == arguments.size()-1 || !grammar_builder_method_string.empty())
90
grammar_builder_method_string = arguments[++i];
92
else if (arg == "--json-semantics" || arg == "-j")
94
if (i == arguments.size()-1 || !json_file_name.empty())
97
json_file_name = arguments[++i];
99
else if (arg == "--grammar-file" || arg == "-g")
101
if (i == arguments.size()-1 || !grammar_file.empty())
104
grammar_file = arguments[++i];
106
else if (arg == "--lex")
108
if (i == arguments.size()-1 || !lex_file.empty())
111
lex_file = arguments[++i];
113
else if (arg == "--path-to-grammar" || arg == "-G")
115
if (i == arguments.size()-1)
118
grammar_path = arguments[++i];
120
else if (arg == "--dot-semantics" || arg == "-s")
122
if (i == arguments.size()-1 || !st_dot_file_name.empty())
125
st_dot_file_name = arguments[++i];
127
else if (arg == "--dot-grammar" || arg == "-d")
129
if (i == arguments.size()-1 || !st_dot_file_name.empty())
132
dot_file_name = arguments[++i];
134
else if (arg == "--state-transitions-info" || arg == "-i")
135
need_state_transitions_info = true;
136
else if (arg == "--rules-info" || arg == "-r")
137
need_rules_info = true;
138
else if (arg == "--insertion-info" || arg == "-o")
140
else if (arg == "--time-intervals" || arg == "-t")
141
need_time_intervals = true;
142
else if (arg == "--silence" || arg == "-S")
144
else if (arg == "--dump-grammar" || arg == "-u")
145
need_build_grammar = true;
146
else if (arg == "--load-grammar" || arg == "-l")
147
need_load_grammar = true;
151
else if (file_name.empty())
157
parser::TableBuildMethod grammar_builder_method = parser::TableBuildMethod::LR1;
159
if (grammar_builder_method_string == "lr" || grammar_builder_method_string == "lr1")
160
grammar_builder_method = parser::TableBuildMethod::LR1; // -V1048
161
else if (grammar_builder_method_string == "slr")
162
grammar_builder_method = parser::TableBuildMethod::SLR;
163
else if (!grammar_builder_method_string.empty()) {
164
cout << "Задан недопустимый метод формирования таблицы грамматики" << endl;
168
if (grammar_file.empty() && !file_name.empty()) {
169
fs::path file_name_path = file_name;
170
if(!file_name_path.extension().empty() && file_name_path.extension().string() != ".") {
171
fs::path path_to_grammar = fs::path(grammar_path) / (file_name_path.extension().string().substr(1) + ".fuze");
172
grammar_file = path_to_grammar.string();
176
if ((grammar_file.empty() || file_name.empty()) && !version && !help)
179
if (need_load_grammar && (need_build_grammar || need_time_intervals))
183
cout << "Ошибка в параметрах запуска" << endl;
187
const string logo = "Утилита анализа грамматики. Проект SIMODO.";
191
<< "Формат запуска:" << endl
192
<< " simodo-parse [<параметры>] <файл>" << endl
193
<< "Параметры:" << endl
194
<< " -h | --help - отображение подсказки по запуску программы" << endl
195
<< " -v | --version - отображение версии программы" << endl
196
<< " -z | --grammar-builder-method <метод> - метод построения таблицы грамматики (slr,lr1)" << endl
197
<< " -t | --time-intervals - отображать интервалы времени разбора" << endl
198
<< " -j | --json-semantics <путь> - создать JSON-файл абстрактного дерева операционной семантики" << endl
199
<< " -s | --dot-semantics <путь> - создать DOT-файл абстрактного дерева операционной семантики" << endl
200
<< " -d | --dot-grammar <путь> - создать DOT-файл графа переходов состояний грамматики" << endl
201
<< " -r | --rules-info - вывести перечень правил грамматики" << endl
202
<< " -i | --state-transitions-info - вывести информацию о переходах состояний грамматики" << endl
203
<< " -o | --insertion-info - вывести структуры семантических вставок" << endl
204
<< " -S | --silence - не выводить диагностику утилиты" << endl
205
<< " -u | --dump-grammar - построить и сохранить грамматику в дампе" << endl
206
<< " -l | --load-grammar - загрузить грамматику из дампа" << endl
207
<< " | --lex <путь> - путь к файлу описания лексики" << endl
208
<< " -g | --grammar-file <путь> - путь к файлу грамматики" << endl
209
<< " -G | --path-to-grammar <путь> - путь к каталогу файлов грамматики" << endl
210
<< " (конкретная грамматика будет определяться по расширению исходного файла)" << endl
218
<< "Версия: " << lib_version().major() << "." << lib_version().minor() << endl;
220
std::ifstream in(grammar_file);
223
cout << "Ошибка при открытии файла '" << grammar_file << "'" << endl;
227
inout::InputStream in_stream(in);
228
inout::ConsoleReporter m;
229
parser::Grammar grammar;
231
bool ok = engine::grammatize(
236
"", //json_file_name,
237
"", //st_dot_file_name,
238
grammar_builder_method,
240
need_state_transitions_info,
247
false, //need_analyze_handles,
248
false, //need_analyze_inserts
255
for(const auto & [name, node] : grammar.handlers)
258
interpret::Interpret * inter = new interpret::Interpret(interpret::InterpretType::Preview, m, loom, {file_name}, node);
259
interpret::builtins::BaseRunning * runner = new interpret::builtins::BaseRunning(inter);
260
std::shared_ptr<interpret::builtins::LexicalParametersModule>
261
lex = std::make_shared<interpret::builtins::LexicalParametersModule>(grammar.lexical);
262
// std::shared_ptr<interpret::builtins::AstFormationModule>
263
// ast = std::make_shared<interpret::builtins::AstFormationModule>();
265
/// \todo Пересмотреть странную передачу самого себя в свой же метод.
266
/// PVS Studio: warn V678 An object is used as an argument to its own method.
267
/// Consider checking the first actual argument of the 'instantiate' function.
268
runner->importNamespace(u"lex", lex->instantiate(lex), inout::null_token_location);
269
/// \todo Пересмотреть странную передачу самого себя в свой же метод.
270
/// PVS Studio: warn V678 An object is used as an argument to its own method.
271
/// Consider checking the first actual argument of the 'instantiate' function.
272
// runner->importNamespace(u"ast", ast->instantiate(ast), inout::null_token_location);
273
inter->instantiateSemantics({runner});
274
loom.dock(inter, true);
280
if (!lex_file.empty() && !variable::loadLexicalParameters(lex_file,grammar.lexical)) {
281
cout << "Ошибка при чтении параметров лексики из файла '" << lex_file << "'" << endl;
285
variable::VariableSet_t hosts_and_operations = interpret::loadSemanticOperationsEnums(fs::path(grammar_file).parent_path().string());
287
interpret::Interpret inter(interpret::InterpretType::Preview, m, loom, {file_name}, null_node);
288
interpret::builtins::BaseInterpret_abstract *
289
sbl = new interpret::builtins::BaseRunning(&inter);
290
interpret::builtins::AstFormationBuilder
291
builder(m,*sbl, hosts_and_operations);
292
parser::PushdownAutomaton parser(m, grammar, inter.files(), builder);
294
inter.instantiateSemantics({sbl});
299
if (!st_dot_file_name.empty()) {
301
cout << "Построение DOT-файла..." << std::endl;
303
const ast::Node & code = builder.ast().tree().root();
304
engine::generateDotFile(st_dot_file_name, code, {});
307
if (!json_file_name.empty()) {
309
cout << "Сохранение JSON-файла..." << std::endl;
311
ok = variable::saveJson(variable::toValue(builder.ast().tree()), json_file_name, false);
314
cout << "Ошибка сохранения в '" << json_file_name << "'" << std::endl;