Pull to refresh

Comments 114

Приятно почитать, тем же страдаю. Только для языка Оберон. Кстати, писал одно программу на языке Модула-2, так вот исполняемый файл антивирусы тоже убивали.
Рад встретить союзника. Наработки где-нибудь выкладывали? Кстати, я присматривался и к Оберону, но смутило несколько обстоятельств: 1) он слишком мало распространён, для него не найти ни примеров, ни тестов, ни желающих в нём разбираться; 2) он слишком лаконичен (спасибо и за то, что вернули цикл FOR!); 3) ключевые слова непременно в верхнем регистре — ужасны.
Есть пара фрагментов в LinkedIn (для понтов), а так, зачем? У Вирта опубликованы исходники, кроме кодогенератора. Ну и, не хочется уподобится многим-многим проектам, так и не законченным. Будет результат, опубликую. У меня к Оберону, это уже наверное седьмой подход. Вирт настолько всё проработал, одним махом делает «семь» действий. У меня если больше двух — ступор. Тяжело было разбираться.
Через неделю программирования на Обероне не будете обращать внимание на заглавные буквы — поначалу те же ощущения были. Язык очень красив и быстро изучаем. Алгоритмы, по крайней мере, на нем пишутся удобно. Ну а для начального обучения вообще отличный выбор — позволяет быстро сосредоточиться на алгоритмах, а не на борьбе с языком. Жаль, что мало людей вообще пробовали на нем писать.
Как вариант замены DOS может быть перенос компилятора под операционную систему KolibriOS.

P.S. Есть прямые варианты запуска программ KolibriOS почти как родные в рамках Linux и Windows.
Эмуляция KolibriOS API (Windows)
Эмулятор под Linux

Ну и разные варианты Паскаль компиляторов тоже есть под KolibriOS, включая и Oberon.
Слышал о ней. Милая вещица, как и её родной ассемблер FASM. Но уход от DOS мне был нужен не ради самого ухода, а ради того, чтобы хоть кому-то можно было показать работу откомпилированных программ. А KolibriOS пришлось бы прикладывать как довесок к каждой программе :)

Видно вы увлечены языком Паскаль, а в чем по вашему мнению достоинства этого языка по сравнению с другими — скажем из первой десятки популярности (на выбор)

Совершенно верно, увлечён. Считаю, что это очень гармонично спроектированный, лёгкий для чтения и удобный для компиляции язык. Да, у раннего Паскаля было слишком много ограничений по сравнению с C, о чём красноречиво писал Керниган. Из-за этого, видимо, C сразу получил фору.

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

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

  • Отсутствие ключевых слов, обозначающих вид объявляемого идентификатора: function, var, type и т.д. Из-за этого начинается нездоровая игра со скобками, а читаемость программы резко ухудшается.
  • Сильная зависимость от препроцессора. Без него невозможно подключить внешний модуль или задать подлинную константу, не занимающую памяти.
  • Провалившаяся попытка отождествить массивы и указатели. Насколько я понимаю, сначала разработчики языка надеялись на полное отождествление. Однако как только пришлось допустить массивы в качестве полей структуры, тождество стало фикцией. В результате для двумерного массива A все величины A, &A, *A, A[0], &A[0] равны друг другу. Не абсурд ли это?
  • Неудобный оператор switch. Это вынужден был признать ещё Керниган.
  • Параллельное существование у структур «имени типа» и «тега типа». Как такое могло появиться, я вообще не представляю.

Я понимаю, что от многих этих недостатков пытаются уйти — если не в C++, то в каком-нибудь Go. Однако здесь мне остаётся присоединиться к одному меткому комментарию на Хабре:
Не понимаю, зачем индустрия хоронит Паскаль, а потом много раз изобретает его заново.


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

У C-подобных языков есть большое преимущество: возможность объявлять переменную там, где она нужна и тогда, когда она нужна. В паскале-подобных языках приходится или заранее, до написания собственно кода, придумывать, что написать в var блоке, либо бегать туда-сюда при написании кода, либо заполнять var блок когда функция уже написана. Ни один из вариантов не похож на заботу о программисте.

У Паскаля есть большое преимущество — программиста учат думать перед тем, как что-то написать. А необьявление переменных было в бейсике)

>преимущество — программиста учат думать перед тем, как что-то написать

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

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

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

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

(утверждение прямо в стиле Черномырдина)
Как по мне, основное преимущество Паскаля в том, что простую программу на Паскале можно объяснить падавану «в лоб» строчка за строчкой, не оставляя «на потом» непонятных сущностей. С другими языками такое обычно не проходит, «тут у нас импортируются библиотеки, это мы рассмотрим позже, пока просто запомните это», «void указывает, что функция не возвращает никакого значения, что такое функция и возвращаемые значения, мы рассмотрим позже, пока просто запомните это» и так далее.
У C-подобных языков есть большое преимущество: возможность объявлять переменную там, где она нужна и тогда, когда она нужна

Да, но до C99 в C (например, C89) ситуация с объявлением переменных тоже была почти как в Паскале. За тем исключением, что:


1) можно было объявлять переменные не только в начале функции, но и в начале блока (scope), глобальные переменные в расчёт не берём
2) не было необходимости в отдельном var-блоке


Из-за этого в C89 даже привычную сейчас декларацию переменную цикла for приходилось объявлять заранее, а не внутри for-конструкции.

Да, это так. Однако в первых вариантах C такой возможности не было, она появилась позже. Ничто не мешает развивать в том же направлении Паскаль. Есть хороший пример Паскаля, в котором переменные объявляются именно там, где они нужны.

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


  1. допустим, мы разрешили объявлять переменные в произвольных местах.
  2. Было бы логично добавить автовывод типов, чтобы не писать лишнего конструкции вида var a := 2
  3. можно прикрутить константы (напимер, val a := 2), чтобы код стал более строгим.
  4. тогда захочется, чтобы конструкции типа if возвращали выражения, чтобы было удобно инициализировать константы: val sign := if (a>=0) then 1 else 0 end

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


Если остановиться на пол-пути и сделать только первое изменение, то возможность легко разложить переменные функции по регистрам/стеку пропадает (придётся анализировать все возможные пути исполнения, включая использование goto), а сам язык не станет сильно лучше.

Возможно, все эти нововведения действительно нужны. Когда заходит речь о конкуренции в сфере профессионального программирования, приходится, видимо, поступаться простотой компилятора. Иначе, не имея всего перечисленного вами, Паскаль навсегда останется слабее С++ или чего-то подобного. Будет ли ваш язык «не совсем» Паскалем? Не знаю. Однако Бейсик до сих пор жив только потому, что он «не совсем» прежний Бейсик. Да даже и Delphi — это «не совсем» Паскаль от Никлауса Вирта. Язык должен эволюционировать — иначе он умирает. Паскаль, увы, оказался не в самых заботливых руках после смерти Borland.

Язык и эволюция? Это такой же миф как и апгрейд.
Может просто стоит выкидывать каждый старый язык и писать ещё один лучший новый, на основе новых достижений и ошибок прошлого?
Иначе мы имеем кейс с++, когда нужно тянуть ворох всей обратной совместимости с классическим Си и его модификациями, так и предыдущими ревизиями С++. Это усложняет и удорожает разработку компилятора, но кого это волнует? А вот то, что это удорожает разработку на этом языке, т.к. постоянно нужно допиливать код и обходить "ловушки", которые появляются из-за разных версий стандарта. Ну, что ж.
И, действительно, если б все было так хорошо с эволюцией, то не появились бы golang, d, rust. Хотя и они менее популярны, как кресты, по крайне мере сейчас

Эволюцией Паскаля были Модула и Оберон. К сожалению, по некоторым причинам, они не получили широкого распространения в 90-е и 2000-е. А сейчас уже поздно.
Да да, сишная хрень теперь и в паскале.
begin
   begin
     var a:=123;
     Writeln(a);
   end;
   begin
     var a:=123.456;
     Writeln(a);
   end;
   begin
     var a:=now;
     Writeln(a);
   end;
   begin
     var a:='Marasmus C in  Pascal';
     Writeln(a);
   end;
   readln;
end;


Ждем реализации сишных макросов, обязательной препроцессорной обработки и регистро-зависимого объявления переменных.
Брр-р-р-р, шикарный язык уродуют чудаки на букву м (с)
Ждем реализации сишных макросов, обязательной препроцессорной обработки и регистро-зависимого объявления переменных.

Зачем ждать это в паскале, если прямой сейчас можно перейти на C++ и получить все эти преимущества немедленно?

О том и речь. что идет переход от паскаля к недо-си, все это при наличии собственного Билдера.

Предлагаете вообще ничего в язык не добавлять?
Это популярности не прибавит, а с ней и так не очень хорошо.

возможность объявлять переменную там, где она нужна и тогда, когда она нужна в PASCAL-подобных языках

Пожалуйста:
В Modula-3 ( ...).Однако, локальная область определения переменной цикла в данном случае вполне соответствует «духу» языка (поскольку возможны прочие локальные области в виде вложенных блоков «VAR… BEGIN… END» для поддержки «горячего определения переменных в коде», в т.ч. с возможностью вывода типа, но оставаясь в рамках «структуризации по-Паскалевски»).


Практика использования вышеупомянутого в Modula-3:

caltech-parser\cit_util\src\SIsuffix.m3
  FOR i := FIRST(List) TO LAST(List) DO
    VAR
      x : BOOLEAN;
    BEGIN
      x := tbl.put(List[i].char, List[i]);
      <* ASSERT NOT x *>
    END
  END


m3-libs\bitvector\test\src\TestBitVector.m3
    FOR i := 0 TO Max - 1 BY 7 DO
      FOR j := 1 TO 6 DO
        VAR set := bv2.set(i+j); BEGIN <* ASSERT NOT set *> END
      END
    END;


Аналогично — в ADA
Прямой наследник Паскаля и Оберона — Go (для меня это был сюрприз)

Когда доделаю очередную статью по надежности, будет чуть подробнее.
Я имел в виду не фигурные скобки (они действительно ничем не хуже begin...end), а круглые в предложениях вида void (*fun_ptr)(int) = &fun. Их обилие напрямую связано с отсутствием ключевых слов для вида объявляемого идентификатора.
Хм. Но что плохого в приведении типа? Да, у C-style cast есть проблема, при использовании следует быть внимательным и знать, что делаешь :-) Но есть и С++ со static_cast и прочими иными _cast.
А разве это приведение типа? Это «просто» объявление указателя на функцию.
В вашем примере — да, объявление указателя. Простое, без кавычек, а также логичное: скобки имеют тот же смысл что и в знакомой любому программисту школьной алгебре — устанавливают приоритет.
Мне кажется, одно только то, что вы сами приняли эту запись за приведение типа, говорит против такого синтаксиса. И разве это логично — оставлять за скобками список аргументов и тип возвращаемого результата? Ведь это часть определения функции, на которую объявляется указатель. Так что скобки здесь только нарушают естественный порядок действий: 1) задать сигнатуру функции; 2) задать указатель на неё.

А стоит только появиться typedef в начале, так fun_ptr, стоящий в середине, вдруг окажется именем типа. И это тоже логично?
>вы сами приняли эту запись за приведение типа

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

>И разве это логично

Вы всего лишь привыкли к паскалевскому синтаксису и субъективно, т.е. для вас, непривычный синтаксис в C/C++ объявляете объективно нелогичным :-)
Я за много лет привык к сишному синтаксису и тем не менее считаю его категорически неудобным. Логичным или нет — сказать сложно — у каждого варианта своя логика, но та, что в C, сильно сложнее читается, чем стиль паскаля/Go/etc., и с усложнением конструкции сложность её чтения растёт экспоненциально.
Любопытно, что точно о том же пишут сами создатели C и UNIX. У Кернигана и Ричи прочёл:
C is sometimes castigated for the syntax of its declarations, particularly ones that involve pointers to functions. The syntax… can be confusing ..., because declarations cannot be read left to right, and because parentheses are over-used.

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

1. Триграфы появились сильно позже того, как язык вышел на широкий простор, и предназначены для работы в странных условиях вроде урезанных или национальных версий EBCDIC. Их вообще поддерживают только ради наличия в стандарте, по умолчанию в массовых компиляторах их распознавание выключено.

2. Ничего из клавиатурных ограничений или кодовых таблиц не заставляет писать «int *a» вместо «var a: *int».
Компактность — единственное, что тут можно более-менее вменить как причину таких синтаксических выборов. Но и то — настолько жёсткую экономию на 2-3 ключевых словах — получаем буквально пару процентов за счёт резкого ухудшения в сложных случаях…
Я помню, в универе, в те времена, когда существовало понятие «машинного времени», одна и та же (по сути) программа компилировалась на Турбо Паскале с считанные секунды, а на Турбо Си десятки секунд. Сложный проект на Паскале компилировался десятки секунд, а такой же на на Си можно было сходить покурить…
Я бы еще добавил один существенный недостаток (если его можно так назвать) C: легкая возможность выстрелить себе в ногу, со всеми этими указателями, разыменованиями и прочими конструкциями.
Защитники сразу же скажут, что, мол, надо знать и понимать, что делаешь, однако статистика уязвимостей показывает, что, похоже, 9 из 10 всевозможных багов и дыр в современном ПО связаны прямо или косвенно с тем, что за всем этим уследить невозможно, как бы ты хорош не был. Если ружье на стене висит, оно обязательно выстрелит.
В Паскале об этом вообще думать не надо практически, что позволяет сосредоточиться на задаче, а не бегать смотреть, там ли ты поставил звездочку, вычитывать warnings компилятора и стараться понять, это ты плохо сделал или это просто перестраховка от компилятора.

Эх, вспоминаю свою юность, ночами на пролет писал на Паскале для Fido, потом портировал это все на пиратский Virtual Pascal, который умел компилировать под Win и OS/2, потом на Free Pascal уже под Linux (и все портирование, кстати, было в убирании прямой работы с видеопамятью и изменение пары типов переменных; вот она сила Паскаля, код из 1998 года компилируется в 2019 :).

Захожу раз в год на свой github, перечитываю и пересматриваю код и радуюсь воспоминаниям.
Дикая усидчивость, терпение и желание творить были. Имея под рукой только одну книжку по Паскалю, несколько чужих примеров, ворованную techhelp библиотеку про прерывания, получалось делать массу всего и очень быстро.

P.S. А выбор в свое время пал на Паскаль только потому, что, когда мне с трудом удалось достать диск с разными компиляторами, он был поцарапанный и архив с Borland C не читался, а Borland Pascal распаковать удалось.
В Паскале об этом вообще думать не надо практически

Это за счёт чего это? В Паскале нет указателей, разименований и прочих конструкций?

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

Да, есть такое. Но я сомневаюсь, что 9 из 10 багов из-за этого. 1 из 10 — готов поверить. Остальные 8 должны быть и в Паскале.

Скорость компиляции в Дельфи) у меня может быть проект на 500 тыщ строк и я могу компилировать после любого изменения и через 1сек видеть результат

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

Золотые слова!
А еще наиболее удобный (с мой точки зрения) для начального обучения.

Согласен. В обучении программированию первенство Паскаля может оспорить разве что Питон. Но здесь есть коварный вопрос: стоит ли сразу ставить ученика перед необходимостью объявлять переменные? Мой опыт программирования начинался с Бейсика, и переход к языкам с явной статической типизацией был мучителен. Есть риск, что с тем же столкнутся и взращенные на Питоне. К тому же, Питон местами совсем не очевиден. Как объяснить начинающему хитрости передачи аргументов в функцию? Как задать большой двумерный массив?

Проблема питона в нескольких вещах


  1. Конкуренция между питон 2. и питон 3. Если б своевременно закопали второй, то мы бы быстрее получили нормальный третий
  2. Отсутствие четкости в тех же типах переменных. Это приводит к тому, что быстро наговнякать скрипт или какой-то маленький проект на питоне действительно очень легко. Но создать большое и надёжное продакшн решени тяжело. Я не говорю, что невозможно, это решаемая проблема, но на какой-нибудь джаве это будет проще, т.к. она больше страхует разраба от него самого. Но ценой своеобразного тулинга и большей многословности кода
В штатах питон — язык для обучения в ВУЗах. Оттуда такой рост на Тиобе.
Мой опыт программирования начинался с Бейсика, и переход к языкам с явной статической типизацией был мучителен.

А у меня — не был. В Бейсике очень быстро привыкаешь объявлять все переменные в начале процедуры, это просто хороший тон.

Меня настораживает такое явление: Те люди, кто не стал программистами, Паскаль — забыли как страшный сон, а Бейсик — помнят и иногда используют для прикладных расчётов. Те же, кто стал программистами — просто знают несколько языков, и совсем неважно, с которого они начинали.
Мы говорим о Qiuck Basic и наследниках, где уже «всё как у людей» — IF / While, строки без нумерации?

P.S. В январе Вы критиковали один из Basic-ов:
где из переходов только GOSUB/GOTO и из циклов только FOR — то это может быть слишком оторвано от современности.
И чё? На нём же не проект писать, а чисто с алгоритмами экспериментировать.
Для чего-то более серьёзного — переходить на более актуальные языки.
Мы говорим о Qiuck Basic и наследниках

Естественно.

P.S. В январе Вы критиковали один из Basic-ов:

Критиковал тот, кого я процитировал. И речь шла о каком-то очень старом бейсике.
Кроме того, в своей защите этого языка, я несколько осторожничал. Сами знаете, чем чревато.
В 50-60 годы, происходил бурный рост программирования как научной дисциплины. К сожалению авторы языка Си, осознано или нет, выбросили все наработки мирового сообщества в мусорное ведро. Их сложно за это винить (тем более что сам Вирт не осмелился убрать GOTO из Паскаля), они хотели иметь Unix и написали себе компилятор так как могли, хотели, считали нужным. К сожалению Си распространился на столько, что теперь мы имеем бесконечные обновления безопасности программ, глюки, зависания. Невозможно найти качественного программного обеспечения (это не всё из-за Си, но львиная доля). Создание всевозможных «костылей» принципиально ни чего не решает. И многих, к сожалению, такое положение вещей устраивает. PS. Просто о Си заговорили. Автору спасибо за статью.
Думаю, не стоит винить C во всех бедах отрасли. В нём, безусловно, были прогрессивные черты (типа операции += или возможности передать в функцию массив произвольной длины, чего не было в Паскале). Однако C вырос из бестипового B, и отпечатки этого, к сожалению, видны до сих пор.

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

Вряд ли по кругу, в лучшем случае — по спирали. Язык B был бестиповым в абсолютном смысле: любая переменная была целочисленным «машинным словом», и более ничем. Язык был как-то пригоден только для системного программирования. Никакие численные расчёты были на нём невозможны.

Не лукавьте. Расчеты были возможны, но количество служебного кода… Зашкалило бы. Поэтому разработка вряд ли была бы эффективной или надёжной.
Насчёт спирали — да, можно и так назвать. Это не столь принципиально.

Ну да, на чистой машине Тьюринга принципиально тоже можно вести расчёты с плавающей точкой, если вы об этом.
Ну так, минуточку, абсолютно все языки программирования в своих прямых «математических» возможностях ограничены возможностями процессоров. Просто сейчас там есть FPU с 80-битными вещественными числами, матричные вычисления и целочисленная арифметика от 8 до 64 бит. А процессор PDP-11 ничего кроме этих 16-битных целых и не умел переваривать. В этом плане возможности тогдашнего С ничем не превосходили возможности В.
Все остальные вещи, будь-то математика, строковые операции и т.д., выполнялись с помощью внешних библиотек. Возможность использовать библиотеки в В имелась, возможность форматировать вывод в нужном виде также была. Поэтому он вполне себе подходил для повседневных задач начала 1970-х.
>Си распространился на столько, что теперь мы имеем бесконечные обновления безопасности программ, глюки, зависания.

(#sarcasm_mode_on) Но конечно же, если бы основная масса софта писалась на б-жественном Паскале, не было бы ни обновлений безопасности, ни глюков, ни зависаний.(#sarcasm_mode_off)

На самом деле — все указанные проблемы связаны с ростом спроса на софт и снижением качества софта в угоду скорости выпуска софта на рынок. Издержки массового производства. И использование «серебряной пилюли» в виде «единственно правильного ЯП, который точно принес бы счастье, но про него незаслуженно забыли» не решает эту проблему.
С очень много позаимствовал из Алгол-68, который был очень даже мощной наработкой всего мирового сообщества
Как человек, который все старшие классы, всё студенчество, и пару лет после кодил исключительно на Паскале/Делфи, переписывая нужный мне сишный код на свой любимый язык, но потом всё же перешедший к изучению (нормальных) языков из топ-десятки, могу сказать, что пытаться оживить труп смысла совершенно нет, кроме как для себя. Работодателей — пара штук всего.

Язык операционных систем — С/С++, и пишем мы всё под операционные системы, ну или под железо, у которого вендорский код либо сишный, опять же, либо азм.

Язык для обучения в школе? Имея на плечах опыт кодинга на разных языках, вижу идеальными языки Го и Питон, т.к. на них проще всего уделять больше времени логике, нежели работе с синтаксисом языка.

Очевидный плюс Дельфы: непревзойдённый пока редактор графического интерфейса, да. И именно он меня привлекал когда-то. Но это не так страшно:)
Увы, со многим вынужден согласиться. Однако вы говорите скорее о состоянии индустрии, чем о достоинствах языков как таковых. Я не думаю, что индустрия несёт высшую справедливость и всегда воздаёт языкам по их достоинствам. Тот же Паскаль сам по себе не имеет никаких неисправимых пороков, которые помешали бы ему при должном развитии сравняться по мощи с современным С++. Но для этого была бы нужна воля корпораций — не только сейчас, но и в прошлом. Стоило Паскалю в 80-х годах чуть опоздать с возможностями системного программирования, и вот уже все ключевые операционные системы написаны на C, а Паскаль вынужден вечно догонять.
>а Паскаль вынужден вечно догонять

Тогда зачем заниматься некромантией, ну, кроме разве что just for fun? Все равно масштабного использования результатов, «Паскаль-экосистемы», которая бы имела шансы на конкуренцию с существующими, уже не будет.

Дизайнер форм Qt мог бы с этой непревзойденностью неслабо поспорить.

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

Потому что по сути его поддерживал только один вендор — Борланд.
Или хотите дальше копнуть?

Ну, а сколько вендоров изначально поддерживали, например, Джаву или C#. И да, хочу копнуть дальше.
Я считаю, это потому, что от Паскаля отвернулась основная масса хакеров (в реймондовском смысле — то есть, копателей на самые глубины).
Паскаль очень активно продвигался в 80-е: был Паскаль от Apple (и у них была первая объектная реализация — Borland уже копировал её идеи, хотя они все следовали за ранним C++), был от Microsoft (и очень неплохой, и совместимый с Borland по многим фичам — это редко упоминают, что они синхронизировались).
Но всё это сорвалось: он перестал быть привлекательным для тех, кто оказался тут ключевым. Я писал несколько раз его проблемы, как их вижу по результату обучения других — и мне кажется, что именно подходы типа «вам это не позволено» стали главными в его падении.
Ряд свойств паскалевского стиля был бы крайне полезен и сейчас — например, порядок слов в объявлениях. Но это надо ждать следующей волны языков…
Скачал компилятор для DOS, прочитал документацию по диагонали. Возможностей работы со звуком не обнаружил. Они есть? Спасибо.
А какие возможности вы хотели бы видеть? Если мне не изменяет память, в Turbo Pascal была только процедура Sound, управляющая PC Speaker'ом. Если вам нужен именно он, то можете управлять им напрямую путём записи в системные порты. Для этого в XD Pascal, как и в Turbo Pascal, есть процедура OutP.
А для микроконтроллеров компилятор паскаля писать не пробовали? Там с Виртовскими языками страшный дефицит.
Нет, не пробовал. Знаю только, что мой компилятор для DOS какие-то поляки портировали на Atari с процессором 6502. Сам немножко работал с Паскалем для 8051, но быстро забросил. Если уж такой компилятор и делать, то уже не игрушечный, а тогда придётся использовать LEX/YACC/ANTLR/LLVM и т.д.

LLVM — да, а вот насчёт LEXX/YACC… Насколько я знаю (но это больше с чужих слов), как раз в неигрушечных компиляторах они, как правило, и не используются.


Они удобны — и мой небольшой опыт это подтверждает — 1) когда невысоки требования к обработке ошибок и вообще работе с невалидным исходным кодом, 2) когда язык только разрабатывается и нужно иметь возможность многократно и кардинально переделывать грамматику.


А при написании полноценного компилятора, с одной стороны, они не особо и помогают (если использовать LL-парсер — он легко пишется руками), а с другой создают лишние проблемы (отдельный язык, влекущий проблему сопряжения с ним; пляски когда надо сделать что-то хоть чуть-чуть нестандартное).

Плюс использования lexx/yacc в том что грамматика вашего языка будет LALR(1), а не ад типа Perl 5, который вообще undecidable.

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

Walter Bright, создатель первого полноценного компилятора C++ и автор языка D писал, что
There are a few things I (perhaps surprisingly) suggest should not be considerations… Easy parsing. It isn’t hard to write parsers with arbitrary lookahead. The looks of the language shouldn’t be compromised to save a few lines of code in the parser. Remember, you’ll spend a lot of time staring at the code. That comes first.

…Somewhat more controversial, I wouldn’t bother wasting time with lexer or parser generators… They’re a waste of time. Writing a lexer and parser is a tiny percentage of the job of writing a compiler.


Мой очень скромный опыт тоже подтверждает эту мысль. Написание LL-парсера вручную не является особой проблемой. Гораздо больше сил уходит на все остальное.
Откуда дефицит? Есть и Паскали и Обероны.
На MSP430 например нет (можно найти только упоминание о нем).
Oberon 07 вроде работает с частью микроконтроллеров успешно

Я уважаю ваш труд и считаю проект интересным, но:

Если повезёт, XD Pascal будет внедрён, наряду с BeRo Tiny Pascal, в лабораторный практикум по курсу конструирования компиляторов в МГТУ им. Н.Э. Баумана.
Это очень плохая идея. Хорошее методическое пособие должно быть простым и прививать правильные подходы. Вы же развивали компилятор, исходя из личной любви к Паскалю, и сделали несколько очень спорных дизайн-решений, если не сказать костылей, из-за которых проект нельзя использовать как пример для подражания:
при каждом проходе заново повторяются все этапы компиляции, начиная с лексического разбора.
Вычисление любых выражений в XD Pascal строится так, что все промежуточные результаты имеют длину 32 бита и сохраняются в стеке. Для строк и множеств Паскаля этот подход неприемлем.
Для самых употребительных процедур, в том числе Read и Write, я сделал исключение и реализовал их нетипичными для грамматики языка
Возьмите лучше специально разработанный для этого минимальный язык\компилятор, типа ChibiCC.
Коллега, я призываю не торопиться с выводами. На той кафедре, о которой идёт речь (а это вовсе не моя родная кафедра и курс веду не я), сейчас для некоторых лабораторных работ используются компиляторы Паскаля P5 и BeRo Tiny Pascal. Речь там вовсе не идёт о каких-то образцах для подражания. Студентам предлагается всего лишь вносить точечные изменения в готовый компилятор и наблюдать их эффект после «раскрутки» (bootstrap'а). Кто-то из студентов на курсовой может заняться и более масштабной задачей (например, была работа по портированию BeRo на Linux). Подробнее об этом можно прочесть тут. Там есть и примеры заданий. Если вы видите какие-либо недостатки XD Pascal в сравнении с BeRo, я с интересом вас выслушаю.

Вы отчего-то не задались вопросом, как именно построен учебный процесс и как именно предполагается применять компилятор, и почему-то спешите предложить компилятор C вместо Паскаля и, кажется, даже без самокомпиляции. Далее, вы неизвестно почему видите недостаток в том, что «для самых употребительных процедур, в том числе Read и Write, я сделал исключение и реализовал их нетипичными для грамматики языка». Однако эти процедуры в Паскале действительно нетипичны для грамматики (принимают любое количество любых аргументов) и действительно требуют реализации как особого случая, что я и сделал. Упрекать же за отсутствие поддержки множеств в любительском компиляторе, ей-богу, чрезмерно.

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

Иэ это, кстати, очень уродующая язык штука. Я в своё время из-за этого на С и перешёл: пусть printf и сложен и неудобен, но зато всё честно, а это важно для душевного здоровья программиста.

Соглашусь, в этом есть какое-то коварство. И если бы дело ограничивалось только Read и Write, было бы не так тяжко. Но таких процедур оказываются десятки. Конечно, хотелось бы видеть грамматику Паскаля сразу достаточно гибкой для того, чтобы списки аргументов Read и Write укладывались в эту грамматику и не торчали бы неудобными исключениями.
Но зачем?

К сожалению, в языках вечно чего то не хватает, и создатели добавляют то атрибуты то трейты…

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

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


Но это не значит, что так как сделано в Паскале — это единственный выход. Есть и другой: не иметь функций с переменным числом параметров ни в каком виде, а проблему удобного ввода-вывода решать иначе. Так сделано в Rust (ипользуются макросы), так сделано в современном C++ (используются темплейты). И решение из C# также может быть доведено до статического-типизированного (params IFormattable[] args вместо params object[] args), хотя оверхед из-за динамической диспатчеризации останется.

Если разрешить на уровне языка определение процедур с произвольным количеством формальных параметров ( да ещё и с произвольными типами аргументов ). В этом случае вся статика летит к чертям.
Зачем же с абсолютно произвольными?

Objective Modula-2
Calling a Variadic Procedure
Index arguments and value terminating arguments are never supplied in the actual parameter
list of a variadic procedure call. The compiler automatically determines and
inserts these arguments into the procedure’s activation record.
(* calling procedure Variadic from Listing 14 *)
Variadic( (* counter omitted *) foo1, bar2, foo2, bar2 );
(* calling procedure Variadic from Listing 15 *)
Variadic( foo1, bar1, foo2, bar2 (* -1 omitted *) );
Listing 16: variadic procedure calls omit index and value terminating arguments


Variadic Procedures with Counter Terminated Variadic Parameter Lists
The number of variadic parameters of a counter terminated variadic parameter list is
automatically passed as a hidden parameter immediately before the variadic list.
PROCEDURE Variadic(v : VARIADIC OF (p1 : Bar; p2 : Baz));
BEGIN
  (* iterate over all variadic tuples by index *)
  FOR n OF CARDINAL := 0 to HIGH(v) DO
    DoSomethingWithBar(v[n].p1);
    DoSomethingWithBaz(v[n].p2);
  END; (* FOR *)
END Variadic;
Listing 14: procedure with a counter terminated variadic parameter list

Variadic Procedures with Value Terminated Variadic Parameter Lists
A value terminated variadic parameter list is terminated by a given constant value.
PROCEDURE Variadic(v : VARIADIC [-1] OF (p1 : INT; p2 : Baz));
BEGIN (* v points to first variadic tuple *)
  WHILE v # NIL DO (* while there are tuples *)
    DoSomethingWithINT(v^.p1);
    DoSomethingWithBaz(v^.p2);
   v := NEXTV(v); (* next variadic tuple *)
  END; (* WHILE *)
END Variadic;
Listing 15: procedure with a value terminated variadic parameter list


В Modula-2 R10 ( в варианте M2Sharp) чуть менее наглядно:

( newVector и PrintList — разные функции; не стал исправлять, привёл 1 к 1, как в первоисточнике )
Variadic Parameters

The extended dialect supports the ARGLIST attribute in formal types and formal parameters. Parameters marked with the ARGLIST attribute may be passed a variable number of arguments.

PROCEDURE newVector ( values : ARGLIST OF REAL ) : Vector;

VAR v1, v2, v3 : Vector;

v1 := newVector(1.2, 3.4); (* two arguments *)
v2 := newVector(1.2, 3.4, 5.6); (* three arguments *)
v3 := newVector(1.2, 3.4, 5.6, 7.8); (* four arguments *)


Within the procedure or function, the argument count may be obtained using built-in function COUNT and the arguments are addressable using array subscript notation.

PROCEDURE PrintList ( values : ARGLIST OF REAL );
VAR index : CARDINAL;
BEGIN
  FOR index := 0 TO COUNT(values)-1 DO
    WriteReal(values[index]);
    WriteLn
  END
END PrintList;
Зачем же с абсолютно произвольными?

В начале обсуждения об этом написано.
Вот, например, в Активном Обероне есть встроенная процедура TRACE, которая принимает любое количество параметров любых типов, и распечатывает их в системный лог ).
TRACE( «Hello», 123, 1.5, NIL );
Она реализована в компиляторе, потому что на уровне языка такое не определишь.
Если все параметры одного типа, то и изобретать особо ничего не нужно — достаточно открытых массивов и массивов-литералов.
Например:
PROCEDURE P( CONST args: ARRAY [ * ] OF HUGEINT );
и вызов
P( [5, 78, 3758, 383489, 585959, 5785759 ] );
можно даже определить так:
PROCEDURE P( CONST args: ARRAY [ * ] );
И тогда процедура будет принимать массивы с любым типом элементов, но это не решит проблему разнородности типов аргументов, которая, к примеру, в Delphi решается с помощью массива вариантов.
Я когда-то писал для нашего программного комплекса (ПК МВТУ-3 и МВТУ-4 (SimInTech)) свой встроенный язык — что-то среднее между Pascal и Matlab, думал тогда сделать его с JIT-компиляцией, но обошёлся тогда псевдокодом, сейчас вот думаю может допилить генерацию машинного кода для скорости ибо программа активно используется во многих местах и скриптов там написано очень много. Конкретно мне было бы интересно обеспечить оптимизированную генерацию кода для исполнения в оперативной памяти для скалярных математических выражений без лишних вызовов подпрограмм как минимум на x86 архитектуре. Сам программный комплекс у нас на Delphi написан исторически. Вы не пробовали сделать на базе вашего компилятора встраиваемую скриптовую машину с компиляцией в оперативную память? Это могло бы быть интересным.
Задача, о которой вы говорите, всё-таки очень специфична. Я всегда ориентировался только на классические исполняемые файлы.
Не знаю, чего народ в этом Паскале нашел. Писал на нем еще в школе потом немного в институте, громоздкий в плане синтаксиса и устаревший язык, одни begin-end чего стоят. На С++ в свое время перешел с удовольствием. Сейчас никакой ностальгии и желания писать на нем снова не испытываю.

Если повезёт, XD Pascal будет внедрён, наряду с BeRo Tiny Pascal, в лабораторный практикум по курсу конструирования компиляторов в МГТУ им. Н.Э. Баумана.

Риторический вопрос, почему российское образование всегда оторвано от реальной жизни…

Нет бы на «конструировании компиляторов» какую-нибудь кодогенерацию для реально работающих микроконтроллеров или плис рассмотреть, нет, нужно что-то обязательно архаичное и нежизнеспособное :) Специально чтобы каждый студент чувствовал, что нигде кроме пар ему это в жизни не пригодится.
Свои аргументы в пользу Паскаля и против C я высказал выше. Это, конечно, сугубо академический разговор о самих языках, а не об их востребованности в индустрии. «Громоздкость» языка оборачивается предельной лёгкостью чтения на нём, что немаловажно, если вспомнить завет Гвидо ван Россума: «Code is read much more often than it is written». «Устарелость» языка — это следствие, а не причина его ухода из индустрии.

Что касается образования, то курс вовсе не ограничивается упражнениями с простенькими компиляторами Паскаля. Вы же не станете утверждать, что нужно перестать преподавать черчение на бумаге, взятие интегралов на бумаге, расчёт прочности балок на бумаге и т.п. лишь потому, что это нечто «архаичное и нежизнеспособное»?
Я к тому, что студенты прекрасно понимают и чувствуют, когда им дают что-то, что никогда не пригодится в реальной жизни. И на мотивацию к изучению это отлично влияет. Можно же найти что-то для учебных примеров, что реально используется в продакшене прямо сейчас, а не нечто из прошлого века…
Найти в production'е самокомпилируемый компилятор, который студенты на первой же лабе смогут изучить, модифицировать, «раскрутить» и посмотреть эффект? Не очень понимаю, что это могло бы быть.
А требование самокомпиляции и генерации exe является критичным? Так-то, можно хоть Lua для Ардуино компилировать, вполне пригодится для задачи домашней автоматизации.
Насколько я понимаю, принципиальной является «раскрутка» (bootstrap). Как бы то ни было, курс веду не я. Я просто предложил свой проект как альтернативу BeRo Tiny Pascal.
Современная реинкарнация Project Oberon от Вирта. Там вообще весь стэк хелловордный — язык описания аппаратуры с компилятором, простейший процессор в ПЛИС, хелловордный яп Оберон-07, с таким же простейшим компилятором, хелловордная ОС Oberon-V. Ну и есть эмуляторы Виртовского процессора на Си, Дельфи, Обероне, Питоне. Впрочем, есть модификации компилятора и под реальное железо. Ну и в придачу книжки «Project Oberon The Design of an Operating System, a Compiler, and a Computer» и «Compiler Construction».
UFO just landed and posted this here

Мне нравится, когда говорят о Си, как о виртуальной машине. Ибо действительно, если бы он однозначно компилировался в ассемблер, то не было возможности для UB. Получается, что на самом деле, он достаточно высокоуровневен, чтобы на нем нельзя было гарантировать последовательность исполнения и результат исполнения ЛЮБОЙ (не обязательно корректной!) программы на Си, и достаточно низкоуровневен, чтобы была возможность отстрелить себе руки и ноги из-за магии битиков.
Но вообще это мне не мешает любить этот язык, т.к. он реально прекрасен своей лаконичностью и своим распространением.


А, да, еще дичь в Си — это триграфы. Это к вопросу о скобочках и т.п., что иногда может тоже отсрелить обе ноги и обе руки.

Возникала, и не раз. Вопрос в целях. Мне доставляло удовольствие знать каждый байт своего компилятора. Использование LLVM — это уже профессиональный размах. Но тогда проекту подобает иметь и профессиональный frontend. Да и нужен ли тогда Паскаль? Может быть, взять Clang? Так, шаг за шагом, от проекта ничего и не осталось бы :)
Да и нужен ли тогда Паскаль?

Почему же? Пусть будет больше языков хороших и разных. С компиляцией в разные байткоды.
Теперь реализован перемещаемый код и благодаря этому — однопроходная компиляция.
Нововведения в компиляторе с момента публикации поста:

  • Множества
  • Строковые операции
  • Процедурные переменные
  • Процедуры Break, Continue, Exit
  • Открытые массивы
  • Вызов функций как процедур
  • Нетипизированные аргументы
  • Однопроходная компиляция
  • Быстрый лексический разбор

Sign up to leave a comment.

Articles