loom

Форк
0
/
main.cpp 
305 строк · 12.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/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"
33

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

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

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

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

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

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

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

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

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

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

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

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

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

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

212
    if (error)
213
        return 1;
214

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

219
    std::ifstream in(grammar_file);
220

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

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

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

252
    loom::Loom   loom;
253

254
    for(const auto & [name, node] : grammar.handlers)
255
    {
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);
260

261
        lexGenerator->importNamespace(u"lex", lex->instantiate(lex), inout::null_token_location);
262
        inter->instantiateSemantics({lexGenerator});
263
        loom.dock(inter, true);
264
        loom.stretch(inter);
265
    }
266

267
    loom.finish();
268

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

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

283
    inter.instantiateSemantics({sbl});
284

285
    if (!parser.parse())
286
        return 1;
287

288
    if (!st_dot_file_name.empty()) {
289
        if (!need_silence)
290
            cout << "Построение DOT-файла..." << std::endl;
291
        utility::generateDotFile(st_dot_file_name, builder.ast().tree().root(), {});
292
    }
293

294
    if (!json_file_name.empty()) {
295
        if (!need_silence)
296
            cout << "Сохранение JSON-файла..." << std::endl;
297

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

300
        if (!ok)
301
            cout << "Ошибка сохранения в '" << json_file_name << "'" << std::endl;
302
    }
303

304
    return 0;
305
}
306

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

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

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

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