Pull to refresh

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. Если возникнет необходимость. Но к теме статьи это не имеет прямого отношения. Тема статьи — показать, что написать транслятор «Бэйсик-Лисп» на лиспе нетрудно.

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

Про уязвимости SQL я в курсе. Но функция input не вычисляет выражение (не передает его ядру); она берет строку и переводит ее в лисповскую форму. В чем же уязвимость?

Вот что значит «мыслить шаблонами...»

А конкретнее — это плохая практика. И даже в учебных целях — а тем более в учебных целях — не надо кормить интерпретатор произвольными данными.


Понятно, что ваш калькулятор безобидный… до поры до времени.
В одном месте кода вы делаете допущение, что на входе — совместимый с очень узким подмножеством лиспа DSL.
В другом месте — положитесь на это допущение и, например, замените DSL-ные операторы на лисповые функции (ну логично же было бы превратить "(1 + (2 3))" в "(+ 1 ( 2 3))"… Либо ваши студенты сделают это за вас.
И так, потихоньку-полегоньку, дырка расползётся.
И вам в конце придётся доказывать с покрытием кода, что никакой трэш на входе не приведёт к вызову никаких произвольных лисповых функций, например, форматирования винчестера.
Я за вас эту работу делать не хочу. Вектор атаки я указал, а каких погромов он может достичь, это пусть хакеры расследуют.


Вместо того, чтобы с самого начала не делать так, что трэш просто не пройдёт синтаксическую проверку (именно DSL, а не синтаксическую проверку лиспа).

Что-то сомневаюсь, что maplist могла пригодиться (даже если бы в HomeLisp был бы реализован intern). К тому же она у вас неправильно вызвана (функция должна идти первым параметром).

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

Плохо вы «обозначили идею». У меня складывается впечатление, что вы и лисп-то не знаете, раз mapcar путаете с maplist.
Я в большом горе по поводу того, что вы «отказываетесь использовать мой диалект». Но обсуждать с вами мой хелп считаю довольно бессмысленным занятием. Сначала выучите лисп (хотя бы до студенческого уровня), а там видно будет…

Я на разных лиспах в студенческие годы писал всякую мелочёвку. И держать эту тьму диалектов в голове не хочу.


А уж тем более — выискивать отличия между вашим диалектом и коммонлиспом.


Но судить о том, хороший хелп или херовый — могу квалифицированно.
Ваш хелп — херовый.
Где, например, глобальное оглавление?
Вы всё рассовали по рубрикам, и пойди думай, в какой рубрике что искать. То, что intern нет ни среди "строковых" функций, ни среди "встроенных функций стандартного лиспа", — не значит, что её нет нигде. Только полным перебором можно обнаружить этот печальный факт.
То, что вы родили not-invented-here диалект лиспа, — требует пояснений, чем этот диалект отличается от прототипа. От коммонлиспа, или от схемы, или от чего ещё вы его форкнули?
Где это в хелпе? Или — пусть студенты учат то, что им дают? А потом попереучиваются на коммонлисп, схему, емакс или вообще автолисп?

«Я на разных лиспах в студенческие годы писал всякую мелочёвку.» И дальше мелочевки, похоже, и не пошли. Ваша критика имеет в подоплёке интеллектуальную импотентность.
Но разве я не прав? Мне попадались такие критики, как вы… «Мне непонятно, где там у вас...» и далее с непередаваемым апломбом (будто бы владеет Истиной) — «Это не так! То — не так!»
Хорошо сказал Малыш из известной книги: «Не всем же быть понятливыми».

Ну выходит, что неправы.


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


Это первый и очевидный "не так".


Пока разбирался, полез читать хелп и увидел второй жирнющий "не так".


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

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

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

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

Интересная статья, но в реальной жизни для такой задачи часто берут flex и bison

В реальной жизни для такой задачи часто берут flex и bison

Что вы, это же магические орудия древних — причём, суда по генерируемому ими коду, предназначенные для ритуальных пыток. Лучше уж ragel и lemon.

Будет интересно, если вы покажете, как решается эта задача с применением указанных средств.
Sign up to leave a comment.

Articles