loom

Форк
0
/
main.cpp 
318 строк · 13.9 Кб
1
/*
2
MIT License
3

4
Copyright (c) 2021 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,
5

6
https://bmstu.codes/lsx/simodo/loom
7
*/
8

9
/*! \file Синтаксический анализ
10
 *
11
 *  Утилита синтаксического анализа текста на любом языке, заданном грамматикой на языке SIMODO fuze.
12
 *
13
 *  Проект SIMODO.
14
*/
15

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"
34

35
#include <iostream>
36
#include <fstream>
37
#include <memory>
38
#include <algorithm>
39
#include <chrono>
40

41
#if __cplusplus >= __cpp_2017
42
#include <filesystem>
43
namespace fs = std::filesystem;
44
#else
45
#include <experimental/filesystem>
46
namespace fs = std::filesystem::experimental;
47
#endif
48

49
using namespace std;
50
using namespace simodo;
51
 
52
int main(int argc, char *argv[])
53
{
54
    vector<std::string> arguments(argv + 1, argv + argc);
55

56
    string  file_name           = "";
57
    string  json_file_name      = "";
58
    string  st_dot_file_name    = "";
59
    string  dot_file_name       = "";
60
    string  lex_file            = "";
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;
68
    bool	error               = false;
69
    bool	help                = false;
70
    bool	version             = false;
71
    bool    need_silence        = true;
72
    bool    need_build_grammar  = false;
73
    bool    need_load_grammar   = false;
74

75
    for(size_t i=0; i < arguments.size(); ++i)
76
    {
77
        const string & arg = arguments[i];
78

79
        if (arg[0] == '-')
80
        {
81
            if (arg == "--help" || arg == "-h")
82
                help = true;
83
            else if (arg == "--version" || arg == "-v")
84
                version = true;
85
            else if (arg == "--grammar-builder-method" || arg == "-z")
86
            {
87
                if (i == arguments.size()-1 || !grammar_builder_method_string.empty())
88
                    error = true;
89
                else
90
                    grammar_builder_method_string = arguments[++i];
91
            }
92
            else if (arg == "--json-semantics" || arg == "-j")
93
            {
94
                if (i == arguments.size()-1 || !json_file_name.empty())
95
                    error = true;
96
                else
97
                    json_file_name = arguments[++i];
98
            }
99
            else if (arg == "--grammar-file" || arg == "-g")
100
            {
101
                if (i == arguments.size()-1 || !grammar_file.empty())
102
                    error = true;
103
                else
104
                    grammar_file = arguments[++i];
105
            }
106
            else if (arg == "--lex")
107
            {
108
                if (i == arguments.size()-1 || !lex_file.empty())
109
                    error = true;
110
                else
111
                    lex_file = arguments[++i];
112
            }
113
            else if (arg == "--path-to-grammar" || arg == "-G")
114
            {
115
                if (i == arguments.size()-1)
116
                    error = true;
117
                else
118
                    grammar_path = arguments[++i];
119
            }
120
            else if (arg == "--dot-semantics" || arg == "-s")
121
            {
122
                if (i == arguments.size()-1 || !st_dot_file_name.empty())
123
                    error = true;
124
                else
125
                    st_dot_file_name = arguments[++i];
126
            }
127
            else if (arg == "--dot-grammar" || arg == "-d")
128
            {
129
                if (i == arguments.size()-1 || !st_dot_file_name.empty())
130
                    error = true;
131
                else
132
                    dot_file_name = arguments[++i];
133
            }
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")
139
                need_st_info = true;
140
            else if (arg == "--time-intervals" || arg == "-t")
141
                need_time_intervals = true;
142
            else if (arg == "--silence" || arg == "-S")
143
                need_silence = true;
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;
148
            else
149
                error = true;
150
        }
151
        else if (file_name.empty())
152
            file_name = arg;
153
        else
154
            error = true;
155
    }
156

157
    parser::TableBuildMethod grammar_builder_method = parser::TableBuildMethod::LR1;
158

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;
165
        error = true;
166
    }
167

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();
173
        }
174
    }
175

176
    if ((grammar_file.empty() || file_name.empty()) && !version && !help)
177
        error = true;
178

179
    if (need_load_grammar && (need_build_grammar || need_time_intervals))
180
        error = true;
181

182
    if (error) {
183
        cout << "Ошибка в параметрах запуска" << endl;
184
        help = true;
185
    }
186

187
    const string logo = "Утилита анализа грамматики. Проект SIMODO.";
188

189
    if (help)
190
        cout	<< logo << endl
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
211
                ;
212

213
    if (error)
214
        return 1;
215

216
    if (version)
217
        cout << logo << endl
218
             << "Версия: " << lib_version().major() << "." << lib_version().minor() << endl;
219

220
    std::ifstream in(grammar_file);
221

222
    if (!in) {
223
        cout << "Ошибка при открытии файла '" << grammar_file << "'" << endl;
224
        return 1;
225
    }
226

227
    inout::InputStream      in_stream(in);
228
    inout::ConsoleReporter  m; 
229
    parser::Grammar         grammar;
230

231
    bool ok = engine::grammatize(
232
                        grammar_file,
233
                        in_stream,
234
                        cout,
235
                        m,
236
                        "", //json_file_name,
237
                        "", //st_dot_file_name,
238
                        grammar_builder_method,
239
                        dot_file_name,
240
                        need_state_transitions_info,
241
                        need_rules_info,
242
                        need_st_info,
243
                        need_time_intervals,
244
                        need_silence,
245
                        need_build_grammar,
246
                        need_load_grammar,
247
                        false, //need_analyze_handles,
248
                        false, //need_analyze_inserts
249
                        grammar);
250
    if (!ok)
251
        return 1;
252

253
    loom::Loom   loom;
254

255
    for(const auto & [name, node] : grammar.handlers)
256
        if (name == u"lex")
257
        {
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>();
264

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);
275
            loom.stretch(inter);
276
        }
277

278
    loom.wait();
279

280
    if (!lex_file.empty() && !variable::loadLexicalParameters(lex_file,grammar.lexical)) {
281
        cout << "Ошибка при чтении параметров лексики из файла '" << lex_file << "'" << endl;
282
        return 1;
283
    }
284

285
    variable::VariableSet_t         hosts_and_operations = interpret::loadSemanticOperationsEnums(fs::path(grammar_file).parent_path().string());
286
    ast::Node                       null_node;
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);
293

294
    inter.instantiateSemantics({sbl});
295

296
    if (!parser.parse())
297
        return 1;
298

299
    if (!st_dot_file_name.empty()) {
300
        if (!need_silence)
301
            cout << "Построение DOT-файла..." << std::endl;
302

303
        const ast::Node & code = builder.ast().tree().root();
304
        engine::generateDotFile(st_dot_file_name, code, {});
305
    }
306

307
    if (!json_file_name.empty()) {
308
        if (!need_silence)
309
            cout << "Сохранение JSON-файла..." << std::endl;
310

311
        ok = variable::saveJson(variable::toValue(builder.ast().tree()), json_file_name, false);
312

313
        if (!ok)
314
            cout << "Ошибка сохранения в '" << json_file_name << "'" << std::endl;
315
    }
316

317
    return 0;
318
}
319

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.