Каким должен быть язык программирования? Анализ и критика Описание языка Компилятор
Отечественные разработки Cтатьи на компьютерные темы Компьютерный юмор Новости и прочее

О русском ассемблере

Краткая история появления пробной версии русского ассемблера

Это была работа «под заказ». Но до, ни после создание подобного транслятора меня не интересовало. Дело было так.

Один великовозрастный недросль хотел получить диплом вуза. Да вот незадача: надо написать дипломную работу. Эта задача ещё осложнялась тем, что этот оболтус, в отличие от своих однокурсников, не стажировался на партнёрских предприятиях. Однокурсники совершенствовали навыки программирования на практических задачах и подбирали для себя темы дипломных проектов, а вот у нашего героя на уме было одно: любоффь и предстоящая свадьба. Вот и получилось: «лето красное пропела, оглянуться не успела...».

Ну и как нередко бывает в жизни, понадобились звонок другу и помощь из зала. Все глаза уставились на меня в надежде, что я не дам пропасть будущему специалисту, что надо оказать помощь прямо сейчас, а вот в будущем он сам возьмётся за ум. Просто у него сейчас мозги ещё не окрепли. Но в будущем это обязательно произойдёт. Потом так и случилось, он повзрослел и стал востребованным специалистом. Задним числом это оправдывает меня :)

Началась подборка темы дипломного проекта. Если однокурсники брали темы у руководителей стажировки, то в нашем случае тему было взять неоткуда. Что мог предложить я? Что-то по теме компиляторов. Чтобы написать какой-то компилятор для какого-то языка, пусть и простейшего, нужно время, которого оставалось мало. Русификацию Си/C++ предложить уже не мог, потому что сразу стало бы ясно, что работа «позаимствована». Легко проверяемо Гуглом. Значит, нужна уникальность. Нашлась неосвоенная ниша — язык ассемблера. Тем более, что в узком кругу уже поднималась тема русского ассемблера. Но если раньше меня эта тема не вдохновляла особо, то теперь деваться было некуда. В институте тему утвердили, начал «въезжать» в неё.

Язык ассемблера выглядит для непосвящённого человека как результат работы бредогенератора. Да и для посвящённого не всё прозрачно. Чтобы читать программу «с листа», нужен многолетний опыт. Хотелось бы этот язык очеловечить. Ведь что толку от замены абракадабр на латинице на абракадабры на кириллице?. К тому же нет общепринятых сокращений русских названий команд. Их нет в учебниках, они не ищутся поисковыми системами.

Поначалу хотелось как можнно больше команд заменить не русскими аббревиатурами, а некими «иероглифами», понятными всему населению планеты — последовательностями спецсимволов. Но такой язык очень быстро превращался в BrainF*ck: длинный забор из ключков и палочек ничуть не способствует быстрому пониманию сути текста. Пришлось ограничиться базовыми операциями в надежде на правило «20 на 80». Что надо 20% наиболее употребляемых операций заменить на понятные и легкозапоминаемые спецсимволы. А лучше, если их вообще запоминать не надо, чтоб они были знакомы из школьной арифметики. И они должны, по идее, занять 80% текста. Вот что получилось в итоге, текст из реальной программы на русском ассемблере:

\\ указатель на строку в - [EBP+08H]
Длина строки  ПРОЦ НАЧАЛО
	БАЗА }; БАЗА = СТЕК
	И }
	И = АДР32 (БАЗА+8)
	Б ^ Б
Метка1:
	АДР8 (И) ? 0
	== Метка2
	++ Б; ++ И
	--> Метка1
Метка2:
	И {; БАЗА {
	<-- 4
Длина строки  ПРОЦ КОНЕЦ

Конечно, не все согласятся, что это лучший вариант замены, укажут на субъективность вкусов. Но под каждой заменой есть аргументированное обоснование. Впрочем, в этом проекте есть возможность полностью сменить синтаксис на свой собственный вариант. С одной стороны, это гибко. С другой — отсутствие стандарта всё же не есть хорошо.

Тема так же обсуждалась на форуме.

P.S. Не могу найти у себя переписку с одним разработчиком, который рассказывал, как они мучались с русским ассемблером под какую-то отечественную систему команд отечественной архитектуры. И как они вздохнули, когда ассемблер был переделан на английские абревиатуры команд. На это только и ответил, что ассемблеры, по-видимому, делятся не только на русские и нерусские, но и на хорошие и плохие. Так что не всё так однозначно.

Если подумать на перспективу

И ещё вопрос: нужен ли он — русский ассемблер? Мне кажется, что если есть другая интересная или нужная работа, то лучше выбрать её. За 8 прошедших лет никто (ни один человек!) не заинтересовался ни моими исходниками, ни исполняемым модулем. Конечно, это может говорить о том, что это только мой ассемблер никому не нужен. Зато другой с гениально подобранными заменами аббревиатур на латинице точно взлетит! Увы, но сильно сомневаюсь.

Кстати, для генерации бинарного кода ассемблер не нужен. Дмитрий Караваев в своём компиляторе PL/1 и Андрей Хохлов в компиляторе Context генерируют бинарный код напрямую. Это не говоря о более известных компиляторах. И ещё кстати. Компилятор Дмитрия Караваева — не только для языка PL/1, но и для языка ассемблера x86/x86-64, то есть два в одном. Идентификаторы там можно записывать кириллицей. Русских обозначений команд не имеется, но задачу «суверенного» компилятора он по крайней мере решает.

Если кто-то решится делать русский ассемблер, то делать его надо в связке с русским дизассемблером и русским отладчиком. А то ведь сгенерируем машинный код, а как потом его расшифровать, сделать обратное преобразование?

Если же делать «универсальный ассемблер», который в чём-то конкурировал бы с LLVM, то надо не допустить ошибок этого проекта. Например, «Low Level» на деле оказывается не таким уж и «low». Если взять наиболее популярные архитектуры процессоров (x86, ARM, MIPS), то во всех есть такие низкоруровневые средства, как стек, регистры и флаги. Но в LLVM они отсутствуют. До такого низкого уровня из LLVM «не достучаться»: нет прямых средств для управления стеком, регистрами и флагами. Знатоки LLVM советуют пользоваться в таких случаях ассемблерными вставками под каждую платформу. Что само по себе дискредитирует LLVM как кроссплатформенный инструмент.

Есть интересное предложение по развитию С++, которое подразумевает прямое использование флага процессора:

Герб Саттер (Herb Sutter) в P709 описал новый механизм передачи исключений. Идейно, функция возвращает std::expected, однако вместо отдельного дискриминатора типа bool, который вместе с выравниванием будет занимать до 8 байт на стеке, этот бит информации передаётся каким-то более быстрым способом, например, в Carry Flag.

Функции, которые не трогают CF (таких большинство), получат возможность использовать статические исключения бесплатно — и в случае обычного возврата, и в случае проброса исключения! Функции, которые вынуждены будут его сохранять и восстанавливать, получат минимальный оверхед, и это всё равно будет быстрее, чем std::expected и любые обычные коды ошибок.

Представить это новшество в GCC или в компиляторе Microsoft совсем нетрудно: в них можно напрямую обратиться к флагу CF. Элементарно, Ватсон! Но вот как это будет делаться в компиляторе Clang, которые работает поверх LLVM? Будут пилить на низком уровне по каждую платформу в отдельности, только бы не дать доступ к «лишним подробностям».

В советское время тоже были проекты «универсального ассемблера»: языки АЛМО, Сигма, Эпсилон и другие. Возможно, там что-то можно найти что-то интересное.

Выводы

Идея универсалього ассемблера или универсального промежуточного представления хороша тем, что поволит экономить на генерации кода под конкретную платформу.

Универсальное промежуточное представление и генератор кода

Разработчикам языков достаточно написать компилятор своего языка в универсальное промежуточное представление — и он заработает на M платформах. Разработчикам архитектур достаточно написать компилятор с универсального промежуточного представления в коды своей системы команд — и на этой платформе будет компилироваться N языков. Вместо написания M*N компиляторов достаточно написать N компиляторов в промежуточное представление и M компиляторов с него в машинный код.

Опубликовано: 2022.11.27, последняя правка: 2022.11.29    00:15

ОценитеОценки посетителей
   ███████████████████████████████ 8 (72.7%)
   ████████ 2 (18.1%)
   ▌ 0
   ████ 1 (9.09%)

Отзывы

     2022/11/28 23:22, MihalNik          # 

За 8 прошедших лет никто (ни один человек!) не заинтересовался ни моими исходниками, ни исполняемым модулем. Конечно, это может говорить о том, что это только мой ассемблер никому не нужен.

Ну, Вы его, наверное, давно общепринятым способом никуда вроде гитхаба и не выкладывали, да и в данном случае сомнительны права на это — как бы чужой диплом. Ручными запросами на исходники люди в принципе редко занимаются, а в данном случае это не этично. Тем более неизвестно, на чем он написан, качество исходников, функциональность, польза вот вообще сомнительна.

Кто нынче пишет на ассемблере? Разве что вставки мелкие какие-нибудь внутри ЯВУ. Если даже самому автору не надо — кто будет поддерживать и развивать? В данном случае, надо полагать, сделать грамотный красивый перевод (как и вообще язык) гораздо сложнее реализации самого механизма перевода.

Разработчикам языков достаточно написать компилятор своего языка в универсальное промежуточное представление — и он заработает на M платформах.

Сейчас чаще всего это C или JS.

     2022/11/29 12:30, Gudleifr          # 

Зачем изобретать новые проблемы? Есть две старых:
  • язык ассемблера должен наглядно описывать команды и структуры машинного языка. Чего стоят 8 полей типов данных в 386-м!? А его шлюзы!? Сравните, насколько отличается элегантнейший FORTH-ассемблер для 8080 от моего 386-го монстра;
  • язык ассемблера должен быть способным создавать наглядные описания интерфейсов к используемым ОС. Сравните, как мне пришлось плясать с бубном для удовлетворения требований WinAPI. Сюда же — конструкций ЯВУ
Победите это — победите всё. И поймёте, что байки о совместимости и переносимости — это просто байки.

     2022/11/29 14:06, Автор сайта          # 

Вы его, наверное, давно общепринятым способом никуда вроде гитхаба и не выкладывали

Гитхаб ничем не помог бы. Есть в сети место сосредоточения любителей ассемблера — форум ОС «Колибри». Русификация ассемблера не то, чтобы вызвала маленький интерес. Он оказался вообще нулевым. Сравниваю с русификатором Си: его скачивали 1,5 тыс. раз, несколько человек интересовались исходниками. А тут полное безразличие.

Ручными запросами на исходники люди в принципе редко занимаются, а в данном случае это не этично.

Так историю никто не знал, поэтому «этика» ни на что не могла повлиять.

Тем более неизвестно, на чем он написан, качество исходников, функциональность

Чтобы всё это оценить, нужно хотя бы поинтересоваться. Но не было даже попыток это сделать.

Сейчас чаще всего это C или JS

Да, JS в этом качестве в какой-то мере удивляет. Язык с автоматическим управлением памятью, не слишком производительный. Но на нём даже клон Win95 написали. Очуметь!

Си, конечно, вариант. Но «обобщённый» ассемблер был бы лучшим решением. LLVM конечно хороша, но лучше иметь отечественный инструмент.

байки о совместимости и переносимости — это просто байки.

Худо-бедно, но есть кроссплатформенные JVM, LLVM, Qt. Есть Wine под Linux. Не всё гладко, но нерешённых проблем не много (в процентах), многие о них даже не знают. Кроссплатформенность серьёзно уменьшает время и затраты на разработку. Конечно, ценой некоторой потери эффективности. Был проект Эпсилон в СССР, генерация кода через него приводила к потере производительности на 20%. Но даже в советское время на это шли, несмотря на дефицит вычислительных мощностей.

язык ассемблера должен наглядно описывать команды и структуры машинного языка.

Современные архитектуры процессоров сильно похожи друг на друга. Найти «наибольший общий делитель» будет нетрудно.

     2022/11/29 14:35, Gudleifr          # 

Худо-бедно, но есть кроссплатформенные JVM, LLVM, Qt. Есть Wine под Linux. Не всё гладко, но нерешённых проблем не много (в процентах)

А геном человека отличается от генома обезьяны на 1%. Суть проблемы совместимости в том, что ВЕСЬ что-то делающий код непереносим. Мы умеем рисовать одинаковые серые окошки на всех платформах? А какой мне прок в программе, рисующей окошки на экране 2000*1000 десктопа, на моем карманном Win CE с разрешением 320*200? С другой стороны, какой мне прок от совместимости реализаций игры X-Com для любых компьютеров? Ведь, хочется описания логики игры в терминах, позволяющих не просто запускать игру, а использовать её отдельные модули, добавлять и убавлять.

Современные архитектуры процессоров сильно похожи друг на друга. Найти «наибольший общий делитель» будет нетрудно.

Но не нужно. ЯВУ с этим худо-бедно справляются. Ну, нет в Си способов работы с портами, сегментной памятью и аппаратными прерываниями. Кого это когда напрягало?

     2022/11/29 20:52, MihalNik          # 

Есть в сети место сосредоточения любителей ассемблера — форум ОС «Колибри». Русификация ассемблера не то, чтобы вызвала маленький интерес. Он оказался вообще нулевым.

Любители ассемблера — знают ассемблер и по определению любят его. Но ОС — это совсем другое дело. Это как на форум автолюбителей прийти обсудить удобное велосипедное седло.

     2022/11/29 22:59, Автор сайта          # 

А геном человека отличается от генома обезьяны на 1%.

Будь Вы творцом вселенной, то нашли бы выгодным повторное использование 99% кода. Творцы — они такие, рутину не любят, им только новые и интересные задачи подавай. А тут ещё дедлайн, надо за 7 дней успеть. А за счёт гибкой методики управился за 6, а седьмой отдыхал.

А какой мне прок в программе, рисующей окошки на экране 2000*1000 десктопа, на моем карманном Win CE с разрешением 320*200?

Когда-нибудь придём к масштабируемому интерфейсу пользователя. Но даже если интерфейс пользователя нужно разрабатывать всякий раз с нуля, то на остальном можно же немало сэкономить? Работа с файлами, базами данных, сетью — в чём там может быть принципиальная разница?

Но ОС — это совсем другое дело

В том то и дело, что не другое. «Колибри» написана на ассемблере, на форуме общаются её разработчики, они же программисты на ассемблере.

     2022/11/29 23:02, MihalNik          # 

В том то и дело, что не другое. «Колибри» написана на ассемблере, на форуме общаются её разработчики, они же программисты на ассемблере.

Именно. Колибри ОС написана другим ассемблером.

     2022/11/30 00:15, Gudleifr          # 

А за счёт гибкой методики управился за 6, а седьмой отдыхал

Не получается. Соблюдение "правил совместимости" весит, минимум, 90% кода. Возьмите любой код любой современной библиотеки и посчитайте сколько кода уходит на шаблонирование универсальных типов, ловушки маловероятных ошибок, замкнутость кольца операций... И сколько в этом коде ошибок.

Работа с файлами...

Тоже самое. Попробуйте, например, совместить NIX'-овские файлы с WIN-файлами-оверлеями без потери 90% производительности.

     2022/11/30 01:06, Бурановский дедушка          # 

Apple много раз перепрыгивала с одного процессора на другой. Сперва Motorola, потом PowerPC, потом Intel, и вот теперь ARM. Миллионы пользователей переходили. Значит, была хорошая совместимость. Apple, между прочим, один из спонсоров LLVM.

Читал описание команд ARM — очень похоже на Intel. Разница куда меньше, чем с IBM/360/370 или Электроника Д3-28/Wang 720C. Наверное, трудности, связанные с разницей в архитектурах, не настолько велики, что Clang выдаёт такой хороший бинарный код. И для Intel, и для ARM.

     2022/11/30 12:05, Gudleifr          # 

Apple много раз перепрыгивала с одного процессора на другой

Т.е. переписывала свои ОС заново. Сохраняя внешние интерфейсы практически без изменений. Это и есть единственная возможная "совместимость" — совершенно разные программы, работающие почти одинаково.

     2022/12/01 12:53, Автор сайта          # 

Колибри ОС написана другим ассемблером

Пишут на Fasm. Моя разработка делала преобразование своего собственного синтаксиса в синтаксис Intel. То есть в синтаксис Masm и Fasm. Но это, повторюсь, никого не заинтересовало.

Но меня легко убедить в обратном, то есть в нужности русского ассемблера: достаточно его написать и сделать широко используемым.

     2022/12/01 18:26, Бурановский дедушка          # 

Т.е. переписывала свои ОС заново

Переписывали с нуля один раз, когда переходили на PowerPC. В остальных случаях просто допиливали по мелочам.

     2022/12/01 18:29, Gudleifr          # 

В остальных случаях просто допиливали по мелочам

Допиливание обычно весит больше переписывания заново.

     2022/12/01 21:01, void          # 

В советское время тоже были проекты «универсального ассемблера»: языки АЛМО, Сигма, Эпсилон и другие. Возможно, там что-то можно найти что-то интересное.

Ещё, как вариант: языки Эль-76, проекты Самсон, Кронос. Эль-76: русскоязычный микрокод, высокоуровневый язык динамически типизированный, вроде Оберона. Модули там, кажется, реализованы через замыкания.

Самсон А. Терехова: на Алголе высокоуровневый ассемблер, высокоуровневый микрокод.

Кронос и далее Мифрил, XDS А.Недори. Проект Кронос: клон Юникса на Модуле-2. Модула-2 как высокоуровневый микрокод или ассемблер.

Самсон и Кронос — реализации своей аппаратной архитектуры на языке высокого уровня (Алгол и Модула соответственно). XDS: двух- (а потом, и трёх-) язычный компилятор Модула-2/Оберон-2/Си, для оптимизации используется представление SSA, как в LLVM.

QBE: https://c9x.me/compile/ — бэкенд компилятор на Си, использующий SSA-представление. Более простой, чем LLVM. Есть реализации простых компиляторов с кодогенерацией через QBE из SSA, SCC: https://github.com/8l/scc, qc: https://github.com/andrewchambers/qc, Myrddin: https://myrlang.org/, https://github.com/8l/mc, https://myrlang.org/retrospective SCC поддерживает QBE среди прочих бэкендов, QC написан на Myrrdin и QBE, Myrrdin в последних версиях переходит на QBE.

Myrrdin — функциональный язык программирования, нечто среднее между Ocaml, Rust и Haskell.

В качестве языка программирования с простым компилятором и кодогенератором, можно также посмотреть Cowgol: https://cowlark.com/cowgol/ и прочие языки этого автора: https://cowlark.com/index/blog.html

P.S. Не могу найти у себя переписку с одним разработчиком, который рассказывал, как они мучались с русским ассемблером под какую-то отечественную систему команд отечественной архитектуры. И как они вздохнули, когда ассемблер был переделан на английские абревиатуры команд. На это только и ответил, что ассемблеры, по-видимому, делятся не только на русские и нерусские, но и на хорошие и плохие. Так что не всё так однозначно.

Кажется, в ЭВМ "Наири" микрокод (автокод) и далее ассемблер был даже армянским, а не русским.

Конечно, не все согласятся, что это лучший вариант замены, укажут на субъективность вкусов. Но под каждой заменой есть аргументированное обоснование. Впрочем, в этом проекте есть возможность полностью сменить синтаксис на свой собственный вариант. С одной стороны, это гибко. С другой — отсутствие стандарта всё же не есть хорошо.

Мне кажется, эту тему нужно разделить на две:
  • высокоуровневый ассемблер (или достаточно высокоуровневый язык в качестве микрокода, автокода, ассемблера наподобие PL/S, PL360)
  • русскоязычный ассемблер

Высокоуровневый ассемблер

Здесь в качестве примеров такого языка и компьютерных архитектур кроме достаточно общеизвестных Эль-76, Самсон/Алгол, Кронос/Модула-2, Лилит/Модула-2, Ceres/Oberon можно привести исторические:
  • AlgolW на PL360 и соответственно PL360, Euler;
  • проект MULTICS, где PL/1 использовался в качестве системного языка вместо ассемблера;
  • проект OS/360, где в том же качестве использовался собственный диалект PL/S;
  • проект CP/M, где в том же качестве использовался PL/M.
  • HLA = High Level Assembly by Randall Hyde и книга "Art Of Assembly" про 64-битный ассемблер, судя по форуму автора — книга пишется сейчас.
  • https://artofasm.randallhyde.com/ про 32-битный ассемблер и собственно HLA — книга, компилятор HLA в ассемблер и исходники есть на
    https://www.randallhyde.com/AssemblyLanguage/www.artofasm.com/index.html
    HLA — это буквально "высокоуровневый ассемблер"под x86-32, с синтаксисом вроде Паскаля, с семантикой С++ (есть аналоги STL, ООП GUI-библиотека, классы и исключения).
  • Есть довольно высокоуровневый язык макросов через функции времени компиляции, СTFE Compile-Time Function Execution. Шаблоны и ООП-система реализованы через такие макросы. Но всё-таки это ассемблер: команды ассемблера синтаксически записываются как вызов функций наподобие mov(ax,bx); но вычисление выражений показывает всю низкоуровневость языка, простой калькулятор выражений фактически не реализован.

    На мой взгляд, высокоуровневость языка определяется именно способом типизации выражений, а вовсе не синтаксисом. То есть высокоуровневым можно назвать тот язык, который "абстрагирует от несущественного" (например, синтаксиса). То есть в котором при вычислении выражения все элементарные значения и их элементарные типы являются first-class objects, как например в языке Kernel диалекте Схемы с семантикой vau-expressions, от автора John Schutt. Всё остальное, например синтаксис языка, — дело наживное, если у вас достаточно развитый макроязык. Например, возьмём в качестве такого языка-носителя для реализации более высокоуровневого языка-гостя язык Форт. Компилирующие слова Форта могут использоваться для реализации синтаксических макросов. Есть реализации ассемблера x86-32 на стандартном переносимом Форте.
  • Есть реализации простых компиляторов, вроде перевода "Let's Build a Compiler" by Jack Crenshaw https://compilers.iecc.com/crenshaw/ про реализацию простого компилятора Паскаля на Паскале и его более поздний сиквел http://home.iae.nl/users/mhx/crenshaw/tiny.html про реализацию компилятора Паскаля на Форте. Вторая реализация на Форте, на мой взгляд, стала ещё проще и нагляднее, а не просто компактнее.
  • На сайте Taygeta есть Forth Scientific Library: https://www.taygeta.com/fsl/scilib.html Среди прочих численных методов там реализован парсер выражений и их трансляция в стандартный Форт. То есть Форт с такой библиотекой используется по сути как Фортран.
  • Форт можно использовать как переносимый ассемблер: https://github.com/rigidus/rigidus.ru/blob/master/org/doc/paf.org Форт получается даже гибче чем Фортран и ассемблер:
    1) синтаксис можно изменять
    2) можно встраивать куски кода на любом языке: высокоуровневом, низкоуровневом или Форте
    3) можно компилировать/ассемблировать/дизассемблировать отдельные слова и динамически смотреть, что получается (то есть, использовать Форт в качестве PL/1 монитора, например).
  • Компиляторный тулчейн PL/I-KT Дмитрия Караваева, кстати, в этом смысле тоже довольно интересный. Основная заслуга — гибкость расширения, заложенную первоначальной архитектурой, — принадлежит автору тулчейна Гари Килдэллу, автору CP/M, PL/M и этого компилятора PL/1 под CP/M, DOS и DR DOS. В тулчейне есть собственно компилятор, линкер и библиотекарь OMF формата и ассемблер RASM. Ассемблер реализован достаточно гибко и расширяемо. Настолько гибко, что это позволило Дмитрию Караваеву относительно просто портировать его на x86-64. Что делает этот тулчейн вполне самодостаточным. Впрочем, Дмитрий Караваев и сам довольно сильно переработал исходный компилятор: поддержка русского языка, физических размерностей, портирование под Win64, подключение стандартных C библиотек Windows, например DirectX.

    Хотя OMF формат удалось приспособить для поддержки 64-битного кода, я подозреваю, что дальнейшее развитие компилятора и тулчейна ограничено именно старым линкером. Например, в языке D Волтера Брайта и его изначальном компиляторном тулчейне DMD = Digital Mars D использовался линкер OPTILINK, точно так же как и в Zortech C++ / Symantec C++ / Digital Mars C++. В дальнейшем это привело к ряду проблем. Например, во время D v1.0 был 3D-движок, написанный на CTFE конструкциях языка D. Так там некоторые примеры не компилировались — происходило переполнение системных таблиц, и напрямую упирались в ограничения формата OMF и старого линкера OPTILINK.

    В PL/I-KT, возможно, ровно такие же проблемы могут возникнуть при достаточно больших программах (впрочем, без метапрограммирования в стиле CTFE этого достигнуть значительно сложнее). Если уважаемый Дмитрий Караваев когда-нибудь соберётся делать порт PL/I-KT под Linux, например, то линкер придётся довольно значительно переписывать для кодогенерации ELF формата exe и .so библиотек. Впрочем, возможно это будет всё-таки проще, чем использовать монстров вроде GCC или LLVM.

     2022/12/01 21:02, void          # 

Вообще интересно, а насколько сложно например на PL/I-KT программировать под EFI? Вот тут https://wiki.osdev.org/UEFI_App_Bare_Bones, например, находятся примеры программирования ядра операционной системы "на голом железе", непосредственно под UEFI (современный аналог BIOS). На языке Си. Также здесь https://www.rodsbooks.com/efi-programming/hello.html и здесь https://github.com/no92/uefi-bare-bones. Непосредственно на ассемблере не сильно сложнее: https://johv.dk/blog/bare-metal-assembly-tutorial

На Форте тоже не очень сложно: https://github.com/c2d7fa/jonasforth
https://github.com/iwilare/monoid-forth
https://compilercrim.es/bootstrap/miniforth/

Кстати, вот рацпредложение уважаемому Дмитрию Караваеву: написать пробный макетный helloworld под UEFI на PL-I/KT и по необходимости минималистично доработать компилятор и тулчейн, чтобы этот пример можно было запустить. Мне кажется, на PL/I вполне можно разрабатывать целые операционные системы bare bones — непосредственно "на голом железе".

UEFI здесь кажется как разумный кандидат на замену BIOS, основная сложность — в доработке линкера и реализации поддержки готовых библиотек вроде GNU-EFI или TianoCore. Как пример, можно обойтись вообще без Си уровня (портировать на Pl/I, пример: https://johv.dk/blog/bare-metal-assembly-tutorial).

     2022/12/01 21:04, void          # 

Впрочем, на Лиспе тоже может быть не сильно сложнее. Есть, например, реализация ассемблера встраиваемого в Схему: https://sassy.sourceforge.net/, но там ассемблер всё ещё 32-битный (или даже 16-битный, для бутсектора).

Гораздо интереснее выглядят проекты Chris Hinsley : Elate OS / intent / AmigaDE / TaoOS и его современный форк CrysaLisp. Cris Hinsley был программистом на ассемблере, автором культовых игрушек середины 80-х: AutoMania, Pyjamarama, прочих https://viva-games.ru/game/automania, https://viva-games.ru/avtor/chris-hinsley. Особенностью этих игрушек было то, что они выходили под несколько платформ сразу.

Крис Хинсли программировал их в своём особенном стиле, фактически — на переносимом ассемблере. В дальнейшем эта идея, регистровой виртуальной машины как виртуального процессора, кроссплатформенного переносимого ассемблера — выкристализовалась в ElateOS / intent / AmigaDE и далее в CrysaLisp.

Виртуальный процессор описан здесь: https://en.wikipedia.org/wiki/Virtual_Processor, там же есть ссылки на журналы, публикации и интервью. Github Avatar: Chris Hinsley

Inventor of the Taos OS.
http://www.uruk.org/emu/Taos.html https://en.wikipedia.org/wiki/Virtual_Processor

Например, довольно содержательное интервью было на OSnews:
https://www.osnews.com/story/157/tao-group-on-elateos-amigade-and-more/
с картинками в вебархиве
https://web.archive.org/web/20110804222848/https://www.osnews.com/story/157/tao-group-on-elateos-amigade-and-more/

Вот, например как выглядит этот "виртуальный ассемблер":
https://web.archive.org/web/20150815172946/http://www.osnews.com/img/vp.jpg. Видно, что язык довольно высокоуровневый, наподобие HLA.

А декомпозиция на tools более компактна, чем объекты или библиотеки — скорее напоминает микросервисы. Впрочем, далее на основе этой идеи был реализован CrysaLisp: https://github.com/vygr/ChrysaLisp и поддерживающие библиотеки: https://github.com/vygr/ChrysaLib — это реализация операционной системы, основанной на идеях ElateOS/intent/AmigaDE Virtual Processor, Лисп-машин и распараллеливания в духе Occam и транспьютеров.

Как вы можете видеть в репозитории проекта на Гитхабе реализовано довольно много, при этом есть 3D графика и мультимедия. Весь этот 3D рендеринг при необходимости может работать как распределённая операционная система в духе Plan9 ANTS или Occam, на нескольких узлах одновременно. Накладные расходы на реализацию "виртуальной машины" этого виртуального процессора — ничтожны. См. более подробные сравнения и бенчмарки непосредственно в репозитории.

Во времена ElateOS/intent/AmigaDE на таком виртуальном процессоре в AmigaDE SDK был реализован компилятор языка С, POSIX совместимый. Фирма Криса Хинсли TaoGroup https://en.wikipedia.org/wiki/Tao_Group и её продукты. Впрочем, и сейчас на чём-то вроде QBE, HLA, CrysaLisp, Форт, Лисп, Схема — должно быть реализовать эти идеи не сильно сложнее.

     2022/12/01 21:32, void          # 

Идея универсалього ассемблера или универсального промежуточного представления хороша тем, что поволит экономить на генерации кода под конкретную платформу.

Здесь возникает вопрос: а насколько хорошо оптимизировать код позволяет это самое универсальное промежуточное представление? Например, в компиляторе GCC есть несколько таких представлений: GIMPLE, TREE SSA, MELT
https://russianblogs.com/article/10021359206/
MELT https://gcc.gnu.org/wiki/MELT%20tutorial
https://gcc.gnu.org/wiki/MiddleEndLispTranslator — это фактически диалект Лиспа, реализованный как плагин для GCC.

В LLVM и QBE (а также компиляторе А. Недори) используется представление SSA. В первую очередь из-за того, что оно удобно для оптимизации. При этом сам язык промежуточного представления "высокоуровневый ассемблер" во всех этих трёх реализациях — разный. Возможно, что LLVM intrinsincs не самый простой и понятный способ расширения реализации. LLVM представляет собой тот самый Virtual Processor, с бесконечным количеством регистров или регистровых переменных, с phi функцией выбора блоков.

В этом смысле эта виртуальная машина времени компиляции похожа на другие регистровые виртуальные машины "виртуального процессора", такие как Dis из Inferno, Dalvik из Android (являющийся по сути клоном Dis в новой упаковке, использующий в качестве более наглядного синтаксического сахара не Limbo/Go/Plan9 C,Squeak,Alef — а попсовый Java синтаксис) или ту же самую ElateOS/intent/AmigaDE/CrysaLisp.

Ещё есть C--, даже два. Один — упрощённый Си, современный форк поддерживает Win32/Win64. Второй используется в реализации компилятора GHC языка Haskell. Этот второй тоже напоминает эдакий достаточно низкроуровневый ассемблер некоторого "виртуальный процессора".

Другой вариант — наоборот, сделать язык реализации промежуточного представления достаточно высокоуровневым. Но в общем случае непонятно, насколько это будет выгодно для эффективной оптимизации.

     2022/12/03 14:24, kt          # 

На мой субъективный взгляд никакого «языка ассемблера» вообще не существует. Есть ряд правил записи команд процессора в текстовом виде и все. И если вы знаете команды, запомнить несколько правил их записи не представляет труда.

Помнится, я начинал с того, что раздобыл книжку с системой команд БЭСМ-6 (тогда она нигде не продавалась) и пару месяцев её изучал, будучи полным нулем в этой области. Все переписывал в тетрадку, чтобы лучше запоминалось. Потом решил изучать Автокод БЭСМ-6 и завел новую тетрадь. Но оказалось, что достаточно одной странички и часа времени.

Поясню свою мысль на примере x86. Вот есть, например, команда
MOV EAX,10
Ее можно записать как
MOV EAX,X1+X2
где
X1 EQU 4
X2 EQU 6
Это может быть удобно, чтобы редактировать меняющиеся константы только в одном месте исходного текста. Так вот, язык ассемблера это жалкие X1+X2 вместо записи сразу 10, т.е. мелочь, а все остальное — определяется системой команд. Если вы знаете систему команд — вы автоматически знаете и ассемблер. И, на мой взгляд, «обобщенный ассемблер» — пустая затея, ступень, без которой можно обойтись.

Автору сайта

для генерации бинарного кода ассемблер не нужен

— нет нужен, иначе как проверять результаты работы транслятора. Неважно это ассемблер или дисассемблер: читать то все равно приходится команды в виде текста. Поэтому PL/1-KT действительно сразу генерирует двоичный код, но и сразу же дисассемблирует этот код в текст для разработчика. Даже есть режим, когда этот проверочный текст можно опять перевести в двоичные коды настоящим транслятором с ассемблера. Мы этот режим применяли для «ручной» оптимизации команд.

MihalNik'у

Кто нынче пишет на ассемблере?

Я пишу. Конечно, это немного жульническое заявление — у меня транслятор был изначально дисассемблирован, поэтому менять и сопровождать его приходилось на ассемблере. Но были у нас и отдельные проекты на ассемблере (все кроме ввода-вывода).

Это был транслятор с ПРОЛ-2 и программа автоматического обращения русско-немецкого технического словаря в немецко-русский. При грамотной организации разбивки на процедуры все получалось довольно быстро. Ну, и скорость рабты программ получалась подходящей. Поэтому, да ради бога, генерируйте в своих трансляторах код для любых LLVM. Только не называйте это ассемблером.

     2022/12/03 14:51, Gudleifr          # 

Просто оставлю это здесь.
https://gudleifr.forum2x2.ru/t116-topic#1898

     2022/12/03 22:25, Автор сайта          # 

На мой субъективный взгляд никакого «языка ассемблера» вообще не существует.

Язык — это совокупность алфавита, синтаксических и семантических правил. Если есть какое-то уникальное сочетание перечисленного, которое отличается от других, то это и есть язык. Значит язык ассемблера вполне себе существует. Более того, у системы команд x86 два основных ассемблера (синтаксиса), в Вашем ассемблере принят за стандарт синтаксис Intel. Есть ещё синтаксис AT&T. Эти синтаксисы отличаются порядком следования аргументов. В AT&T ещё указывается размер операндов.

Если вы знаете систему команд — вы автоматически знаете и ассемблер.

Да нет же. Ассемблеры могут отличаться синтаксисом (см. выше). А ещё в языке ассемблера есть макросы, зная систему команд, не имеешь автоматического знания языка макросов.

Дональд Кнут в своих трудах описывал алгоритмы на своём собственном выдуманном ассемблере. То есть системы команд у него не было, а язык ассемблера был :)

для генерации бинарного кода ассемблер не нужен

— нет нужен, иначе как проверять результаты работы транслятора. Неважно это ассемблер или дисассемблер: читать то все равно приходится команды в виде текста.

Ну так для этого вполне сгодится сторонний дизассемблер.

ради бога, генерируйте в своих трансляторах код для любых LLVM. Только не называйте это ассемблером.

Ну так я употреблял термин — «обобщённый ассемблер». Этот термин не я изобрёл, я термины изобретать не люблю. Наверно, близко по смыслу термину «машинно-ориентированный язык». Как бы груздь не назывался, лишь бы в кузов залезал. Просто языки ассемблера имеют характерный вид и поэтому что-то похожее тоже можно назвать ассемблером :) Тот же Форт больше похож на ассемблер, чем на что-то алголо-подобное.

     2022/12/03 22:30, Gudleifr          # 

Дональд Кнут в своих трудах описывал алгоритмы на своём собственном выдуманном ассемблере. То есть системы команд у него не было, а язык ассемблера был

Это неверно, сначала он описал гипотетическую машину MIX 1009.

«обобщённый ассемблер»... Наверно, близко по смыслу термину «машинно-ориентированный язык»

С точностью до наоборот.

     2022/12/03 23:10, Автор сайта          # 

Гипотетической была не только машина, но и команды были такие же. Какой двоичный код у команда «загрузить значение из памяти в регистр»? Какая длина у этой команды? У виртуальной машины JVM команды имеют такие характеристики, а у гипотетической MIX 1009 нет. У Кнута была умозрительная машина с такими же умозрительными регистрами, командами и языком ассемблера.

     2022/12/03 23:30, Gudleifr          # 

Какой двоичный код у команда «загрузить значение из памяти в регистр»? Какая длина у этой команды?

Коды — от 08 до 23. Длина — 5 "байтов" и знак.

     2022/12/04 09:05, kt          # 

Более того, у системы команд x86 два основных ассемблера (синтаксиса)

Не противоречит

если вы знаете команды, запомнить несколько правил их записи не представляет труда.

Ну так для этого вполне сгодится сторонний дизассемблер.

чтобы использовать дисассемблер все равно нужно знать команды — т.е. с моей точки зрения знать ассемблер

     2022/12/04 10:55, Автор сайта          # 

Gudleifr

Коды — от 08 до 23. Длина — 5 "байтов" и знак.

Не может быть! Там даже размер байта был приблизительный: «6 и более битов». А флаг результата сравнения представлял из себя не бит, а трит — один разряд в троичной системе счисления. Так что там всё было умозрительным, даже одновременное сочетание двоичной и троичной системы счисления.

Но мы отклонились от темы, да и обсуждение превращается в спор «кто кого».

kt

чтобы использовать дисассемблер все равно нужно знать команды — т.е. с моей точки зрения знать ассемблер

Так ведь вопрос так и не ставился — знать язык ассемблера и машинные коды или не знать. Говорилось о том, что можно напрямую генерировать машинные коды, а не текст на языке ассемблера, чтобы потом полученный текст скормить самому ассемблеру и получить двоичный код. С этой точки зрения транслятор ассемблера не является необходимым, чтобы получить двоичный код из программы на ЯВУ.

void

Кажется, в ЭВМ "Наири" микрокод (автокод) и далее ассемблер был даже армянским, а не русским.

Нет, именно были именно русские аббревиатуры.

На мой вгзляд, высокоуровневость языка определяется именно способом типизации выражений, а вовсе не синтаксисом. То есть высокоуровневым можно назвать тот язык, который "абстрагирует от несущественного" (например, синтаксиса). То есть в котором при вычислении выражения все элементарные значения и их элементарные типы являются first-class objects

А на мой взгляд высокоуровневость определяется полиморфизмом, степенью повторного использования кода. Описал, к примеру, новый тип данных с присущими ему операциями — и объекты этого типа сразу могут быть элементами коллекций, в том числе упорядоченных коллекций. Если для этого типа данных определена операция сравнения «<=», то данные этого типа можно сортировать. Способ же типизации лишь определяет, на каком этапе станет известен тип объекта — на этапе компиляции или же исполнения. «Несущественными деталями» можно считать регистры, флаги. Но при генерации кода эти детали становятся существенными. Можно сделать управление памятью автоматическим и посчитать это повышением уровня языка, так как скрыли ещё одну деталь. Но в некоторых случаях это равносильно одеванию смирительной рубашки: руки теперь связаны.

А вот насчёт first-class objects возражений нет.

Хотя OMF формат удалось приспособить для поддержки 64-битного кода, я подозреваю, что дальнейшее развитие компилятора и тулчейна ограничено именно старым линкером.

В PL/I-KT, возможно, ровно такие же проблемы могут возникнуть при достаточно больших программах (впрочем, без метапрограммирования в стиле CTFE этого достигнуть значительно сложнее). Если уважаемый Дмитрий Караваев когда-нибудь соберётся делать порт PL/I-KT под Linux, например, то линкер придётся довольно значительно переписывать для кодогенерации ELF формата exe и .so библиотек.

Лучше всего, если это прокомментирует Дмитрий Юрьевич.

Идея универсалього ассемблера или универсального промежуточного представления хороша тем, что поволит экономить на генерации кода под конкретную платформу.

Здесь возникает вопрос: а насколько хорошо оптимизировать код позволяет это самое универсальное промежуточное представление?

При использовании Эпсилон потери были приблизительно 20%.

В LLVM и QBE (а также компиляторе А. Недори) используется представление SSA.

Алексей Недоря на днях анонсировал свой язык, можно будет поинтересоваться, будет ли там использовано представление SSA. Ведь он собрался делать кроссплатформенную экосистему.

     2022/12/04 12:37, Gudleifr          # 

Идея универсалього ассемблера или универсального промежуточного представления хороша тем, что позволит

... попил бабла на том, что очень легко сделать. Причем, этот попил будет повторяться для каждой реальной машины. А все расходы по переводу ЯВУ в убогое промежуточное представление понесет пользователь.

     2022/12/04 13:22, kt          # 

когда-нибудь соберётся делать порт PL/I-KT под Linux, например, то линкер придётся довольно значительно переписывать для кодогенерации ELF формата exe и .so библиотек.

Как раз этот этап видится простым и упирается пока в отсутствие рабочего места с требуемой версией linux (т.е. жду, пока мне такое место не поднесут на блюдечке). Дело в том, что был этап с 1995 по 2003, когда работали под ДОС, но уже в 32 разрядном режиме. И в 2004 появился дополнительный модуль WPE (т.е. Windows PE), который после Link брал старый EXE (с 32-х разрядными командами) и преобразовывал его в PE-формат. Это несложно, поскольку коды уже по сути готовы. Для Linux потребуется отдельный модуль ELF, который из нашего EXE сделает ELF. PE и ELF — одного класса форматы, по возможностям очень похожи. Таким образом, Link вообще не дорабатывается. Правда, есть одна заморочка в LINK — объем кодов команд не должен превышать 16 Мбайт в файле. Но, учитывая, что наша основная программа за 30 лет развития не превысила 1,5 Мбайта команд, это не сильное ограничение. Переход с 32 на 64 потребовал незначительной доработки модуля WPE и существенной доработки компилятора и ассемблера.

написать пробный макетный helloworld под UEFI на PL-I/KT и по необходимости минималистично доработать компилятор и тулчейн, чтобы этот пример можно было запустить.

Увы, на исследовательские вещи совершенно нет времени сейчас. Как говорится "не до грибов". Мы не успеваем справляться с задачами по текущим работам, в том числе, исправлять ошибки компилятора. Например, на прошлой недели один из пользователей написал оператор вывода, число форматов в котором превысило 255, и компилятор позорно рухнул.

Мне кажется, на PL/I вполне можно разрабатывать целые операционные системы bare bones — непосредственно "на голом железе".

Мне тоже кажется, что это возможно, учитывая, например, что есть особенность генерации произвольных кодов. В программе на PL/1 пишешь, например, UNSPEC('E688'b4); и это означает в x86 команду обращения к порту 88: OUT 88H,AL

     2022/12/04 13:33, Gudleifr          # 

Мне кажется, на PL/I вполне можно разрабатывать целые операционные системы bare bones — непосредственно "на голом железе"

Нет, в силу неудобоваримости решения на нем двух "ассемблерных" (или же ОС-писательных) вопросов:

... язык ассемблера должен наглядно описывать команды и структуры машинного языка...
... язык ассемблера должен быть способным создавать наглядные описания интерфейсов к используемым ОС.

     2022/12/04 21:47, Автор сайта          # 

Мы не успеваем ... исправлять ошибки компилятора. Например, на прошлой недели один из пользователей написал оператор вывода, число форматов в котором превысило 255, и компилятор позорно рухнул.

Сочувствую. Представляю Вашу досаду. Но раз не стесняетесь признавать ошибки, значит уверены в себе.

     2022/12/05 09:35, kt          # 

При этом пользователь заявил, что просмотрел всю таблицу ошибок при компиляции и такой не нашел. И действительно есть небольшая проблема отличия ошибок при компиляции от ошибок самого компилятора))

     2022/12/06 02:13, void          # 

А на мой взгляд высокоуровневость определяется полиморфизмом, степенью повторного использования кода. Описал, к примеру, новый тип данных с присущими ему операциями — и объекты этого типа сразу могут быть элементами коллекций, в том числе упорядоченных коллекций. Если для этого типа данных определена операция сравнения «<=», то данные этого типа можно сортировать. Способ же типизации лишь определяет, на каком этапе станет известен тип объекта — на этапе компиляции или же исполнения. «Несущественными деталями» можно считать регистры, флаги. Но при генерации кода эти детали становятся существенными. Можно сделать управление памятью автоматическим и посчитать это повышением уровня языка, так как скрыли ещё одну деталь. Но в некоторых случаях это равносильно одеванию смирительной рубашки: руки теперь связаны.

Например, если взять условный псевдокод
фыва<-X1+X2
Здесь, если фыва — не название регистра, а переменная то получится две инструкции
MOV RAX,z; MOV [фыва],RAX
К тому же, нужно догадаться какого размера переменные и промежуточный регистр. Если
z := X1+X2
— не переменная, а константа, которую можно посчитать во время компиляции, то есть X1 и X2 — статически типизированы и z соответственно тоже, и их типы можно целиком посчитать во время компиляции. С другой стороны,
y := X1+W
где W — переменная динамического типа (например, объект с полиморфизмом) — этот y нельзя посчитать статически, y будет динамического типа. К тому же, здесь + тоже будет по сути полиморфным вызовом метода "+". Типы этой numeric tower не обязательно образуют иерархию, так что полиморфизм там несколько сложнее. Ближе к полиморфизму высшего порядка в каком-нибудь Хаскеле (с нормальной системой типов времени компиляции).

Смысл нормальной высокоуровневой системы типов, с нормальным полиморфизмом времени компиляции — в том, чтобы догадаться можно было в идеале, именно во время компиляции, то есть CTFE — а не динамически во время выполнения.

«Несущественными деталями» можно считать регистры, флаги. Но при генерации кода эти детали становятся существенными. Можно сделать управление памятью автоматическим и посчитать это повышением уровня языка, так как скрыли ещё одну деталь. Но в некоторых случаях это равносильно одеванию смирительной рубашки: руки теперь связаны.

Чем же отличается "высокоуровневый" и "низкоуровневый" язык (или представления)? Чтобы сгенерировать эффективный код, нужно знать:
  • размер
  • статическая или динамическая типизация
  • полиморфизм времени компиляции или времени выполнения
Синтаксис не так важен, но может помочь подсказать эти моменты.

Язык — это совокупность алфавита, синтаксических и семантических правил. Если есть какое-то уникальное сочетание перечисленного, которое отличается от других, то это и есть язык. Значит язык ассемблера вполне себе существует. Более того, у системы команд x86 два основных ассемблера (синтаксиса), в Вашем ассемблере принят за стандарт синтаксис Intel. Есть ещё синтаксис AT&T. Эти синтаксисы отличаются порядком следования аргументов. В AT&T ещё указывается размер операндов.

Не знаю насколько справедлива байка о том, что AT&T синтаксис получился как хак предварительной оптимизации. Потому что Брайан Керниган написал ассемблер на AWK, и этот синтаксический шум ($123 или %reg или просто 123) использовался для упрощения написания ассемблера (и однопроходной генерации).

Сейчас быстро находится только такая вот реализация ассемблера на AWK:https://doc.cat-v.org/henry_spencer/amazing_awk_assembler/ "Amazing AWK assembler" by Henry Spencer.

"aaa" (the Amazing Awk Assembler) is a primitive assembler written entirely in awk and sed. It was done for fun, to establish whether it was possible. It is; it works. It's quite slow, the input syntax is eccentric and rather restricted, and error-checking is virtually nonexistent, but it does work.

По слухам, у Брайана Кернигана было тоже самое. Потом эта предварительная оптимизация, которая корень всего зла — отразилась в синтаксисе ($123 или %reg или просто 123)

Вообще любопытно, откуда возникают такие мифы и анекдоты. Например, "Unix Way" про то, что "лучше делать много простых программ, связанных простыми текстовыми интерфейсами через пайпы — чем монолитные непрозрачные комбайны". Мне кажется, это напрямую взялось из troff. Если посмотреть на структуру "офисного пакета" :))) troff для генерации PS/PDF/и прочих форматов электронной бумаги, то здесь мы видим отдельными утилитами: grap, pic, tbl, ну и "compiler driver" их запускающий — собственно troff.

Потом этот подход напрямую перекочевал в структуру компилятора gcc: gcc как запускалка — "compiler driver" для выбора нужной реализации через machine triplet, к тому же для разных языков может быть разная реализация. Потом выясняется что неявно gcc рассчитывает, что в системе будет "дешевый" запуск новых процессов, например, через fork и copy-on-write.

И реализация отдельными утилитами, связанными через пайпы в отличие от своего велосипеда"компилятор как библиотека" в том же Watcom/OpenWatcom всё-таки хуже — сложнее переносима.

Да нет же. Ассемблеры могут отличаться синтаксисом (см. выше). А ещё в языке ассемблера есть макросы, зная систему команд, не имеешь автоматического знания языка макросов.

и язык макросов может быть либо примитивным, подставляя лексемы как текст — и не имея никакой информации о типизации макросов, или более полноценным (и тогда вопрос, а почему бы для него, языка макросов, и не брать сразу нормально типизированный высокоуровневый язык?) Вообще, два отдельных вопроса здесь — необходимая (и достаточная) гибкость языков, и необходимая гибкость тулчейна для их реализации.

По сути, одно из преимуществ линкера ld/gold в gcc тулчейне — это возможность задавать свои "linker scripts". На OSdev много примеров где это используется для разработки ядра ОС, а вот ещё один полезный пример. Например, "actually portable executables" by Justine Tunney : http://justine.lol/ape.html. Написаны вообще в полиглотном стиле — это quine многоязычная программа, составленная из нескольких языков (подобранных так, чтобы "запускалось везде").

Что здесь реализует ape.lds https://github.com/jart/cosmopolitan/blob/master/ape/ape.lds? Скрипты линкера. Если не считать комментариев, язык скриптов линкера активно использует макросы в духе Си и различные секции исполняемого файла (написанные в универсальном, полиглотном стиле под несколько операционных систем сразу).

В итоге вот — имеем любопытный хак, создающий технологию "воистину переносимых исполняемых файлов" — а не как в Яве: Write once, run debug and test everywhere. Не в последнюю очередь, такой хак стал возможным из-за гибкости языка "linker script" в ld/gold линкерах из GCC тулчейна.

Здесь возникает другой вопрос: а почему бы линкер, позволяющий эдакие скрипты линкера, языки расширения, не написать сразу на высокоуровневом языке (вроде Лиспа или Форта, ну или на худой конец — том же "actually portable" awk http://justine.lol/awk/)?

По ссылке отсюда https://www.plantation-productions.com/Webster/RollYourOwn/index.html на книгу P.D. Terry, новая версия на С++ https://web.archive.org/web/20051231233910/http://www.scifac.ru.ac.za/compilers/ или https://web.archive.org/web/20051118125547/http://www.scifac.ru.ac.za/cspt/compbook.htm. Там в главе 6 пишут ассемблер, а в приложении D — макроассемблер. Пишут на "компиляторе компиляторов" CoCo/R. Исходники на Модуле-2, на мой взгляд, более понятны и наглядны, чем на С++.

В книге "Linkers and Loaders" by John R. Levine https://freecomputerbooks.com/Linkers-and-Loaders.html, кстати, линкер пишут для наглядности вообще на Perl. А в книге "Assemblers And Loaders" by David Salomon https://www.davidsalomon.name/assem.advertis/AssemAd.html https://www.davidsalomon.name/assem.advertis/asl.pdf "высокоуровневым ассемблерам" посвящена отдельная глава: 6.1 High-Level Assemblers. Пример кода на PL360:

A program written in PL360 superficially resembles an Algol 60 program. It consists of statements, not instructions. It has the same control structures and block structure. Even variable declarations are very similar. However, on a closer look, 7one can easily see the common use of machine registers and of machine instructions. Some simple examples are shown in Fig. 6.1 below:

begin short integer z;		//A short integer is 16 bits (halfword)
array 1000 real quant,price; //Two arrays, 100 f-p values each.
integer n; //A 32-bit variable (fullword).
array 132 byte line; //An array of 132 bytes.
integer B syn line(R1); //B is another name for the element
//of array line pointed to by R1
long real x,y,h; //64-bit (doubleword) f.p. variables.
F0=quant(R1)*price(R1); //R1 is used as an index.
R9:=R8 and R7 shll 8 or R6; //Left to right execution (see below).
F23:=F67++h; //F23, F67 are pairs of f.p. registers,
//for operations on long reals.
if R0<10 then R1:=1 else SET(flags(2)); //The SET function is identical
//to the SET machine instruction.
while R1<0 do
begin
R0:=R0+1; F01:=F01*F01
end;
for R2:=R1 step 4 until R0 do
begin
F23:=quant(R2)*price(R2);
F01:=F01+F23;
end;
end;
Figure 6.1

Это всё-таки ассемблер, хоть и алгол высокоуровневый. Потому что для R (регистры), F(floats), и переменных — допустимы разные операции, то есть вычисление выражений всё ещё остаётся низкоуровневым, а не first class objects CTFE (макро|мета)языка. Кстати, там ещё интересна глава 6.3

     2022/12/06 02:21, void          # 

Кстати, там ещё интересна глава 6.3 про мета-ассемблеры:

6.3 Meta Assemblers

A Meta-Assembler (MA), sometimes also called a universal assembler, is an assembler that can assemble code for a number of different computers. A conventional assembler can only handle source and object code for one computer; it is dedicated to that computer. In contrast, a MA running on computer K may be able to assemble code for computers K,L,M and others. A MA is therefore also an example of a cross assembler.

There are two types of MAs, restricted and general; and there are two ways to design a MA, it can be generative or adaptive. A restricted MA can only assemble code for a limited number of computers, normally the members of a computer family. Information about the instruction sets is built into the MA so it only has to be given the name of a computer, followed by the source file. A general MA can, in principle, handle code for any computer. It does not have any instruction set built-in, and has to be handed over, with each source file, a complete description of the source & object instructions.

A generative MA (which can be either restricted or general) is given either the name of a computer or a description of an instruction set, and generates a dedicated assembler. That assembler is then run in the usual way, translating source files into object files.

An adaptive MA (again, restricted or general) is given either the name of a computer or a description of an instruction set, followed by a source file. It then assembles the source and generates an object file.

Это вообще отдельный разговор про то — насколько расширяемый макроязык должен быть у такого "универсального ассемблера". Но вот что по сути тут происходит — возникают сами собой несколько малых языков, недоязычков, макроязычков:
  • язык программирования
  • макросы в языке программирования — на уровне лексем либо более прозрачно расширяемой системы типов
  • ассемблер
  • макроассемблер
  • линкер
  • скрипты линкера — чуть не сказал, "макролинкера"
Возникает вопрос: а почему бы не придумать один, универсально расширяемый метаязык для всего компиляторного тулчейна? А не несколько разных, отдельных.

     2022/12/06 02:35, void          # 

FasmG из состава ассемблера FASM — кажется и есть такой метаассемблер: для нескольких архитектур, задаваемых разными синтаксисами. В поставке есть x86, z80, 6801, JVM bytecode, .NET CLR bytecode и прочие. Можно в духе книг P.D. Terry или Дональда Кнута про MIX — задать и свой собственный.

При этом как бы мы ни сочиняли макросы на строках, чтобы реализовать там полиморфизм высшего порядка в духе тайпклассов Хаскеля, GADT из ATS или функциональных объектов, всё равно придётся написать eval, то есть, интерпретатор собственного языка. Хотя и этот метаязык компилятора компиляторов отдельных ассемблеров довольно гибкий, всё же не полностью гибкий.

     2022/12/06 02:46, void          # 

Мне кажется, на PL/I вполне можно разрабатывать целые операционные системы bare bones — непосредственно "на голом железе"

Нет, в силу неудобоваримости решения на нем двух "ассемблерных" (или же ОС-писательных) вопросов:
... язык ассемблера должен наглядно описывать команды и структуры машинного языка...
... язык ассемблера должен быть способным создавать наглядные описания интерфейсов к используемым ОС.

Тем не менее, в MULTICS написали ядро ОС на PL/I. В OS/360 тоже с PL360 как-то справлялись, как и в CP/M с PL/M. Последовательно понижая "высокоуровневость" этого "высокоуровневого ассемблера". Исходники MULTICS были общедоступны на сайте MIT (по крайней мере, ранее). Откомменированы, с гиперссылками.

Фундаментальный недостаток, по первому беглому взгляду на них, состоялся в том, что уровень HAL (Hardware Abstraction Level) не был реализован вообще .Это не проблема PL/I или даже не проблема MULTICS как такового. Это проблема того, что из архитектур там было всего два мейнфрейма, и задачу переносимости как таковую даже поставить и осознать не успевали. Хотя из публикаций J.Corbato одной из причин реализации на PL/I заявляется именно переносимость, хотя там в принципе мог быть почти любой алголоподобный язык.

В дальнейшем, кстати, первоначальные разработчики одного мейнфрейма организовали мини-ЭВМ Nova. И для него написали какой-то свой форк Мультикса, более переносимый. Фундаментальным недостатком было впрочем то, что о переносимости никто тогда толком не думал. Хотя уже на PL/M в CP/M такой слой в виде BDOS и BIOS начинает появляться. Хотя ему конечно далеко до полноценного HAL в той же Windows NT.

     2022/12/06 03:00, void          # 

ConvergePL: https://convergepl.org/about.html — язык наподобие питона с механизмом даже не макросов, а мультистадийных вычислений в духе MetaML, Template Haskell: https://convergepl.org/documentation/2.0/ctmp/. CTMP = Compile-Time Meta-Programming. Здесь стараются сделать корректно компилируемые макросы. В макросистеме есть splicing, capturing, quasi-quoting, insertion. Немного другой набор операций, чем в обычной лисповой макросистеме (quote, unquote, splice).

В дальнейшем на этом реализуются модульные макросы, с гигиеной, лексической/динамической областями видимости, интерфейсом между интерпретатором и компилятором (CEI). Реализация здесь поверх мини интерпретатора Питона — но с той же целью можно было взять и компилируемый язык, например Nim (в котором есть свои AST макросы, и компиляция трансляцией через Си). Прямо с заглавной страницы: https://convergepl.org/about.html

Domain specific language implementation
There's only so much pre-caching of results one can do. Converge allows Domain Specific Languages (DSLs) of arbitrary syntaxes to be embedded into it. Wouldn't it be fun to see how the fib function would look in an idealised assembly language that abstracts away from the specifics of a real-world processor? Normally this would involve flex, yacc, head scratching, and an implementation so fragile that it only works under a full moon. In Converge, a simple layer atop CTMP means that a 10Kb DSL implementation makes it easy to define our own personal assembly language.

и далее идёт пример ARM-подобного ассемблера, довольно высокоуровневого:
https://github.com/ltratt/converge/tree/master/examples/dsls/wsi_asm

определили грамматику
https://github.com/ltratt/converge/blob/master/examples/dsls/wsi_asm/WSI_Asm.cv
потом использовали в ex1.cv..ex4.cv

     2022/12/06 14:13, Gudleifr          # 

Тем не менее, в MULTICS написали ядро ОС на PL/I

Ну, во-первых, не ядро. Ядро там — на языке ассемблера. Во-вторых, что может лучше свидетельствовать о бесперспективности подобного писания, чем этот пример?

     2022/12/06 22:35, Неслучайный читатель          # 

исправлять ошибки компилятора. Например, на прошлой недели один из пользователей написал оператор вывода, число форматов в котором превысило 255, и компилятор позорно рухнул.

Интересно, в какой версии эта ошибка появилась? В той, которую написал глава Digital Research? Или виноваты более поздние доработки?

     2022/12/07 19:45, void          # 

Тем не менее, в MULTICS написали ядро ОС на PL/I

Ну, во-первых, не ядро. Ядро там — на языке ассемблера. Во-вторых, что может лучше свидетельствовать о бесперспективности подобного писания, чем этот пример?

Нет, именно ядро на PL/I. Можете сами убедиться: сайт https://multicians.org/ , история проекта
https://multicians.org/history.html , статьи и публикации на https://multicians.org/papers.html. Первая же статья от авторов F. J. Corbató, V. A. Vyssotsky "Introduction and Overview of the Multics System" https://multicians.org/fjcc1.html, где пишут

Because the system must ultimately be comprehensive and able to adapt to unknown future requirements, its framework must be general, and capable of evolving with time. As brought out in the companion papers, this need for an evolutionary framework influences and contributes to much of the system design and is a major reason why most of the programming of the system will be done in the PL/I language. Because the PL/I language is largely machine-independent (e.g. data descriptions refer to logical items, not physical words), the system should also be. Specifically, it is hoped that future hardware improvements will not make system and user programs obsolete and that implementation of the entire system on other suitable computers will require only a moderate amount of additional programming.

то есть: это было сознательное решение, концепция: написать ОС на языке высокого уровня, например, PL/I. К описанию ядра также относится описание режима супервизора https://multicians.org/fjcc3.html "Structure of the Multics Supervisor", где уточняют:

All operating system data layouts for the initial implementation of 645 Multics will be compatible with data layouts used by PL/I, except where hardware constraints dictate otherwise. All modules of the initial implementation of the operating system will be written in PL/I, except where hardware constraints make it impossible to express the function of the module in the PL/I language. <...> Since the PL/I translator which will be used until mid-1966 generates inefficient object code, it is clear that 645 Multics in its first few months of existence will be inefficient. This penalty is being paid deliberately. After mid-1966, two courses of action will be available: upgrade the compiler to compile more efficient code, or recode selected modules by hand in machine language. We expect that both strategies will be employed, but we expect to place preponderant emphasis on upgrading the PL/I compiler; indeed, one subsequent version of PL/I is already being implemented, and a second is being designed.

то есть, что эта вторая часть на машинном коде должна быть как можно более минималистичной.

Далее нужно смотреть исходники: https://multicians.org/multics-source.html и индекс https://multicians.org/source-index.html или в Github репозиториях:
https://github.com/dancrossnyc/multics со снимком и по отдельным коммитам, полная история на https://gitlab.com/atsampson/multics-history-repo/-/tree/master/library_dir_dir/system_library_1 — как вам здесь https://gitlab.com/atsampson/multics-history-repo/-/commits/master — первый релиз от Nov 15, 1988 ?

Хотя это не вся история, с самого начала разработки: https://web.mit.edu/multics-history/#history

The plan for Multics was presented to the 1965 Fall Joint Computer Conference in a series of six papers. It was a joint project with M.I.T., General Electric, and Bell Labs. Bell Labs dropped out in 1969, and in 1970 GE's computer business, including Multics, was taken over by Honeywell (now Bull).

MIT's Multics research began in 1964, led by Professor Fernando J. Corbató at MIT Project MAC, which later became the MIT Laboratory for Computer Science (LCS) and then Computer Science And Artificial Intelligence Laboratory (CSAIL). Starting in 1969, Multics was provided as a campus-wide information service by the MIT Information Processing Services organization, serving thousands of academic and administrative users.

LCS research on Multics ended in the late 1970s, and Bull ended Multics development in 1985. MIT shut down its Multics service in 1988. The last Multics system was deactivated in 2000.

То есть: после исхода из этого мегапроекта Bell Labs авторы Юникс Брайан Керниган и Денис Ричи, писавшие там утилиты, например, для компилятора компиляторов, — и создали свою упрощённую поделку "Униплексированная" (а не мультиплексированная) система разделения времени, взяв вместо PL/I языки ассемблер, BCPL и B, Си, и утащив туда по пути некоторые концепции (например, кольца защиты, режим root супервизора, виртуальную память процессов), но ниасилив некоторые другие (нормальный мандатный доступ, ACL, файловые сегменты данных, например).

Откомментированные исходники и обзор по ним лежат также на
https://web.mit.edu/multics-history/ и далее на
http://web.mit.edu/multics-history/source/Multics_Internet_Server/Multics_sources.html
Симулятор, в котором Мультикс можно запустить напоиграться есть на
https://multicians.org/simulator.html
Подробности на https://multics-wiki.swenson.org/index.php/Getting_Started
В презентациях про "душу старой машины"
https://multicians.org/simulator.html => https://multicians.org/soul-of-an-old-machine.pdf и
https://multicians.org/dps8m-emulator-presentation-text.pdf
Автор симулятора DPS8/M, в частности, пишет:

создать симулятор тех мейнфреймов оказалось проще, чем пытаться выделить в этих исходниках переносимый уровень HAL (Hardware Abstraction Level)

Не то, чтобы это было невозможно "в принципе" — просто у автора эмулятора не хватило терпения портировать эти старые исходники, да и запустить "как есть" само по себе было более важной задачей. Проблема этих исходников в другом: что при разработке ориентировались на конкретное железо конкретных мейнфреймов. И поэтому уровень HAL не выделили вообще (хотя вполне могли бы). Потому что так далеко на перспективу о мобильности операционной системы за пределы архитектуры этих двух мейнфреймов и в сторону "переносимого ассемблера высокого уровня" — никто не думал.

     2022/12/07 19:56, void          # 

Вот тут история проекта MULTICS нарисована графически: https://multicians.org/history.html
Про общую структуру исходников: https://multicians.org/flass-organick.html
Про обоснование выбора PL/I в качестве системного языка для написания ОС и реализацию компилятора PL/I в MULTICS:
https://multicians.org/pl1.html и https://multicians.org/pl1-raf.html

     2022/12/07 19:59, Gudleifr          # 

Нет, именно ядро на PL/I.

Посмотрите исходники. Там все, что относится к ядру — на языке ассемблера.

     2022/12/07 20:05, void          # 

Emacs, например, там был написан на PL/I:
https://github.com/dancrossnyc/multics/blob/
dc291689edf955c660e57236da694630e2217151/library_dir_dir
/system_library_unbundled/source/bound_multics_emacs_.s.archive/emacs.pl1

Как по мне — так вот эти исторические сорцы на PL/I нагляднее, понятнее и лучше структурированы чем исходники современного GNU/Emacs на языке Си. Реализации встроенного в емакс лиспа и отдельного лиспа — тоже на PL/I.

     2022/12/07 20:08, void          # 

Посмотрите исходники. Там все, что относится к ядру — на языке ассемблера.

Куда именно смотреть, ткните пальцем в конкретную строчку репозитория. Загрузчик на PL/I, например. Опять же: то что такого уровня HAL не было в исходниках Мультикс изначального не означает что этот слой в принципе невозможно выделить (хотя автор симулятора DPS-8M, например, — ниасилил).

     2022/12/07 20:17, Gudleifr          # 

Emacs, например, там был написан на PL/I:

Emacs — это не ядро.

     2022/12/07 20:21, Gudleifr          # 

Куда именно смотреть, ткните пальцем в конкретную строчку репозитория

Я просто ввел MULTICS source code и выбрал первую строку. Далее смотрите на расширения файлов — pl1 или alm.

     2022/12/07 20:30, void          # 

Вот *.alm файлы — это похоже ассемблер. Вопрос об их назначении.

     2022/12/07 20:34, Gudleifr          # 

Вопрос об их назначении.

Дык, ядро же.

     2022/12/07 20:34, void          # 

В общем, надо брать мурзилку пошаговую https://multicians.org/sim-inst.html, устанавливать симулятор и пересобирать ядро, поглядывая в "Linux From Scratch" и BLFS и пытаясь найти аналогичные места. Нет, там в емаксе какие-то куски на alm про многозадачность и асинхронность были. Так что не везде ядро — надо отдельно разбираться, представляя всю последовательность загрузки, сборки и пересборки ядра и всех утилит системных.

Опять же, отдельный интересный вопрос: а насколько диалект языка PL/I поддерживаемый компилятором в MULTICS отличается от Subset G и возможностей PL-I/KT, например. Любопытно было бы как-то приблизительно оценить трудоёмкость портирования этих исторических сорцов под более современную реализацию PL/I.

     2022/12/07 20:47, Gudleifr          # 

В общем, надо брать мурзилку пошаговую

Зачем? Проще понять, почему это работает только для попила бабла на представление правдоподобно выглядящего макета. А причина проста: внутри у любого ЯВУ болтается "маленький хитрый кусок, завязанный на текущую ОС" и "большая смачная собственная ОС-надстройка/библиотека". При написании на ЯВУ оба эти фрагмента использовать невозможно, т.к. на момент загрузки ОС, последняя ещё не работоспособна. Поэтому придется либо пользоваться очень ограниченным подмножеством ЯВУ, либо писать для него костыли. Причем, по окончании работы окажется, что костыли удобнее стандартных процедур ЯВУ.

     2022/12/07 21:26, void          # 

Зачем?

ну например, из спортивно музейно-реконструкторского интереса.

Проще понять, почему это работает только для попила бабла на представление правдоподобно выглядящего макета. А причина проста: внутри у любого ЯВУ болтается "маленький хитрый кусок, завязанный на текущую ОС" и "большая смачная собственная ОС-надстройка/библиотека". При написании на ЯВУ оба эти фрагмента использовать невозможно, т.к. на момент загрузки ОС, последняя ещё не работоспособна. Поэтому придется либо пользоваться очень ограниченным подмножеством ЯВУ, либо писать для него костыли. Причем, по окончании работы окажется, что костыли удобнее стандартных процедур ЯВУ.

Переведу на понятный мне язык: вот есть в стандартах каждого ЯВУ описание языка как совокупность трёх вещей:
  • синтаксис и семантика базового языка
  • стандартная библиотека
  • модель памяти, абстрактный исполнитель
Если брать не условный Си с потенциально "нулевым рантаймом", а например Аду или ПЛ/1 (не говоря уже о Форте или Лиспе) — есть описание среды выполнения рантайм и компайлтайм. То есть: уже например форматы в PL/1
GET EDIT ...
— это по сути мини-диалект языка. В Си, например, интерпретатор встроенных форматных строк в printf, scanf. В Форте — внешний и внутренний интерпретатор, связь между интерпретируемыми и компилируемыми словами. Только этот интерпретатор мини-языка либо реализован в умном трансляторе, в случае PL/1; либо в компиляторе (как например
std::cout << x << y << z
в С++), либо crt0/msvcrt.dll языка в рантайм библиотеке Си языка.

Шаблоны и прочие CTFE трюки потенциально должны обеспечить типобезопасность. Например, в языке Nim была презентация про AST макросы и корректный printf времени компиляции. В итоге язык программирования явно и не явно содержит зависимость на рантайм библиотеку.

При реализации ядра ОС, как видно в OSdev wiki как правило, эта рантайм библиотека специально делается минималистичной своей собственной — потому что всё остальное ядро фактически должно быть реализовано на портированной новой этой рантайм библиотеке под новое ядро ОС. Проблема курицы и яйца, ага. Ну или метакомпиляторов в духе Форта или self-bootstrapping compiler.

В случае С++ всё ещё хуже из-за непереносимости ABI. Например, в LFS book компилятор gcc, который в последних версиях переписали на С++ — пересобирают по три раза, в разной комплектации; вообще в LFS как рецепте "собери свой Линукс" по сути множество циклических зависимостей, которые, чтобы разрешить, пересобирают несколько раз по кругу.

С другой стороны, если взять язык вроде Ада. У которого в самом языке есть task, entry, task types. То есть, от рантайм поддержки реализации языка требуется портировать эти примитивы, даже если самого ядра ещё нет — bare bones standalone. Ну с той погрешностью, что прагмами можно разные фичи вроде исключений, задач — отключать, и есть уже готовые профили вроде Ravenscar, которые более отключабельно минималистичны.

Чтобы сменить рантайм языка в Ада есть отдельный ключик компилятора,"брать другой рантайм из вот этого каталога". То есть, не так уж сложно собрать например ядро тоже самое, но с другим рантаймом. И затем его полноценно портировать (только несколько рантаймов, а не весь тулчейн-велосипед по три раза).

А причина проста: внутри у любого ЯВУ болтается "маленький хитрый кусок, завязанный на текущую ОС" и "большая смачная собственная ОС-надстройка/библиотека". При написании на ЯВУ оба эти фрагмента использовать невозможно, т.к. на момент загрузки ОС, последняя ещё не работоспособна. Поэтому придется либо пользоваться очень ограниченным подмножеством ЯВУ, либо писать для него костыли.

То есть, эту часть как проблему курицы и яйца можно раскрутить через системный bootstrap. Вот например, хорошая подборка: https://bootstrappable.org/ и например https://reproducible-builds.org/news/2022/05/18/jan-nieuwenhuizen-on-bootrappable-builds-gnu-mes-and-gnu-guix/ про MES и Guix Stage0, https://www.gnu.org/software/mes/manual/mes.html#Stage0 и выше/ниже по тексту про M2-Planet, mescc-tools, и т.п.

На bootstrappable.org например в вебархиве
https://web.archive.org/web/20221129205449/https://bootstrappable.org/ пишут примеры проектов, успешно разрешающие эту проблему "курицы и яйца", компиляторы, написанные по сути на самом себе.

Когда-то там же была ссылка про метакомпилятор Форта, но чего-то сейчас сразу не найду. Например, вот этот метакомпилятор Форта: lbForth https://github.com/larsbrinkhoff/lbForth — раскрученный из метакомпилятора на Лиспе :) В общем, этот "маленький хитрый кусок" может быть совсем маленьким.

В случае метакомпилятора он фактически написан "на самом себе", поэтому перенос под новую ОС (или ядра ОС, написанном на такой реализации через метакомпилятор) — элементарен. В случае высокоуровневого ЯВУ типа той же Ады — можно элементарно сменить рантайм на более минималистичный, при необходимости.

Хотя сам резон использования высокоуровневого языка в том и состоит, что хочется всё-таки использовать полноценно эти высокоуровневые фичи — реализованные уже на уровне самого языка, его рантайма (среды исполнения) — а не отдельных библиотек, как например в Си.

Вот смотрю я, например, на микроядро L4 и "дистрибутив" Genode Sculpt OS. И мне упорно кажется, что весь этот мандатный доступ, к системным объектам уровня ядра, который оборачивают в L4::Pistaschio через C++ и шаблоны и прочие смартпоинтеры, — это костыли и подпорки именно С++ как таковые. А при реализации той же идеи микроядра L4 на Аде, например, они становятся просто не нужны: достаточно переписать на уровне рантайма более правильную реализацию Address, или task, entry, task types, исключений.

То же самое, в какой-то степени, относится и к реализации на PL/I. Например, в PL/I была многозадачность и исключения. Которая явно используется в той же реализации Emacs на PL/I из MULTICS. И которую с грехом пополам, многозадачность и неблокирующую асинхронность наконец допортировали в GNU/Emacs на языке Си примерно к 2020 году, не раньше.

То есть все эти смачные надстройки и собственные реализации фич могут оказаться более полезны, для реализации ядра ОС — если реализованы уже непосредственно на уровне языка, его стандарта и рантайма. Их просто не нужно будет портировать — они уже будут встроены в язык, даже bare bones standalone на "голом железе".

     2022/12/07 21:49, Gudleifr          # 

из спортивно музейно-реконструкторского интереса

Вы идете, в общем-то, правильным путем. Но тут лучше сначала попробовать самому, чем сразу перейти к классификациям готовых решений. Порообуйте, например, создать загрузочную флэшку (не дающую запуститься Винде) и посмотреть, какими инструментами можно сделать её достаточно умной (ОС-образной).

     2022/12/07 22:51, kt          # 

Неслучайный читатель

Интересно, в какой версии эта ошибка появилась? В той, которую написал глава Digital Research? Или виноваты более поздние доработки?

Изначально не догадались проверить EDIT на переполнение. Ограничение форматов там даже не 255, а 127, поскольку каждый формат минимум два байта: тип и размер. Превышение списка форматов приводило к закрытию очередной записи OMF и формированию следующей, чего из-за конкретной реализации EDIT делать было нельзя. А так, корни восходят ещё к PL/I-80 для 8080.

Подобные ограничения есть и в структуре, где на каждом уровне может быть только 255 членов. Но можно завести промежуточный «пустой» уровень и тогда в структуре может быть описано до 255 членов по 255 объектов каждый (а можно и ещё углУбить уровни). Кстати и EDIT можно записывать не как
PUT EDIT(X1,X2,…Xn)(F1,F2,…Fn);
а как
PUT EDIT(X1)(F1)
(X2)(F2)

(Xn)(Fn);
Тогда ограничение исчезает.

     2022/12/08 13:32, Gudleifr          # 

P.S.

Когда-то там же была ссылка про метакомпилятор Форта, но чего-то сейчас сразу не найду.

Зачем искать? Все, что нужно знать о Forth, лежит в одном месте. Если Вам интересно, как разворачивается Forth — https://gudleifr.forum2x2.ru/t30-topic

     2022/12/08 21:01, Автор сайта          # 

void
Вы готовы утопить в море информации. Зачем здесь столько ссылок — чтобы по ним переходили и читали? Тогда, скорее всего, наступит то, что называют параличом анализа. Когда новая информация появляется быстрее, чем обрабатывается старая. Когда изучение новой информации отодвигает результат ещё дальше, чем было до изучения. Типичный случай, когда «вкрытие показало, что смерть наступила от вскрытия».

Если бы Вы хотели позитивного результата, то отобрали бы и рекомендовали 5 — 6 вариантов. Именно столько человеческий мозг в состоянии осмыслить в приемлемые сроки и принять правильное решение. В противном случае я не понимаю Вашей логики.

     2022/12/09 06:55, MihalNik          # 

столько человеческий мозг в состоянии осмыслить в приемлемые сроки

А что есть приемлемые сроки? Например, некоторые оставляют комментарии к статьям (и другим ответам!) спустя годы написания. Некоторые статьи в принципе состоят больше из вопросов — и сами напрашиваются на весьма длинные ответы и рассуждения. А некоторые могут потребовать небыстрого прочтения и немалого обдумывания, например, статьи Д.Ю. Караваева. Так есть ли сроки вообще?

Другое дело — неудобное оформление. Я вот сейчас не уверен, что отсылки запросто можно нагуглить, особенно человеку не в теме таких довольно специфических языков, как Хаскелл, Форт, Лисп, или довольно давних исторических разработок. Но может лучше хоть так, чем совсем ничего.

     2023/04/13 20:22, Лис          # 

За 8 прошедших лет никто (ни один человек!) не заинтересовался ни моими исходниками, ни исполняемым модулем.

Я, конечно, не человек, но попробую. Прошу выложить, пожалуйста, твои исходники под открытой общедоступной всем разумным лицензией.

     2023/04/14 09:39, kiv(jobless)          # 

История зациклилась как ей и предписано.

С машиной поставлялся автокод АРМУ (Автокод Ряда Машин Урал), который был единым автокодом ряда ЭВМ типа “Урал”. Он был составлен с учетом особенностей этих машин и обеспечивал полную совместимость от меньшей машины к большей. Каждая ЭВМ “Урал” имела собственный транслятор с языка АРМУ на свой машинный язык. Таким образом, совместимость ЭВМ типа “Урал” была ограниченной и существовала только на уровне автокода АРМУ.

https://computer-museum.ru/histussr/ural11.htm

P.S. Первая программа, которой кто-то кроме меня пользовался, была написана 40 лет назад как раз для Урал-11. Это мой комментарий: https://habr.com/ru/articles/722532/comments/#comment_25328792

     2023/04/15 13:52, Автор сайта          # 

Вы пытаетесь занять меня работой, которой я пока что не собирался заниматься: изучать виды лицензий, сравнивать, выбирать, потом куда-то выкладывать — а это опять изучать и выбирать.

От исходников проку никакого, ведь продолжать разработку никто не будет. В этой разработке больше всего я ценю синтаксис. Всё остальное «тупо кодируется», ничего уникального там нет. Но синтаксис не защищается авторским правом, поэтому пользоваться этим можно без оглядки на законы. Так что для начала можно познакомиться, а если что-то показалось нужным, вот тогда и вернуться к вопросу о лицензиях. Ссылка для скачивания: https://disk.yandex.ru/d/qhBKuW4xcvgu9g

Недавно обнаружил один проект на тему ассемблера (https://github.com/langprogramming-AsmX/AsmX). После небольшого общения с автором выяснилось, 1) что программирование на русском его вообще не интересует, 2) что «удобно», «понятно» и «просто» выглядят для нас совершенно по-разному, если не сказать, что противоположно.

     2023/04/15 15:46, Денис Будяк          # 

Соглашусь с Лисом. Лицензия нужна. Разница в том, что либо Вы работаете в корзину, либо приносите пользу другим людям. Я понимаю, что многим это всё равно, но тем не менее разница именно такая.

     2023/04/15 15:58, Лис          # 

Юрий всё правильно написал про время и текущие интересы. Конечно, хорошо было бы лицензию сделать, но мы не можем к этому принуждать именно Юрия.

Я хотел поспособствовать Евгению в ответе на его вопрос о том, есть ли какой-нибудь синтаксис ассемблера. Юрий помог в решении этого вопроса. Верно, что исходники дорабатывать никто не будет. Тема на лисофоруме — http://plana.mybb.ru/viewtopic.php?id=2058

Пока этого достаточно, я так думаю.

     2023/04/15 16:19, Автор сайта          # 

Мне всё равно, под какой лицензией это будет. Уже был подобный случай, можно повторить. Но если надо «по-взрослому», то будьте добры, изложите мне кратко суть самых подходящих лицензий, чтобы я ткнул пальцем в одну из них. И заодно объясните, насколько вписываются зарубежные лицензии в наше правовое поле.

     2023/04/16 00:17, Бурановский дедушка          # 

В изобретении ассемблеров одиночества нет: https://habr.com/ru/users/VitGo/posts/

Добавить свой отзыв

Написать автору можно на электронную почту
mail(аt)compiler.su

Авторизация

Регистрация

Выслать пароль

Карта сайта


Содержание

Каким должен быть язык программирования?

Анализ и критика

Описание языка

Компилятор

Отечественные разработки

Cтатьи на компьютерные темы

●  О превращении кибернетики в шаманство

●  Про лебедей, раков и щук

●  О русском ассемблере

●  Арифметика синтаксиса-3

●  Концепция владения в Rust на примерах

●●  Концепция владения в Rust на примерах, часть 2

●●  Концепция владения в Rust на примерах, часть 3

●  Суть побочных эффектов в чисто функциональных языках

●  О неулучшаемой архитектуре процессоров

●  Двадцать тысяч строк кода, которые потрясут мир?

●  Почему владение/заимствование в Rust такое сложное?

●  Масштабируемые архитектуры программ

●  О создании языков

●●  Джоэл Спольски о функциональном программировании

●  Почему Хаскелл так мало используется в отрасли?

●  Программирование исчезнет. Будет дрессировка нейронных сетей

●  О глупости «программирования на естественном языке»

●  Десятка худших фич C#

●  Бесплатный софт в мышеловке

●  Исповедь правового нигилиста

●  ЕС ЭВМ — это измена, трусость и обман?

●  Русской операционной системой должна стать ReactOS

●  Почему обречён язык Форт

●  Программирование без программистов — это медицина без врачей

●  Электроника без электронщиков

●  Программисты-профессионалы и программирующие инженеры

●  Статьи Дмитрия Караваева

●●  Идеальный транслятор

●●  В защиту PL/1

●●  К вопросу о совершенствовании языка программирования

●●  Опыт самостоятельного развития средства программирования в РКК «Энергия»

●●  О реализации метода оптимизации при компиляции

●●  О реализации метода распределения регистров при компиляции

●●  О распределении памяти при выполнении теста Кнута

●●  Опыты со стеком или «чемпионат по выполнению теста Кнута»

●●  О размещении переменных в стеке

●●  Сколько проходов должно быть у транслятора?

●●  Чтение лексем

●●  Экстракоды при синтезе программ

●●  Об исключенных командах или за что «списали» инструкцию INTO?

●●  Типы в инженерных задачах

●●  Непрерывное компилирование

●●  Об одной реализации специализированных операторов ввода-вывода

●●  Особенности реализации структурной обработки исключений в Win64

●●  О русском языке в программировании

●●  Формула расчета точности для умножения

●●  Права доступа к переменным

●●  Заметки о выходе из функции без значения и зеркальности get и put

●●  Модификация исполняемого кода как способ реализации массивов с изменяемыми границами

●●  Ошибка при отсутствии выполняемых действий

●●  О PL/1 и почему в нём не зарезервированы ключевые слова

●●  Не поминайте всуе PL/1

●●  Скорость в попугаях

●●  Крах операции «Инкогнито»

●●  Предопределённый результат

●●  Поддержка профилирования кода программы на низком уровне

●●  К вопросу о парадигмах

●  Следующие 7000 языков программирования

●●  Что нового с 1966 года?

●●  Наблюдаемая эволюция языка программирования

●●  Ряд важных языков в 2017 году

●●  Слоны в комнате

●●  Следующие 7000 языков программирования: заключение

Компьютерный юмор

Новости и прочее




Последние отзывы

2024/04/25 21:05 ••• Ttimofeyka
Энтузиасты-разработчики компиляторов и их проекты

2024/04/23 00:00 ••• alextretyak
Признаки устаревшего языка

2024/04/21 00:00 ••• alextretyak
Постфиксные инкремент и декремент

2024/04/20 21:28 ••• Бурановский дедушка
Русский язык и программирование

2024/04/07 15:33 ••• MihalNik
Все языки эквивалентны. Но некоторые из них эквивалентнее других

2024/04/01 23:39 ••• Бурановский дедушка
Новости и прочее

2024/04/01 23:32 ••• Бурановский дедушка
Русской операционной системой должна стать ReactOS

2024/03/22 20:41 ••• void
Раскрутка компилятора

2024/03/20 19:54 ••• kt
О многократном резервировании функций

2024/03/20 13:13 ••• Неслучайный читатель
Надёжные программы из ненадёжных компонентов

2024/03/07 14:16 ••• Неслучайный читатель
«Двухмерный» синтаксис Python

2024/03/03 16:49 ••• Автор сайта
О неправомерном доступе к памяти через указатели

2024/02/28 18:59 ••• Вежливый Лис
Про лебедей, раков и щук