Это язык машинных кодов. Разработали его электронщики в виде схем соединения радиоламп. Тогда ЭВМ были ламповыми. А программисты вводили программу при помощи панелей тумблеров, где каждый представлял собой бит 0/1. Мало-мальски в привычном смысле программирование появилось несколько позже еще на ламповых ЭВМ. А развитие получило уже на транзисторных второго поколения. По прежнему язык определялся по сути схемотехникой.
На языке машинных кодов был написан ныне забытый автокод. Это то же программирование на машинных кодах только существовал некий прородитель компилятора который мог подставлять абсолютные адреса в памяти вместо относительных. Что в разы снизило трудоемкость программирования.
Потом появились ассемблеры. Компилятор с ассемблера это еще тоже простая штука. Но с другой стороны сам язык ассемблера позволяет уже писать сложные проекты с по современным меркам приемлемой трудоемкостью.
Кстати многие мощные языки высокого уровня типа C написаны сами на себе. Т.е. сначала на ассемблере или другом доступном до этого языке пишется либо интерпретатор либо упрощенный компилятор. Который во-первых поддерживает только упрощенное подмножество языка. А во-вторых порождает неэффективный неоптимизированный код. Затем на этом упрощенном подмножестве (проще говоря на самом этом языке только без использования некоторых фич и синтаксического сахара) пишется уже полноценный оптимизирующий компилятор. Дальше он пропускается через компилятор первой очереди либо выполняется на интерпретаторе. И через него уже можно пропустить его же собственный код. После чего интерпретатор/компилятор первой очереди уже не нужен. Получается что реально применяемый на прикладных задачах компилятор скомпилировал сам себя. Процесс я описал упрощенно на самом деле он итеративный, шагов гораздо больше. Возможности языка и эффективность генерируемого компилятором кода как бы "разворачиваются", расширяются при многочисленных повторениях описанных выше шагов.