Comments 30
Это значит
а затем заставит Лисп прочитать полученный список:
с использованием лисповского парсера S-выражений — функции input.
Это же очень смелое предположение: что пользовательская (т.е. произвольная) строка на входе — S-выражение.
И более того: что правильная строка на входном языке (с точностью до пробелов, так и быть) — одновременно является S-выражением.
В недобейсике, максимально комфортном для лиспа, — только дисбаланс скобок.
Причём, раз мы разбираем файл построчно, — возникает ограничение на синтаксис языка: каждая строка должна быть законченным выражением. Перенос формул, как это, например, в питоне или делается, — с незакрытыми скобками, — уже будет невозможен.
Но, в перспективе, возникают следующие проблемы:
Вместо линейного списка токенов мы получаем структурированное выражение; с одной стороны, нахаляву нашли парные скобки, а с другой — никакие другие скобки (квадратные там, фигурные, словесные begin-end всякие) мы нахаляву не нашли. Всё равно придётся делать обрабочики.
К тому же, часть токенов у нас представлена атомами, а часть (а именно, скобки) — не атомами, а структурой. Негомогенненько!
Если синтаксис допускает непарные скобки (например, забавный синтаксис case в баше), то облом с построением S-выражений будет штатной ситуацией, не свидетельствующей об ошибках на входе.
Если мы добавим строковые литералы, несовместимые по синтаксису с лиспом, — то они рассыплются на произвольные куски. А там ещё и скобки могут попасться.
Одно и то же S-выражение можно записать по-разному. Например, одноэлементный список (a)
эквивалентен конс-паре (a . nil)
Из этого следует, что нескольким разным входным строкам может соответствовать одно и то же S-выражение.
И ещё из этого следует, что некоторые заведомо неправильные с точки зрения синтаксиса целевого языка строки будут ошибочно приняты за правильные. (А для некоторых целевых языков возможна обратная ситуация: правильную строку превратили чёрт знает во что — и хорошо, если это просто приведёт к ложному обнаружению ошибки).
Слишком много всяких оговорок получается. Не проще ли было, сделав разбивку строки на токены, просто взять и каждый токен приводить к атому?
Чтобы обрабатывать строки, нужно — да — усложнить парсер. Поэтому я и написал в постановке: «Работаем с числами». То же относится и к проблеме переноса (правда не оговоренной явно).
И уж совсем непонятно, при чем здесь точечная нотация.
При чём точечная нотация? Да при том, что ваш интерпретатор недобейсика схавает выражение вида "(1.NIL)2", думая, что это "(1)2".
А также при том, что выражение вида "(1. 2)" приведёт интерпретатор в недоумение — он ведь ожидает, что ему на вход подаются многоуровневые списки, но никак не конс-пары с CDR, который атом, но не NIL.
Вот кстати насчёт разумной достаточности. GENSYM из CL позаимствовали, а почему INTERN забыли? Ведь явно же в недрах INPUT используется нечто подобное.
Тогда вместо колдунства с переклеиванием и переразбором строки было бы просто
(maplist lex intern)
Ну вот же возникла необходимость! И вместо того, чтобы сделать intern публичной функцией, нагородили хорошо известный антипаттерн уязвимости.
Уязвимости ДЛЯ всего. Про Бобби Дроптейблза знаете?
https://xkcd.ru/327/
Вот что значит «мыслить шаблонами...»
А конкретнее — это плохая практика. И даже в учебных целях — а тем более в учебных целях — не надо кормить интерпретатор произвольными данными.
Понятно, что ваш калькулятор безобидный… до поры до времени.
В одном месте кода вы делаете допущение, что на входе — совместимый с очень узким подмножеством лиспа DSL.
В другом месте — положитесь на это допущение и, например, замените DSL-ные операторы на лисповые функции (ну логично же было бы превратить "(1 + (2 3))" в "(+ 1 ( 2 3))"… Либо ваши студенты сделают это за вас.
И так, потихоньку-полегоньку, дырка расползётся.
И вам в конце придётся доказывать с покрытием кода, что никакой трэш на входе не приведёт к вызову никаких произвольных лисповых функций, например, форматирования винчестера.
Я за вас эту работу делать не хочу. Вектор атаки я указал, а каких погромов он может достичь, это пусть хакеры расследуют.
Вместо того, чтобы с самого начала не делать так, что трэш просто не пройдёт синтаксическую проверку (именно DSL, а не синтаксическую проверку лиспа).
Я ваш диалект лиспа учить и использовать всё равно не собираюсь, поэтому просто обозначил идею.
А хелп на него — ужасный. Но это предмет для отдельных обсуждений.
Я на разных лиспах в студенческие годы писал всякую мелочёвку. И держать эту тьму диалектов в голове не хочу.
А уж тем более — выискивать отличия между вашим диалектом и коммонлиспом.
Но судить о том, хороший хелп или херовый — могу квалифицированно.
Ваш хелп — херовый.
Где, например, глобальное оглавление?
Вы всё рассовали по рубрикам, и пойди думай, в какой рубрике что искать. То, что intern нет ни среди "строковых" функций, ни среди "встроенных функций стандартного лиспа", — не значит, что её нет нигде. Только полным перебором можно обнаружить этот печальный факт.
То, что вы родили not-invented-here диалект лиспа, — требует пояснений, чем этот диалект отличается от прототипа. От коммонлиспа, или от схемы, или от чего ещё вы его форкнули?
Где это в хелпе? Или — пусть студенты учат то, что им дают? А потом попереучиваются на коммонлисп, схему, емакс или вообще автолисп?
Довод "сам дурак" принят. Окей.
Хорошо сказал Малыш из известной книги: «Не всем же быть понятливыми».
Ну выходит, что неправы.
Мы начали с того, что вы вместо публичной реализации стандартной коммонлисповской функции intern были вынуждены писать велосипед с уязвимостями.
Это первый и очевидный "не так".
Пока разбирался, полез читать хелп и увидел второй жирнющий "не так".
Но вы сочли, что нападение — лучшая оборона, и перешли на обсуждение моих компетенций.
Я в эту игру тоже умею играть. Что вы на вашем лиспе написали, кроме учебного материала для ваших студентов?
Если я кого-то критикую, то делаю это корректно. Без пренебрежения и хамства. А нарвавшись на таковое — отвечаю адекватно. Ваше мнение — всего лишь одно из мнений, а не истина в последней инстанции (как вы, вероятно, думаете).
Играть с вами по вашим правилам (и тем более обсуждать Лисп, help и прочее) я не собираюсь. Вы свое мнение высказали — и успокойтесь.
Интересная статья, но в реальной жизни для такой задачи часто берут flex и bison
В реальной жизни для такой задачи часто берут flex и bison
Что вы, это же магические орудия древних — причём, суда по генерируемому ими коду, предназначенные для ритуальных пыток. Лучше уж ragel и lemon.
Пишем простой транслятор на Лиспе — I