О PL/1 и почему в нём не зарезервированы ключевые слова
Я обучался программированию на языке PL/1. Это было формальное обучение, я должен был оцениваться на каждом этапе и
продвигаться по служебной лестнице программиста-стажера, помощника программиста, младшего программиста,
в конечном итоге достигая старшего программиста через несколько лет.
Оглядываясь назад, понимаю, что тогдашние мои наставники были одними из лучших разработчиков программного обеспечения, с которыми я когда-либо работал, но в те дни титула «разработчик программного обеспечения» еще не существовало.
Обучение включало в себя письменные и устные контакты, определение повестки дня совещаний и председательство на совещаниях, написание спецификаций, оценку алгоритмов и, конечно же, глубокое понимание языка PL/1, используемого на «мэйнфреймах» IBM.
В то время Си был академическим языком с очень небольшим присутствием в коммерческом мире, Паскаль был более распространен, чем Си, но в то время тремя основными языками были COBOL, Fortran и PL/1. У меня был выбор в колледже специализироваться на одном из этих трех, и после некоторых исследований в библиотеке, это не стало проблемой для такого технически склонного человека, как я, поскольку PL/1 был существенно более продвинутым, чем другие.
Вот некоторые не очень известные факты об этом языке:
-
До сравнительно недавнего времени оптимизирующий компилятор IBM PL/1 был самым сложным из существующих компиляторов.
-
PL/1 был первым языком высокого уровня, используемым для написания операционной системы (Multics).
-
PL/1 был первым языком, использующим /* */ для комментариев.
-
PL/1 был первым языком, который использовал термин «статический» для хранения переменных, не связанных со стеком.
-
Это был первый язык, который обрабатывал исключения на основе стековых фреймов (называемых «условиями», т.е. condition).
-
Это единственный язык программирования, в котором нет зарезервированных слов.
-
Это был первый язык, компилятор которого был написан на этом языке.
-
Это был первый язык, который использовал нотацию -> для указателей.
Как язык системного программирования он значительно превосходил Си, а написание компиляторов и операционных систем на языке PL/1 давало ряд преимуществ с точки зрения надежности, производительности и технического сопровождения.
Я написал почти полный компилятор PL/1 в Си для Windows NT (32-битный COFF) и до сих пор имею весь исходный код (реализация для Visual Studio 2005).
Способность парсера поддерживать требование «никаких зарезервированных слов», хотя и очень мощная, не слишком сложна, вот как это делается.
На самом деле в языке существует только два вида операторов: операторы с ключевыми словами и операторы присваивания.
Оператором с ключевым словом может быть почти любое выражение языка, типа: call log_fault; или, например, do while (flag = FALSE);
Оператор присваивания всегда имеет вид <ссылка> = <выражение> ;
Таким образом, синтаксический анализатор просто решает, является ли оператор присваиванием или нет, если это так, то ключевые слова не имеют значения, а идентификаторы могут быть любыми.
Вот почему PL/1 позволяет Вам кодировать, что-нибудь вроде:
if then then else=then; else then=if;
Грамматика очень мощная, и Вам не нужно «==» для сравнения, как в Си, достаточно только одного «=» для присвоения и сравнения.
Кстати, причина, по которой PL/1 поддерживает это, заключается не в том, чтобы позволить Вам писать сбивающий с толку код, а в том, чтобы позволить вводить новые ключевые слова в будущем, не нарушая существующий код.
Очень полезная статья о реализации компилятора PL/1 была написана Бобом Фрейбургхаузом в 1969 году,
и вот ещё одна увлекательная статья, которая подробно рассказывает о том,
как язык был выбран в качестве основы для Multics.
Статья Боба была чрезвычайно полезна мне, когда я начал описывать дизайн и общий подход к моему собственному компилятору PL/1,
любой, кто интересуется компиляторами, их реализацией и историей, должен ценить эти источники.
Автор: Hugh Gleaves, 23.11.2013.
Перевод: Д.Ю.Караваев. 27.07.2020
Опубликовано: 2020.07.27, последняя правка: 2020.07.27 20:34
Отзывы
✅ 2020/07/27 23:25, Австор сайта #0
До сравнительно недавнего времени оптимизирующий компилятор IBM PL/1 был самым сложным из существующих компиляторов. Мне кажется, компилятор Алгол-68 (если вести речь о языках 1960-70-х годов) был куда сложнее. Настолько сложнее, что первые его компиляторы появились аж лет 10 спустя после утверждения стандарта.PL/1 был первым языком, который использовал термин «статический» для хранения переменных, не связанных со стеком. Конечно, это преимущество. Но странно говорить о нём, когда в архитектуре IBM/360 (с которой начинался PL/1) концепция стека вообще не реализована.Это был первый язык, компилятор которого был написан на этом языке. Это вовсе не так. Впервые раскрутка компилятора была применена для языков ассемблера. Первым компилятором с применением техники раскрутки для языка высокого уровня был компилятор для Neliac — диалекта языка Алгол-58. Уж поверьте мне хотя бы потому, что 80% текста этой статьи в Википедии — мои.Вам не нужно «==» для сравнения, как в Си, достаточно только одного «=» для присвоения и сравнения. Целую статью посвятил этому: Операции присвоения и проверки на равенство. Возможно ли одинаковое обозначение?. Что бы ответил автор статьи, если дал ему такое задание на засыпку: переопределить операции присвоения и проверки на равенство, использующих одинаковое обозначение?На самом деле в языке существует только два вида операторов: операторы с ключевыми словами и операторы присваивания. Спорное утверждение, при том я PL/1 основательно забыл. f(g(h(x))); /* нет ни ключевых слов, ни присваивания */ Или правильно так? CALL f(g(h(x))); Оператором с ключевым словом может быть почти любое выражение языка, типа: call log_fault; или, например, do while (flag = FALSE); Оператор присваивания всегда имеет вид <ссылка> = <выражение>; Таким образом, синтаксический анализатор просто решает, является ли оператор присваиванием или нет, если это так, то ключевые слова не имеют значения, а идентификаторы могут быть любыми. Я понимаю, что в PL/1 свои порядки. И со своим уставом в чужой монастырь не лезут. Но возьмём такой пример, когда if в одном случае является идентификатором переменной, а в другом — ключевым словом. if = (if A; B else C) /* если A истинно, то переменной if присвоить значение B; иначе переменной if присвоить значение C */ Есть подозрение, что грамматика современных распространённых языков вызовет трудности у анализатора. Хотя у Дмитрия Юрьевича есть практический опыт преодоления неоднозначностей в своём компиляторе :) Наверное, будет уместным спросить самого Дмитрия Юрьевича: как ключевые слова отличить от обычных идентификаторов и насколько эти приёмы применимы к другим языкам?✅ 2020/07/30 11:04, kt #1
Я думаю, преувеличения «первый» вместо «один из первых» и т.п. происходят от того, что в 60-70 была очень слабая связь между разработчиками. Многие были просто не в курсе, что происходит в разных фирмах. Про ключевые слова я писал давно, ещё в статье «Да здравствует ПЛ!». Структура языка такова, что все должно начинаться с ключевых слов. Кроме метки и присваивания. Поэтому предварительный просмотр пытается дойти до двоеточия или равенства вне скобок. Т.е. найти метку или присваивание. Иначе — это ключевое слово. Все получается довольно изящно и просто. И я выкинул необходимость слова CALL и тоже ничего не сломалось. Правда, при ошибках, вместо «неописанный идентификатор» теперь идет сообщение «неописанная процедура». Но на этом и все. При этом выражения типа if = (if A; B else C); в языке были изначально недопустимы. Интересно, что другой автор в статье «В защиту PL/1» считает эту философию ошибочной и называет незарезервированные слова «бородавками языка». Т.е. он не понимает, что цель была — добавление новых ключевых слов без изменения уже созданного ПО. Пример — я легко добавил русские ключевые слова и старое ПО не нужно было менять. Я не считаю это ошибкой и бывали случаи, когда забывал, что есть такое ключевое слово и использовал его как идентификатор. Все нормально проходило. Но сейчас в ряде случаев, компилятор все-таки предупредит, что какая-нибудь GAMMA есть как встроенная функция языка. При этом код сгенерируется для GAMMA-идентификатора. На всякий случай для разрешения подобных случаев имеется атрибут BUILTIN Добавить свой отзыв
Написать автору можно на электронную почту mail(аt)compiler.su
|