loom
254 строки · 8.9 Кб
1/*
2MIT License
3
4Copyright (c) 2021 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,
5
6https://bmstu.codes/lsx/simodo
7*/
8
9/*! \file Утилита тестирования средств лексического анализа библиотеки SIMODO core. Проект SIMODO.
10*/
11
12#include "simodo/variable/json/LexicalParametersLoader.h"
13#include "simodo/inout/convert/functions.h"
14#include "simodo/inout/reporter/Reporter_abstract.h"
15#include "simodo/inout/token/Tokenizer.h"
16#include "simodo/inout/token/FileStream.h"
17#include "simodo/inout/token/RefBufferStream.h"
18
19#include <fstream>
20#include <iostream>
21#include <locale>
22#include <codecvt>
23#include <memory>
24#include <algorithm>
25
26using namespace simodo::inout;
27using namespace simodo::variable;
28
29namespace
30{
31
32int produceLexicalAnalysis (const std::string & file_name, bool use_string_buffer, const LexicalParameters & lex_param)
33{
34std::ifstream in(file_name);
35std::u16string string_buffer;
36std::unique_ptr<InputStream_interface> stream;
37
38if (!in)
39{
40std::cout << "Ошибка при открытии файла '" << file_name << "'" << std::endl;
41return 2;
42}
43
44if (use_string_buffer)
45{
46InputStream in_stream(in);
47
48while(true)
49{
50char16_t ch = in_stream.get();
51if (ch == std::char_traits<char16_t>::eof())
52break;
53string_buffer += ch;
54}
55
56stream = std::make_unique<RefBufferStream>(string_buffer.data());
57}
58else
59stream = std::make_unique<InputStream>(in);
60
61Tokenizer tzer(0, *stream, lex_param);
62
63uint32_t comment_n = 0;
64uint32_t annotation_n = 0;
65uint32_t punctuation_n = 0;
66uint32_t keyword_n = 0;
67uint32_t word_n = 0;
68uint32_t word_national_mix_error_n = 0;
69uint32_t word_national_use_error_n = 0;
70uint32_t number_n = 0;
71uint32_t number_wrong_n = 0;
72uint32_t error_n = 0;
73uint32_t unknown = 0;
74uint32_t token_count = 0;
75
76Token t = tzer.getAnyToken();
77
78while (t.type() != LexemeType::Empty)
79{
80token_count ++;
81
82switch(t.type())
83{
84case LexemeType::Punctuation:
85punctuation_n ++;
86if (t.qualification() == TokenQualification::Keyword)
87keyword_n ++;
88break;
89case LexemeType::Id:
90word_n ++;
91if (t.qualification() == TokenQualification::NationalCharacterMix)
92word_national_mix_error_n ++;
93break;
94case LexemeType::Annotation:
95annotation_n ++;
96break;
97case LexemeType::Number:
98number_n ++;
99if (t.qualification() == TokenQualification::NotANumber)
100number_wrong_n ++;
101break;
102case LexemeType::Comment:
103comment_n ++;
104break;
105case LexemeType::Error:
106error_n ++;
107if (t.qualification() == TokenQualification::NationalCharacterMix)
108word_national_mix_error_n ++;
109if (t.qualification() == TokenQualification::NationalCharacterUse)
110word_national_use_error_n ++;
111break;
112default:
113unknown ++;
114break;
115}
116
117Location loc = t.makeLocation({file_name});
118
119std::cout << loc.uri()
120<< ":" << loc.range().start().line() << "/" << loc.range().start().character()
121<< "-" << loc.range().end().line() << "/" << loc.range().end().character() << ", token: \""
122<< simodo::inout::toU8(t.token()) << "\"";
123
124if (t.token() != t.lexeme())
125std::cout << ", lexeme: \"" << toU8(t.lexeme()) << "\"";
126
127std::cout << ", type: " << getLexemeTypeName(t.type());
128
129if (t.qualification() != TokenQualification::None)
130std::cout << ", qualification: " << getQualificationName(t.qualification());
131
132std::cout << std::endl;
133
134t = tzer.getAnyToken();
135}
136
137std::cout << "ИТОГО: токенов ..... " << token_count << std::endl
138<< " комментариев. " << comment_n << std::endl
139<< " аннотаций ... " << annotation_n << std::endl
140<< " пунктуаций .. " << punctuation_n << " (из них ключевых слов: " << keyword_n << ")" << std::endl
141<< " слов ........ " << word_n << " (из них с перемешанными алфавитами: " << word_national_mix_error_n << ")" << std::endl
142<< " чисел ....... " << number_n << " (из них с ошибками: " << number_wrong_n << ")" << std::endl
143<< " ошибок ...... " << error_n
144<< " (из них с недопустимым алфавитом: " << word_national_use_error_n << ","
145<< " c перемешанными алфавитами: " << word_national_mix_error_n << ")" << std::endl
146<< " сбоев ....... " << unknown << std::endl
147;
148
149return 0;
150}
151}
152
153int main(int argc, char *argv[])
154{
155std::vector<std::string> arguments(argv + 1, argv + argc);
156
157std::string file_name = "";
158bool use_char16_buffer = false;
159std::string lex_file_name = "";
160
161bool error = false;
162bool help = false;
163
164std::vector<NumberMask> masks;
165
166for(size_t i=0; i < arguments.size(); ++i)
167{
168const std::string & arg = arguments[i];
169
170if (arg[0] == '-')
171{
172if (arg == "--help" || arg == "-h")
173help = true;
174else if (arg == "--use-char16-buffer")
175use_char16_buffer = true;
176else if (arg == "--lex-param-json" || arg == "-l")
177{
178if (i == arguments.size()-1 || !lex_file_name.empty())
179error = true;
180else
181lex_file_name = arguments[++i];
182}
183else if (arg == "--number_mask" || arg == "-n")
184{
185if (i+2 >= arguments.size())
186error = true;
187else {
188masks.push_back({toU16(arguments[i+1]),
189LexemeType::Number,
190static_cast<number_system_t>(stoi(arguments[i+2]))});
191i += 2;
192}
193}
194else
195error = true;
196}
197else if (file_name.empty())
198file_name = arg;
199else
200error = true;
201}
202
203if (!help && file_name.empty())
204error = true;
205
206if (error)
207{
208std::cout << "Ошибка в параметрах запуска" << std::endl;
209help = true;
210}
211
212if (help)
213std::cout << "Утилита лексического анализа. Чтение лексических параметров из JSON-файла. Проект SIMODO." << std::endl
214<< "Формат запуска:" << std::endl
215<< " <имя утилиты> [<параметры>] <файл>" << std::endl
216<< "Параметры:" << std::endl
217<< " -h | --help - отображение подсказки по запуску программы" << std::endl
218<< " --use-char16-buffer - провести лексический анализ заданного файла с использованием строкового буфера" << std::endl
219<< " -l | --lex-param-json <файл> - JSON-файл определения лексических параметров" << std::endl
220<< " -n | --number_mask <маска> <система счисления> - добавить маску числа" << std::endl
221;
222
223if (error)
224return 1;
225
226if (file_name.empty())
227return 0;
228
229LexicalParameters lex_param{
230{},
231{},
232u"",
233{},
234u"",
235u"",
236u"",
237u"",
238false,
239false,
240false
241};
242
243if (!lex_file_name.empty())
244if (!loadLexicalParameters(lex_file_name,lex_param))
245{
246std::cout << "Ошибка при загрузке файла описания лексики '" << lex_file_name << "'" << std::endl;
247return 1;
248}
249
250for(const NumberMask & m : masks)
251lex_param.masks.push_back(m);
252
253return produceLexicalAnalysis(file_name, use_char16_buffer, lex_param);
254}
255