This repository has been archived by the owner on Sep 22, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
/
frontend.cxx
312 lines (260 loc) · 10.4 KB
/
frontend.cxx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
/*
* Copyright 2016-2017 libfptu authors: please see AUTHORS file.
*
* This file is part of libfptu, aka "Fast Positive Tuples".
*
* libfptu is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* libfptu is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with libfptu. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* libfptu = { Fast Positive Tuples, aka Позитивные Кортежи }
*
* The kind of lightweight linearized tuples, which are extremely handy
* to machining, including cases with shared memory.
* Please see README.md at https://github.com/leo-yuriev/libfptu
*
* The Future will Positive. Всё будет хорошо.
*
* "Позитивные Кортежи" дают легковесное линейное представление небольших
* JSON-подобных структур в экстремально удобной для машины форме,
* в том числе при размещении в разделяемой памяти.
*/
#include "ast.h"
#include "interfaces.h"
#include <map>
#include <set>
#include <stack>
#include <stdarg.h>
#include <stdio.h>
#include <vector>
#include "filesystem.h"
#include <sstream>
namespace fptu {
namespace Schema {
namespace Compiler {
void Throw_InvalidTypenameLength(const Token &token, const char *reason) {
throw exception(
token, format("Typename '%*s' is %s", token.length, token.text, reason));
}
void Throw_InvalidTypeIdValue(const Token &token) {
throw exception(token,
format("TypeId '%*s' is invalid", token.length, token.text));
}
class Engine : public IFrontend {
protected:
typedef std::map<TokenId, Node *> nodes_by_id;
typedef std::map<std::string, Node *> nodes_by_name;
/* схема как плоский список всех узлов без иерархии. */
NodeList scheme_;
/* узлы по номеру типов. */
nodes_by_id nodes_by_id_;
/* узлы по полному имени типов. */
nodes_by_name nodes_by_name_;
void collect(Node *node);
void collect(std::unique_ptr<NodeList> &&list, Node *parent);
Node *find(const BaseName *);
Node *find(const unsigned);
void generate_builtins();
std::unique_ptr<IBackend> builder_;
typedef std::map<const Symbol *, std::unique_ptr<ISourcer>,
std::greater_equal<const Symbol *>>
sources_list;
/* Все исходники отсортированные по адресам токенов */
sources_list sources_;
/* Стек с путями к исходникам,
* нужен для правильной обработки вложенности import-директив */
std::stack<const char *> stack_;
/* Имя обрабатываемого сейчас файла.
* Требуется для сообщений об ошибках при обработке исключений */
const char *current_filename_;
public:
Engine() { generate_builtins(); }
void Append(std::unique_ptr<NodeList> &&list) {
collect(std::move(list), nullptr);
}
void Import(std::unique_ptr<BaseName> &&name);
void Commit();
void Load(const std_filesystem::path &filename);
void Update();
void Product(const std_filesystem::path &basename);
Location Where(const Token &) const;
void HandleException(const std::exception *trouble);
};
IFrontend *IFrontend::Create() { return new Engine(); }
/* Вывод сообщения об ошибке. */
void IFrontend::Error(const char *msg, ...) {
ok_ = false;
fputs("pts-compiler.Error: ", stderr);
va_list ap;
va_start(ap, msg);
vfprintf(stderr, msg, ap);
putc('\n', stderr);
va_end(ap);
}
/* Вывод предупреждения. */
void IFrontend::Warning(const char *msg, ...) {
fputs("pts-compiler.Warning: ", stderr);
va_list ap;
va_start(ap, msg);
vfprintf(stderr, msg, ap);
putc('\n', stderr);
va_end(ap);
}
/* Поиск типа по полному имени с диагностикой. */
Node *Engine::find(const BaseName *name) {
if (name) {
std::string key = fqtn(name);
nodes_by_name::iterator at = nodes_by_name_.find(key);
if (at != nodes_by_name_.end())
return at->second;
Error("Undefined type-name '%s'", key.c_str());
}
return nullptr;
}
/* Поиск типа номеру с диагностикой. */
Node *Engine::find(const unsigned id) {
if (id) {
nodes_by_id::iterator at = nodes_by_id_.find(id);
if (at != nodes_by_id_.end())
return at->second;
Error("Undefined type '%u'", id);
}
return nullptr;
}
/* Первый проход, собираем узлы из "дочернего" списка. */
void Engine::collect(std::unique_ptr<NodeList> &&list, Node *parent) {
if (list) {
while (!list->empty()) {
std::unique_ptr<Node> node = std::move(list->front());
list->pop_front();
node->parent_ = parent;
node->deep_ = parent ? parent->deep_ + 1 : 1;
collect(node.get());
scheme_.push_back(std::move(node));
}
}
}
/* Первый проход, добавляем узел и рекурсивно его дочерние. */
void Engine::collect(Node *node) {
/* TODO */
collect(std::move(node->child_), node);
}
void Engine::Commit() {}
//------------------------------------------------------------------------------
/* Импорт (загрузка) части схемы из файла по директиве 'import'. */
void Engine::Import(std::unique_ptr<BaseName> &&name) {
std_filesystem::path filename(
std_filesystem::path(stack_.top()).parent_path());
for (BaseName::iterator i = name->begin(), e = name->end(); i != e; ++i)
filename /= i->string();
Load(filename.replace_extension(".pts"));
}
/* Штатный костыль на отсутствие finally в C++. */
template <typename I> class raii_stacker {
std::stack<I> &stack_;
public:
raii_stacker(std::stack<I> &stack, const I &i) : stack_(stack) {
stack_.push(i);
}
~raii_stacker() { stack_.pop(); }
};
/* Загрузка описания схемы из исходного файла. */
void Engine::Load(const std_filesystem::path &filename) {
std_filesystem::file_status status(std_filesystem::status(filename));
if (!std_filesystem::exists(status))
Error("the file '%s' is not exists.", filename.c_str());
else if (!std_filesystem::is_regular_file(status))
Error("the file '%s' is not a regular file.", filename.c_str());
else if (!std_filesystem::file_size(filename))
Warning("the file '%s' is empty.", filename.c_str());
else {
const size_t before = scheme_.size();
current_filename_ = filename.c_str();
try {
std::unique_ptr<ISourcer> sourcer(ISourcer::Create(filename));
auto ptr = sourcer.get();
auto key = sourcer->begin();
sources_[key] = std::move(sourcer);
std::unique_ptr<ILexer> lexer(ILexer::Create(this, ptr));
std::unique_ptr<IParser> parser(IParser::Create(this));
raii_stacker<const char *> guard(stack_, current_filename_);
while (true) {
ILexer::Result token = lexer->Scan();
if (options.verbose) {
::fprintf(::stdout, "%d %.*s\n", token.id, token.length, token.text);
::fflush(::stdout);
}
if (TOKEN_COMMENT != token.id)
parser->Push(token);
if (TOKEN_EOF == token.id)
break;
}
} catch (const std::exception &trouble) {
HandleException(&trouble);
}
current_filename_ = stack_.empty() ? nullptr : stack_.top();
if (before == scheme_.size())
Warning("no definitions in the file '%s'.", filename.c_str());
}
}
//------------------------------------------------------------------------------
/* Обновление (простановка) назначенных номеров типов в исходных файлах
* описания схемы. */
void Engine::Update() { current_filename_ = nullptr; }
/* Формирование продуктов компиляции (бинарного справочника схемы и
* h-файла с определениями). */
void Engine::Product(const std_filesystem::path &basename) {
std_filesystem::path filename(basename);
// std::ofstream file;
// file.exceptions(std::ios::failbit | std::ios::badbit);
filename += "-scheme.h";
current_filename_ = filename.c_str();
// file.open(current_filename_, std::ios::out | std::ios::trunc);
// builder_.todo(file);
// file.close();
current_filename_ = nullptr;
}
fptu_typeKey Node::typekey() const { return 0 /* FIXME */; }
//------------------------------------------------------------------------------
/* Генерация базовых/встроенных liro-типов. */
void Engine::generate_builtins() { current_filename_ = nullptr; }
/* Возвращает локацию для переданной лексемы. */
Location Engine::Where(const Token &token) const {
auto i = sources_.lower_bound(token.end());
if (i == sources_.end() || token.begin() < i->second->begin())
throw std::out_of_range("Token out of sources");
return i->second->Where(token.begin());
}
void Engine::HandleException(const std::exception *trouble) {
const auto trouble_with_token = dynamic_cast<const exception *>(trouble);
if (trouble_with_token) {
const Location location = Where(trouble_with_token->token());
if (location.line || location.position)
Error("%s, file '%s', line %u, position %u", trouble->what(),
location.filename, location.line, location.position);
else
Error("%s, file '%s'", trouble_with_token->what(), location.filename);
} else if (current_filename_) {
Error("exception %s, file '%s'", trouble->what(), current_filename_);
} else {
Error("exception %s", trouble->what());
}
}
void IFrontend::SyntaxError(const Token &token) {
const Location location = Where(token);
Error("Syntax at file '%s', line %u, position %u", location.filename,
location.line, location.position);
}
} /* namespace Compiler */
} /* namespace Schema */
} /* namespace fptu */