- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 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
// https://govnokod.ru/26890#comment571155
// bormand 2 часа назад #
// Можно брейнфак запилить на операторах. Как раз вроде унарных хватает.
// & * - ~ ! -- + ++ --
#include <array>
#include <vector>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <limits>
struct Brainfuck {
public:
using IPType = uint16_t;
constexpr static size_t MAX_MEMORY = std::numeric_limits<IPType>::max();
std::array<uint8_t, MAX_MEMORY> memory{};
std::vector<char> app{};
IPType ip = 0;
IPType cell = 0;
IPType find_matching_tag(IPType cur_ip, char open, char close, int ip_direction)
{
size_t stack_size = 0;
do {
if (app[cur_ip] == close) {
--stack_size;
}
if (app[cur_ip] == open) {
++stack_size;
}
cur_ip += ip_direction;
} while (stack_size > 0);
return cur_ip - ip_direction;
}
IPType find_matching_close_tag(IPType cur_ip)
{
return find_matching_tag(cur_ip, '[', ']', 1);
}
IPType find_matching_open_tag(IPType cur_ip)
{
return find_matching_tag(cur_ip, ']', '[', -1);
}
void loop_open()
{
if (memory[cell] == 0) {
ip = find_matching_close_tag(ip);
} else {
++ip;
}
}
void loop_close()
{
if (memory[cell] != 0) {
ip = find_matching_open_tag(ip);
} else {
++ip;
}
}
void exec(char op)
{
switch (op) {
case '>': ++cell; break;
case '<': --cell; break;
case '+': ++memory[cell]; break;
case '-': --memory[cell]; break;
case '.': std::putchar(memory[cell]); break;
case ',': memory[cell] = static_cast<uint8_t>(std::getchar()); break;
case '[': loop_open(); return; // no ip advancing
case ']': loop_close(); return; // no ip advancing
}
ip++;
}
void run()
{
while (ip < app.size()) {
exec(app[ip]);
}
}
public:
Brainfuck & operator++() { app.push_back('>'); return *this; }
Brainfuck & operator--() { app.push_back('<'); return *this; }
Brainfuck & operator+() { app.push_back('+'); return *this; }
Brainfuck & operator-() { app.push_back('-'); return *this; }
Brainfuck & operator*() { app.push_back('.'); return *this; }
Brainfuck & operator&() { app.push_back(','); return *this; }
Brainfuck & operator!() { app.push_back('['); return *this; }
Brainfuck & operator~() { app.push_back(']'); return *this; }
Brainfuck & operator>>(const Brainfuck &) { run(); return *this; }
};
Перевод из классического «Брайнфака» в крестовый DSL:
Какой еще язык можно так быстро реализовать?
а гост ебанутый малость, это уже очевидно
> Его спецификация настолько проста, что ты написал его реализацию за два часа.
И бо́льшая часть времени заняла реализация циклов (только под самый конец осознал, что [ может сразу же переместиться к ], поэтому просто последовательно по одному символу проходить не получится).
Закрывающая скобка цикла "пушит" правую часть в отдельное поле и начинает новую пустую цепочку. Открывающая скобка заворачивает эту цепочку в цикл и пристегивает к запушенному куску.
Ну и у всего этого есть невиртуальный оператор (). Должно неплохо оптимизироваться если в глубину инлайнов не упрется.
S<Plus, Plus, Plus, Loop<Plus, Right, Minus, Left>, Out>
S::operator() { dummy(args()...); } где dummy ничего не делает.
Это вроде лучше инлайниться должно.
Осталось в операторы обмазать.
Всё, заебало, будет без украшательств. Работает и ладно.
Кстати в компайлтайме проверяет баланс циклов.
Для рынка этот язык никчемный.
З.Ы. Ну в CSM ещё фрагменты есть для общения с 16-битной хуйнёй. Но тут явно не этот случай.
у меня почти все проги под реальный режим вообще были tiny, это я помню.
Но хуйню, которая грузится с загрузочной дискеты и выводит ":)" я тоже делал когда mbr изучал, а вот про uefi я знаю только в теории(
Да там ничего особо интересного. Гуиды да интерфейсы. Получаешь интерфейс по гуиду да зовёшь методы. Той магии, что была на биосе, там уже нет.
32-битный уефи ты в природе хер найдёшь. Вроде больше не выпускают девайсов с ним.
В железо тебе там лезть не надо, там всё очень высокоуровневое. Даже к pci лазить будешь через интерфейс а не напрямую.
В прерывания тоже лезть не надо, там все на таймерах да ивентах. Да там кроме таймерного их и нет, лол.
Это по сути простенькая однозадачная ось.
>Даже к pci лазить будешь через интерфейс.
Там прямо сишные функции "энумирейт бас", "считать доступные адреса из спейса" и "настроить девайс"?
> на таймерах да ивентах.
Колбеки типа?
Ну вот разве что у дисплея ты можешь захотеть напрямую порисовать. Там интерфейс тормознутый (адрес, разрешение и формат пикселя он тебе расскажет).
Это может быть важно, чтобы игрушки писать. А для загрузочного экрана наверное пофиг. Тащемто биосный API для видео тоже тормозил.
А для USB? SATA? Для этого говна тоже есть API, или там напрямую не нужно?
Есть интерфейсы для дисков. Рид да врайт.
Есть интерфейс для файлухи. Но изкоробки только фат да исо. Разделы и т.п. само подхватывает и публикует.
В принципе там плуг энд плей даже.
Так прошивка сама всё конфигурит (это ведь и есть плуг энд плей), но ты можешь потом переконфигурить под себя?
А вот ты говоришь, что там си, да? А там надо статически рунтайм весь в себя линковать?
Да, прошивка сама все что может распознает и конфигурит. Лоу-левел интерфейсы это если ты свои дрова собрался писать.
типа
?
Я просто не понял, а откуда я возьму printf?
> Лоу-левел интерфейсы это если ты свои дрова собрался писать.
Кстати, а что случилось с биосами устройств?
Если я сделаю карточку, и хочу чтобы uefi мог с нее грузиться, я могу в карточке разместить какой-то код под efi, который сэмулирует из нее например диск или mass storage usb?
Аллокаторы, сосноль, всё через те таблички.
то есть ответ на мой вопрос про рантайм -- хуй. Ну ок, тоже ничего.
Остался вопрос про биосы устройств
А для всяких usb все и на дженерик дровах взлетает. Мышки, клавы, флешки и т.п.
Спасибо)
или у виртуалок есть интерфейсы для дебага uefi?
куему может
мои первым кодом было мигание лампочками на клаве.. там был io порт вроде, и туда надо было писать
А фиг знает, возможно в старых бекапах есть. Я давно туда не заглядывал. Может быть уже и проебал.
Нет. Чтение неинициализированных данных - UB. Вплоть до полного разрушения логики и true = false в других местах программы.
Не надо так делать.
Ну с int или char, скорее всего, ничего особо страшного не случится.
А флоат просто крашнуть процесс может. Хотя это обычно отключено.
Там вроде только при нормальном касте в инт гарантируется единичка. А в самом буле запросто может лежать FF.
Ну и ты забиваешь его единичками а не true.
Каст була в инт возвращает 0 или 1. Независимо от внутренного представления була.
Каст инта в бул возвращает false для 0 и true для остального. Независимо от внутренного представления була.
Ну он чарами заполняет. Просто исторически сложилось, что он в интерфейсе инт принимает.
Нельзя. Ты заполняешь единичками а не true ибо memset принимает int, а (int)true это 1. Он не шаблон.
std::fill(std::begin(bools), std::end(bools), true) и не еби мозг.
Но memset принимает int. А (int)(bool)1 это 1. А true это не обязательно 1. И вообще бул может быть больше байта (хотя я такого идиотизма нигде не видел).
Ну, по крайней мере, там будет false а не UB.
З.Ы. А, это MS так позиксовые функции уродует.
Имхо, лучше уж явно проверить в начале, возможно даже static_assert'ом. А потом и обычный memcpy сойдёт.
Только одного типа и размера можно присваивать друг другу.
Ну вектора и мапы всякие с кучей работают.
Ну как ваш ArrayList.
И даже вообще без стандартной либы. Но это уже просто няшная с RAII и шаблонами.
И исключения тоже, по крайней мере в gcc. Там чуть-чуть аллокатор зовётся при старте. Возможно и потом при каких-то условиях (слишком жирное исключение или второе подряд?) Я сильно не изучал.
Придётся на них тоже забить если кучи нету.
sizeof(bool) is not required to be 1
кроме чара и байта вроде, это довольно логично
вероятно, и массив байтов можно читнуть
if an indeterminate value of type unsigned char or std::byte (since C++17) is assigned to another variable of type (possibly cv-qualified) unsigned char or std::byte (since C++17)(the value of the variable becomes indeterminate, but the behavior is not undefined);
https://en.cppreference.com/w/cpp/language/default_initialization
Если я верно понимаю, то написано так:
Да, ты можешь считать любое значение. Но компьютер не сгорит. А если ты считаешь его из булена, например, то у тебя может нарушиться true != false или еще что-то такое
Ты можешь присвоить indeterminate value из одного байта только другому байту. Если ты потом попытаешься получить доступ к этому indeterminate value (например, попробуешь его вывести на экран) — всё равно получишь UB.
Хотя, с другой стороны, они обычно volatile поэтому конпелятор не выёбывается.
Ну ведь это же логично: один байт всегда валиден, какое бы говно ты туда ни пихнул.
А int совсем нет.
Допустим, на какой-то системе старший бит инта обязан быть единицией. Или обязан быть чексуммой. Если это не так, то процессор взрывается.
А ты сунул туда говно, и всё сломалось.
> Если ты потом попытаешься получить доступ
хм.
А вот тут я не уверен: является ли UB вывод этого байта в cout?
Хотя... если он прям сразу в буфер с байтами пишется...
char a;
char b[1];
b[0] = a;
так можно?
C++ стоит учить именно ради того, чтобы вести такие беседы,лол
Хотя, емнип, примеры в стандарте не являются нормативными и на них нельзя строить пруфы.
А взять любые 4 байта и сказать "вот инт" я не могу: это может быть не правдой.
Так я трактую cppref, но надо читат стандарт
§ 6.7.4/2
пускай я хочу чтобы там был любой мусор в зависимости от желания компилятора
зачем мне тратить инструкцию на заплнение инта чем-то?
З.Ы. Но по стандарту там и на входе и на выходе конечно же байты.
Все выводящие байт функции (put, putchar, fputc, etc.) принимают int, поэтому вывод через них — является. Аргументы всех функций форматированного вывода (fprintf, printf, etc.) сначала integer promotятся, поэтому через них тоже вывести не получится. А поведение basic_ostream::operator<<(..., unsigned char) по Стандарту я сейчас подробно изучаю.
интресно про стрим
Скобки нахуя?
Так понимаю, что до 11 у тебя вообще выбора не было: фигурные скобочки писать было нельзя, а круглые (благодаря Most vexing parse) -- тоже.
Так вот зачем лалки придумали «cstdio» вместо «stdio.h».
Ибо массив на 65535 элементов вместо 65536.
Да это-то похуй, несбалансированные циклы — это UB. А вот память задумывалась полноценно циклической.
Слова не мальчика, но крестостандартизатора.
Что-то гугл мне не помог по этому понятию, где о них почитать?
У Кнута?
Получается что php получилось довести до совершенства только за 7 версий,
а с++ и за 20 не смогли
наверное сишники опять проебались и случилось переполнение численного типа
https://bellard.org/jslinux/
Да, тот самый Фабрис.
> public:
Структура и так public. И по смыслу здесь не структура, а класс.
Просто охуенное название переменной.
Первое о чём подумал, нахуя здесь тип айпишника, и при чем он в brainfuck.
std::string
Программа по смыслу - это строка.
Ну и по-хорошему там вообще должен быть std::deque<char> и push_front() в операторах.
Ну видимо потому что вектор позже появился. А хреновых строк уже понаписали.
В первых крестах даже контейнеров и алгоритмов то не было, стринг да иострим.
А вот для вектора он явно требует амортизированное О(1).
И комитет всегда реально ссыт кому-то что-то сломать.
Там до смешного доходит, когда новые классы добавляют вместо того, чтобы пофиксить старые. И теперь у тебя есть выбор между scoped_lock, unique_lock и lock_guard.
Oh, my sweet summer child...
Надо глянуть, может там добавили пункт про О(1) у строки.
Или код длиннее 65к - тоже UB?
Подтверждаю, инженерный отдел напутал cell и app.
> Или код длиннее 65к - тоже UB?
А и то правда!