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/utility/grammatize.h"
23
#include "simodo/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"
40
#if __cplusplus >= __cpp_2017
42
namespace fs = std::filesystem;
44
#include <experimental/filesystem>
45
namespace fs = std::filesystem::experimental;
49
using namespace simodo;
51
int main(int argc, char *argv[])
53
vector<std::string> arguments(argv + 1, argv + argc);
55
string file_name = "";
56
string json_file_name = "";
57
string st_dot_file_name = "";
58
string dot_file_name = "";
60
string grammar_file = "";
61
string grammar_path = "data/grammar";
62
string grammar_builder_method_string = "";
63
bool need_time_intervals = false;
64
bool need_state_transitions_info = false;
65
bool need_rules_info = false;
66
bool need_st_info = false;
70
bool need_silence = true;
71
bool need_build_grammar = false;
72
bool need_load_grammar = false;
74
for(size_t i=0; i < arguments.size(); ++i)
76
const string & arg = arguments[i];
80
if (arg == "--help" || arg == "-h")
82
else if (arg == "--version" || arg == "-v")
84
else if (arg == "--grammar-builder-method" || arg == "-z")
86
if (i == arguments.size()-1 || !grammar_builder_method_string.empty())
89
grammar_builder_method_string = arguments[++i];
91
else if (arg == "--json-semantics" || arg == "-j")
93
if (i == arguments.size()-1 || !json_file_name.empty())
96
json_file_name = arguments[++i];
98
else if (arg == "--grammar-file" || arg == "-g")
100
if (i == arguments.size()-1 || !grammar_file.empty())
103
grammar_file = arguments[++i];
105
else if (arg == "--lex")
107
if (i == arguments.size()-1 || !lex_file.empty())
110
lex_file = arguments[++i];
112
else if (arg == "--path-to-grammar" || arg == "-G")
114
if (i == arguments.size()-1)
117
grammar_path = arguments[++i];
119
else if (arg == "--dot-semantics" || arg == "-s")
121
if (i == arguments.size()-1 || !st_dot_file_name.empty())
124
st_dot_file_name = arguments[++i];
126
else if (arg == "--dot-grammar" || arg == "-d")
128
if (i == arguments.size()-1 || !st_dot_file_name.empty())
131
dot_file_name = arguments[++i];
133
else if (arg == "--state-transitions-info" || arg == "-i")
134
need_state_transitions_info = true;
135
else if (arg == "--rules-info" || arg == "-r")
136
need_rules_info = true;
137
else if (arg == "--insertion-info" || arg == "-o")
139
else if (arg == "--time-intervals" || arg == "-t")
140
need_time_intervals = true;
141
else if (arg == "--silence" || arg == "-S")
143
else if (arg == "--dump-grammar" || arg == "-u")
144
need_build_grammar = true;
145
else if (arg == "--load-grammar" || arg == "-l")
146
need_load_grammar = true;
150
else if (file_name.empty())
156
parser::TableBuildMethod grammar_builder_method = parser::TableBuildMethod::LR1;
158
if (grammar_builder_method_string == "lr" || grammar_builder_method_string == "lr1")
159
grammar_builder_method = parser::TableBuildMethod::LR1;
160
else if (grammar_builder_method_string == "slr")
161
grammar_builder_method = parser::TableBuildMethod::SLR;
162
else if (!grammar_builder_method_string.empty()) {
163
cout << "Задан недопустимый метод формирования таблицы грамматики" << endl;
167
if (grammar_file.empty() && !file_name.empty()) {
168
fs::path file_name_path = file_name;
169
if(!file_name_path.extension().empty() && file_name_path.extension().string() != ".") {
170
fs::path path_to_grammar = fs::path(grammar_path) / (file_name_path.extension().string().substr(1) + ".fuze");
171
grammar_file = path_to_grammar.string();
175
if ((grammar_file.empty() || file_name.empty()) && !version && !help)
178
if (need_load_grammar && (need_build_grammar || need_time_intervals))
182
cout << "Ошибка в параметрах запуска" << endl;
186
const string logo = "Утилита анализа грамматики. Проект SIMODO.";
190
<< "Формат запуска:" << endl
191
<< " simodo-parse [<параметры>] <файл>" << endl
192
<< "Параметры:" << endl
193
<< " -h | --help - отображение подсказки по запуску программы" << endl
194
<< " -v | --version - отображение версии программы" << endl
195
<< " -z | --grammar-builder-method <метод> - метод построения таблицы грамматики (slr,lr1)" << endl
196
<< " -t | --time-intervals - отображать интервалы времени разбора" << endl
197
<< " -j | --json-semantics <путь> - создать JSON-файл абстрактного дерева операционной семантики" << endl
198
<< " -s | --dot-semantics <путь> - создать DOT-файл абстрактного дерева операционной семантики" << endl
199
<< " -d | --dot-grammar <путь> - создать DOT-файл графа переходов состояний грамматики" << endl
200
<< " -r | --rules-info - вывести перечень правил грамматики" << endl
201
<< " -i | --state-transitions-info - вывести информацию о переходах состояний грамматики" << endl
202
<< " -o | --insertion-info - вывести структуры семантических вставок" << endl
203
<< " -S | --silence - не выводить диагностику утилиты" << endl
204
<< " -u | --dump-grammar - построить и сохранить грамматику в дампе" << endl
205
<< " -l | --load-grammar - загрузить грамматику из дампа" << endl
206
<< " | --lex <путь> - путь к файлу описания лексики" << endl
207
<< " -g | --grammar-file <путь> - путь к файлу грамматики" << endl
208
<< " -G | --path-to-grammar <путь> - путь к каталогу файлов грамматики" << endl
209
<< " (конкретная грамматика будет определяться по расширению исходного файла)" << endl
217
<< "Версия: " << lib_version().major() << "." << lib_version().minor() << endl;
219
std::ifstream in(grammar_file);
222
cout << "Ошибка при открытии файла '" << grammar_file << "'" << endl;
226
inout::InputStream in_stream(in);
227
inout::ConsoleReporter m;
228
parser::Grammar grammar;
230
bool ok = utility::grammatize(
235
"", //json_file_name,
236
"", //st_dot_file_name,
237
grammar_builder_method,
239
need_state_transitions_info,
246
false, //need_analyze_handles,
247
false, //need_analyze_inserts
254
for(const auto & [name, node] : grammar.handlers)
256
interpret::Interpret * inter = new interpret::Interpret(interpret::InterpretType::Preview, m, loom, {file_name}, node);
257
interpret::builtins::BaseRunning * lexGenerator = new interpret::builtins::BaseRunning(inter);
258
std::shared_ptr<interpret::builtins::LexicalParametersModule>
259
lex = std::make_shared<interpret::builtins::LexicalParametersModule>(grammar.lexical);
261
lexGenerator->importNamespace(u"lex", lex->instantiate(lex), inout::null_token_location);
262
inter->instantiateSemantics({lexGenerator});
263
loom.dock(inter, true);
269
if (!lex_file.empty() && !variable::loadLexicalParameters(lex_file,grammar.lexical)) {
270
cout << "Ошибка при чтении параметров лексики из файла '" << lex_file << "'" << endl;
274
variable::VariableSet_t hosts_and_operations = interpret::loadSemanticOperationsEnums(fs::path(grammar_file).parent_path().string());
276
interpret::Interpret inter(interpret::InterpretType::Preview, m, loom, {file_name}, null_node);
277
interpret::builtins::BaseInterpret_abstract *
278
sbl = new interpret::builtins::BaseRunning(&inter);
279
interpret::builtins::AstFormationBuilder
280
builder(m,*sbl, hosts_and_operations);
281
parser::PushdownAutomaton parser(m, grammar, inter.files(), builder);
283
inter.instantiateSemantics({sbl});
288
if (!st_dot_file_name.empty()) {
290
cout << "Построение DOT-файла..." << std::endl;
291
utility::generateDotFile(st_dot_file_name, builder.ast().tree().root(), {});
294
if (!json_file_name.empty()) {
296
cout << "Сохранение JSON-файла..." << std::endl;
298
ok = variable::saveJson(variable::toValue(builder.ast().tree()), json_file_name, false);
301
cout << "Ошибка сохранения в '" << json_file_name << "'" << std::endl;