{
    "version": "https:\/\/jsonfeed.org\/version\/1.1",
    "title": "Блоги: заметки с тегом m4",
    "_rss_description": "Автоматически собираемая лента заметок, написанных в блогах на Эгее",
    "_rss_language": "ru",
    "_itunes_email": "",
    "_itunes_categories_xml": "",
    "_itunes_image": false,
    "_itunes_explicit": "no",
    "home_page_url": "https:\/\/blogengine.me\/blogs\/tags\/m4\/",
    "feed_url": "https:\/\/blogengine.me\/blogs\/tags\/m4\/json\/",
    "icon": false,
    "authors": [
        {
            "name": "Илья Бирман",
            "url": "https:\/\/blogengine.me\/blogs\/",
            "avatar": false
        }
    ],
    "items": [
        {
            "id": "135849",
            "url": "https:\/\/bolknote.ru\/all\/nemnogo-o-slozhnostyah-napisaniya-assemblera-na-m4\/",
            "title": "Немного о сложностях написания ассемблера на m4",
            "content_html": "<p>Не думаю, что я много буду использовать язык <i>m4<\/i> в будущем, если вообще буду, поэтому хотел дать себе и, возможно, кому-то из читателей чуть больше контекста о том как писался на этом макропроцессоре <a href=\"https:\/\/bolknote.ru\/all\/assembler-processora-i8080a-na-m4\/\">ассемблер процессора 8080A<\/a>. А то со временем всё забудется.<\/p>\n<p>Для этого я чуть-чуть больше расскажу о <i>m4<\/i> и ассемблере 8080A.<\/p>\n<p>Ассемблер 8080А довольно простой. Будучи школьником, я его выучил по комментариям к кускам кода, которые печатались в журнале «Радио» — другой литературы в моём доступе не было. В нём всего несколько команд, большинство из них имеют один или два параметра.<\/p>\n<p>Посмотрим, например, на команды <tt>ADD B<\/tt> и <tt>ADD C<\/tt>. Первая эквивалентна <tt>A += B<\/tt> на других языках, вторая — <tt>A += C<\/tt>. Буквами обозначаются регистры, для простоты можно считать их именованными переменными. Их мало, всего несколько штук и они имеют свои особенности. Например, в этих двух командах мы видим особенность регистра <tt>A<\/tt> — к нему можно прибавлять значения других регистров.<\/p>\n<p>Команды <tt>ADD B<\/tt> и <tt>ADD C<\/tt> для исполнения компьютером переводятся в числа — в машинные коды. Обычно их записывают в шестандцатеричном виде, я тоже так буду делать. Данные команды сложения кодируются как числа <tt>80<\/tt> и <tt>81<\/tt> соответственно.<\/p>\n<p>Теперь немного про <i>m4<\/i>. Я писал выше, что <i>m4<\/i> — макропроцессор, если упрощать, язык макропроцессора позволяет указать как одни «слова» заменить на другие. «Слова» при этом должны начинаться с буквы или подчёркивания и содержать только буквы, цифры или знак подчёркивания. Это ограничение очень важное. Не будь его, я бы задал по одному правилу на каждую команду: <nobr><tt>ADD B → 80<\/tt><\/nobr>, <nobr><tt>ADD C → 81<\/tt><\/nobr> и был таков.<\/p>\n<p>К сожалению, так это не работает. Из-за этого ограничения, когда макропроцессор встречает <tt>ADD<\/tt>, он ещё не знает что будет дальше, поэтому не может выбрать на какой код заменить это слово, а когда дальше он видит <tt>B<\/tt> или <tt>C<\/tt>, ему надо помнить, что было до этого, так как с этими регистрами работает много команд. Другими словами, макропроцессору нужно запоминать контекст.<\/p>\n<p>В руководствах по <i>m4<\/i> указывается, что этот макропроцессор контекст учитывать не умеет. Так и есть, встроенных конструкций, предназначенных именно для этого нет, но можно выкрутиться менее специфичными. Дело в том, что <i>m4<\/i> может проверять как выглядят его текущие правила замен одного слова на другое.<\/p>\n<p>Поэтому мы можем завести специальное правило, куда будем записывать какая команда нам встретилась, а позже, встретив имя регистра, будет проверять чему равно наше специальное правило и производить замену, основываясь на этом.<\/p>\n<p>При этом <i>m4<\/i> не делает различий между, так сказать, текстом программы и обрабатываемым текстом, для него это одно и то же. То есть макропроцессор делает возможным метапрограммирование — позволяет менять программе свой собственный текст.<\/p>\n<p>Вот как это выглядит в коде:<\/p>\n<pre class=\"e2-text-code\"><code class=\"plaintext\">dnl заменяем строку ADD на определение макроса, сама строка ADD при этом пропадёт\ndefine(`ADD&#039;, `define(`__cmd&#039;, `__s_ADD&#039;)&#039;)dnl\n\ndnl когда встречаем B, смотрим чему равно определение макроса __cmd\ndefine(`B&#039;, `\nifelse(\n    defn(`__cmd&#039;), `__s_ADC&#039;, 88,\n    defn(`__cmd&#039;), `__s_ADD&#039;, 80,\n    …тут остальные команды…\n    `&#039;)\n&#039;)dnl\n\ndnl когда встречаем C, смотрим чему равно определение макроса __cmd\ndefine(`C&#039;, `\nifelse(\n    defn(`__cmd&#039;), `__s_ADC&#039;, 89,\n    defn(`__cmd&#039;), `__s_ADD&#039;, 81,\n    …тут остальные команды…\n    `&#039;)\n&#039;)dnl<\/code><\/pre><p>Чтобы дойти до этого трюка, пришлось поломать голову, но тем интереснее. Возможно он где-то уже описан, но искать информацию по <i>m4<\/i> очень тяжело — поисковые машины охотно путают его с одноимённым процессором, а нейросети пишут какую-то пургу, не имеющую никакого отношения к реальности.<\/p>\n",
            "date_published": "2025-05-18T17:56:58+05:00",
            "date_modified": "2025-05-18T17:56:28+05:00",
            "tags": [
                "m4",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Sun, 18 May 2025 17:56:58 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "135849",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "135830",
            "url": "https:\/\/bolknote.ru\/all\/assembler-processora-i8080a-na-m4\/",
            "title": "Ассемблер процессора i8080A на m4",
            "content_html": "<p>Сегодня опять сычевал почти до полуночи — вечером попался кусок кода на <i>m4<\/i> и я, пробормотав вечное «когда-нибудь надо бы его выучить», вдруг подумал — а почему бы и не сейчас? Я и так всё время откладываю, а этот вечер ничем для этой цели не хуже, чем любой другой.<\/p>\n<p>Чтобы разбираться было веселее, придумал себе задачу — написать на <i>m4<\/i> ассемблер, желательно не очень сложный, чтобы занятие на вечерок не разрослось потом до недельного проекта. Взял <a href=\"https:\/\/web.archive.org\/web\/20131014125438\/https:\/\/demin.ws\/projects\/radio86\/info\/kr580\/i8080.html\">инструкции интеловского процессора 8080A<\/a> — это был мой первый ассемблер. Советской аналог процессора стоял на компьютере «Радио-86РК», с <a href=\"https:\/\/bolknote.ru\/all\/4316\/\"> которого я когда-то начинал<\/a>.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/bolknote.ru\/pictures\/2025.05.15@2x.webp\" width=\"1000\" height=\"665\" alt=\"\" \/>\n<div class=\"e2-text-caption\">Строка «HELLO WORLD», выведенная программой, переведённой в машинный код моим ассемблером<\/div>\n<\/div>\n<p>Несколько слов о том что такое <i>m4<\/i>.<\/p>\n<p>Это довольно простой макропроцессор, умеющий заменять одни указанные строки на другие. Описание что на что заменить делается параметрическими макросами. В языке есть собственные макросы, но можно определить и пользовательские. Поддерживаются так же условия и математика. В продвинутых версиях <i>m4<\/i> есть даже циклы, но их в любой версии можно эмулировать рекурсией.<\/p>\n<p>Парочка примеров того как выглядит его синтаксис:<\/p>\n<pre class=\"e2-text-code\"><code class=\"plaintext\">dnl Макрос, заменяющий одну строку на другую\ndefine(`WORLD&#039;, `KAZAN&#039;)dnl\n\ndnl Макрос, оставляющий первый свой параметр как есть, а\ndnl второй складывающий со значением другого макроса,\ndnl если второй параметр не указан, его значение — единица\ndefine(`__pr&#039;, `define(`__ip&#039;, eval(__ip + ifelse($2, `&#039;, 1, $2)))$1&#039;)dnl<\/code><\/pre><p>Чтобы реализовать задуманное, я взял список команд процессора с кодами — их там чуть меньше 250, если брать варианты с разными регистрами, и написал на Пайтоне два генератора.<\/p>\n<p>Два, потому что мне нужно было как-то решить проблему расчёта адресов ссылок. Первая программа генерирует файл <tt>linker8080.m4<\/tt>, который этим и занимается. Адреса он на следующем этапе передаёт в виде макросов второму файлу — <tt>asm8080.m4<\/tt>, который делает основную работу — переводит ассемблер в машинные коды.<\/p>\n<p>Сначала у меня всё было сделано в одном файле, но я быстро выяснил, что макросы распространяются сверху вниз, то есть определённые ниже макросы не влияют на текст выше. Если ссылка, для которой я подсчитал адрес, находится ниже точки вызова, я этот вызов уже не могу заменить.<\/p>\n<p>Вот программа на этом ассемблере, в действии её можно посмотреть на скриншоте:<\/p>\n<pre class=\"e2-text-code\"><code class=\"asm\">ORG(h1100)\nLXI H, ADDR(TEXT)\nCALL hF818\nJMP hF86C\n\nLABEL(TEXT)\nBYTE(h48, h45, h4C, h4C, h4F, h20, h57, h4F, h52, h4C, h44, hD, hA, h0)<\/code><\/pre><p>Не слишком отличается от привычного вида, но отличия всё-таки есть.<\/p>\n<p>Во-первых, числа должны быть только шестнадцатеричными. Часто так и бывает, но тут запись немного непривычная — <tt>hFF<\/tt> вместо более привычной <tt>FFh<\/tt>.<\/p>\n<p>Во-вторых, многие вещи, не генерирующие код, выглядят чуть иначе — адрес запуска задаётся конструкцией <tt>ORG(…)<\/tt>, метка — через <tt>LABEL(…)<\/tt>, а её адрес получается через <tt>ADDR(…)<\/tt>.<\/p>\n<p>В-третьих, произвольные цепочки байт задаются не директивой <tt>DB<\/tt>, а конструкцией <tt>BYTE(…)<\/tt>.<\/p>\n<p>Результат можно увидеть у меня <a href=\"https:\/\/github.com\/bolknote\/M4-8080A-Asm\">в репозитории<\/a>.<\/p>\n",
            "date_published": "2025-05-16T10:40:51+05:00",
            "date_modified": "2025-05-16T12:27:02+05:00",
            "tags": [
                "m4",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Fri, 16 May 2025 10:40:51 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "135830",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        }
    ],
    "_e2_version": 4079,
    "_e2_ua_string": "Aegea 11.0 (v4079e)"
}