|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
Пишем свой интерпретатор языка BASIC20.06.2009, 20:03. Показов 253448. Ответов 464
Метки нет (Все метки)
Благодаря форуму и Evg в частности интерпретатор развивается, потихоньку превращаясь в простенький интерпретатор QBASIC.
Некоторые из самых старых версий сохранились в теме и ссылки на них будут добавлены в это сообщение,а также ссылки на другие темы,связанные с этой. Репозиторий с проектом находится тут, там же есть возможность в браузере посмотреть историю ревизий (английский в логах весьма примитивен,комментарии и рекомендации можете писать в личку),а также скачать самый последний архив репозитория в формате .tar.gz Если кто-то пользуется Subversion,скачать исходники можно так:
Технический приём для формирования согласованных данных https://www.cyberforum.ru/c-linux/thread46096.html Вопрос по svn (Subversion) Создание системы тестирования ПО. Вопрос про разные реализации бэйсиков Можно ли выразить порядковый номер элемента массива через индексы? [C++] Какие флаги указать линкеру для компиляции программы? Как можно определить переменную в файле configure.in,чтобы её можно было использовать в Makefile? Странный SIGSEGV, или что зависит от порядка написания интерфейса класса https://www.cyberforum.ru/c-linux/thread61324.html Альтернативная версия интерпретатора от Evg на C Это простая реализация разбора выражений, написанная Evg на C: Представление выражения в двоичном дереве ***************** Первое сообщение: ***************** Задание(Страуструп,из книги,по готовому коду): Введите программу калькулятора и заставьте её работать.Например,при вводе
LexicalAnalyzer.h
LexicalAnalyzer.cpp
main.cpp
Анализатор-то работает,но конечное значение не вычисляется.Более того,если вводим
Добавлено через 2 часа 5 минут 30 секунд Пришлось решать влоб с дебаггером.У Страуструпа опечатка (или намеренная ошибка,что более вероятно ) Вот в этом куске кода в функции get_token():
Добавлено через 16 минут 19 секунд И ещё опечатка была
31
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
| 20.06.2009, 20:03 | |
|
Ответы с готовыми решениями:
464
Пишем свой интерпретатор языка BASIC
Пишем свой чекер |
|
|
||||
| 14.08.2009, 20:43 | ||||
|
Добавлено через 5 минут 26 секунд Закинул сюда Вопрос про разные реализации бэйсиков Добавлено через 1 час 16 минут 21 секунду Пока не забыл. Функции тем не менее остаются, но только встроенные (SIN, COS и т.п.). С точки зрения парсера удобнее считать, что это keyword'ы - проще получается разбор. С точки зрения дальнейшей поддержки функций лучше считать, что это IDENT, а дальше уже разбираться, у нас идёт обращение к переменной или вызов функции Добавлено через 4 часа 31 минуту 32 секунды Кстати, звучит как парадокс, но вариант с промежуточным представлением проще, чем с двумя проходами. Хотя тебе полезно сделать оба варианта (сначала "плохой")
1
|
||||
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
||||||
| 15.08.2009, 23:25 [ТС] | ||||||
|
Так,думаю,нужно подвести некоторые итоги.Я сейчас недаром застрял,я думал над реализацией промежуточного представления,но что-то никак не укладывается в голове,как вообще это организовать,то есть не вижу реализации за идеей.Вот смотрю на твой пример реализации и просто не понимаю,что с чем там будет связываться,если будет строиться дерево,то есть как после построения дерева его потом разгребать.Самое непонятное для меня это то,что переменные по ходу работы программы могу меняться,и как это связывается с деревом,вообщем бардак полный в голове
Вариант с пропуском кода не лучше,то есть как-то не видится вариант реализации,делать флаги какие-то,что-ли,что-бы передавались в функции,а потом их менять после выхода из пропускаемого блока... это тоже не так просто.Это надо тогда подпортить все функции этими флагами. Понять бы получше механизм промежуточного представления,в каком точно виде всё это дерево будет и что будет его читать.Насчёт системы тестирования-реально полезная вещь,которая позволила мне исправить кучу логических ошибок без особых затрат!Теперь даже можно сделать такой исходник
Правда пришлось делать скидку на то,что блоки в IF и WHILE пропускаются без разбора,но даже и так много изменил всяких мелочей.Пока ещё вложенность условий не поменял везде(имею ввиду непроинвертированные),но кое-что подправил.Код прилагаю,посмотри,как выглядит syntax_parser.cpp,там я поменял больше всего с точки зрения отступов и т.д.Меня очень интересует мнение по оформлению,стал ли код менее читабельным.Я расположил строки немного плотнее.
0
|
||||||
|
|
|
| 16.08.2009, 00:27 | |
|
Я вроде уже писал. Посмотри тут посты 3 и 5. Фактически там у меня сначала строится промежуточное представление (когда выражение представлено в виде дерева), а потом обходится и обсчитывается (по сути происходит исполнение)
В данном примере по сути делается то, что должно быть в промежуточном представлении на тех местах, где идёт выражение. Если опять непонятно, буду думать, как объяснять. Проще всего было бы набросать рабочий исходник на Си для демонстрации. Может, если не поленюсь, набросаю какой-нибудь кастрированный вариант Добавлено через 11 минут 13 секунд Исходники потом гляну
1
|
|
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|
| 17.08.2009, 16:55 [ТС] | |
|
Я посмотрел твои исходники,вроде всё понятно,но я не представляю,что изменить именно в моей реализации,как-то смутно всё.Как будто снова вернулся к отправной точке,когда только начинал перекраивать калькулятор.Просто не могу представить механизм работы после промежуточного представления. Может,я просто морально не готов писать всё заново
Но если бы точно представлял,что и как сделать,то наверное переделал бы.Я решил проблему с динамической памятью,оказалось,всё просто.С самого начала я не пользовался динамической памятью,но тогда прога вылетала,и я ошибочно подумал,что это необходимо,использовать new.Теперь я просто передаю сами объекты из функций.Всё использование динамической памяти было полностью убрано из программы. Ещё я добавил оператор GOTO.
0
|
|
|
|
|||||||||||||||||||
| 17.08.2009, 17:52 | |||||||||||||||||||
И в этом вопросе я тебя понимаю.Промежуточное представление - это некий набор структур данных, связанных между собой, которые отражают исходную программу. Пример отображения выражения ты уже видел - это дерево. Сейчас попробую на пальцах объяснить, как хранить операторы и пока не забыл, скажу: про непонятки лучше спрашивать максимально конкретно, а то какие-то вещи для меня слишком очевидны, что я за общими вопросами могу и не увидеть проблему Программа у тебя состоит из цепочки операторов. Нам всю эту цепочку надо иметь в некотором внутреннем виде, который мы затем будем интерпретировать. Если помнишь мои предыдущие пояснения, то структуры, хрянащиеся в списке, я хранил в одном флаконе: данные и топологию (т.е. как элементы связаны между собой). Мне такой вариант кажется более удобным, но я его не навязываю. Просто я сам не смогу внятно написать всё это с использованием stl'ских контейнеров, поэтому напишу именно по-своему - так хоть есть вероятность, что поймёшь Рассмотрим для начала простой код. Если ты это не поймёшь, будем жевать подробнее, если поймёшь - попробуем двигаться дальше. Поэтому для начала простой пример
Промежуточное представление будет состоять из statement'ов. Все они провязаны в список по очереди через поле next (см. ниже). Структура для хранения представления statement'а в таком упрощённом случае следующая
При таком раскладе привожу код, который "вручную" создаёт промежуточное представление. Чтобы понятно было, что у нас в итоге получится. Понятно, что аналогичное представление у тебя будет строиться в процессе работы парсера. Разделяю построение каждого оператора отдельно (ибо реально они будут отдельно), перменная Last моделирует некую глобальную переменную
Давай пока на этом остановлюсь. И жду уже более конкретных вопросов
1
|
|||||||||||||||||||
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|||||||||||||||||||||
| 17.08.2009, 18:35 [ТС] | |||||||||||||||||||||
|
Пыгает вроде.. у меня сами метки создаются в глобальной таблице,так что неважно,куда прыгать..В сообщение твоё сейчас буду вникать.
А вот пример:
В главной функции:
А это в syntax_parser.cpp:
0
|
|||||||||||||||||||||
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|
| 17.08.2009, 18:51 [ТС] | |
|
А да,та версия,что я выкладывал,ещё без GOTO,так что вот новая
0
|
|
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|
| 17.08.2009, 19:41 [ТС] | |
|
Да,теперь мне понятна идея реализации,по крайней мере,направление.Незнаю почему,но когда кто-то целенаправленно объясняет,мозг воспринимает лучше,хотя в исходниках было то же самое.))
Что мне не понятно: как будет организован while ,а также goto при такой реализации?Мы же уже не будем работать с файлом,тогда как узнать,на какую строку/символ прыгать? А так вроде доходит потихоньку,что у нас будут данные,но присваивания и вообще опрерации над ними ещё не произведены,и будут сделаны после. Как всегда,перекраивать надо с ног до головы ![]() Добавлено через 19 минут 44 секунды P.S.GOTO прыгает только вперёд.Потому что сначала ему надо узнать метку и создать её,а уже потом прыгать .Я понял о чём ты,скорее всего это разрешается промежуточным представлением. Добавлено через 19 минут 45 секунды Я кажется понимаю,goto просто будет хранить порядковый номер следующей инструкции.
0
|
|
|
|
|||||||||||
| 17.08.2009, 19:52 | |||||||||||
![]() Что касается компилятора - теоретически ничего не мешает нам его в будущем написать. Пусть код будет медленным и гавёным, но это будет рабочий код. В крайнем случае можно написать конвертор Бэйсик->Си. Но это так, к сведению. Пока мы пишем интерпретатор Добавлено через 6 минут 35 секунд Вот так выглядят метка и операция GOTO. Всё это так же является частью поля Statement.data
1
|
|||||||||||
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|
| 17.08.2009, 20:05 [ТС] | |
|
Да,всё вроде понятно теперь. Пока что у меня GOTO действительно только назад прыгает.
0
|
|
|
|
||||||||||||||||||||||||||
| 17.08.2009, 20:31 | ||||||||||||||||||||||||||
|
Теперь что касается всякийх циклов и условных исполнений. Нам дополнительно понадобится одна-единственная операция условного перехода (CONDITIONAL_GOTO)
Например, для такого кода
1
|
||||||||||||||||||||||||||
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
||||||
| 18.08.2009, 22:39 [ТС] | ||||||
|
Ещё одна мелочь.Вот тут
0
|
||||||
|
|
||||||||||||
| 19.08.2009, 20:17 | ||||||||||||
|
Expression нет смысла провязывать в цепочку. Это же по сути дерево. Statement'ы мы в цепочку провязываем для того, чтобы всё это потом обходить последовательно. Т.е. вместо Value у тебя будет указатель на Expression, который, по аналогии с моим примером выглядить что-то типа того
Добавлено через 8 минут 59 секунд Не забудь сделать отладочную печать представления. При этом каждому Statement'у надо присваимвать уникальный номер. Тогда в операциях перехода можно будет его печатать, чтобы визуально понять, куда у тебя реально идёт переход Добавлено через 4 минуты 11 секунд И сразу думай о том, как работать с массивами. Ибо, навскидку, это последний невыясненный момент Ну и надо разобраться, как же реально в Q-Basic'е идёт работа с типом. Потму как надо уже под это дело подстраиваться Добавлено через 20 часов 44 минуты 14 секунд Смотрю исходники. По оформлению читать уже гораздо проще чем раньше. Но три пробела в начале строки по прежнему убивают наповал ![]() Внутри syntax_ParseTerm ты в цикле вызываешь syntax_ParseTerm, хотя мне кажется, что надо всё-таки syntax_ParsePrimary. Проверить не могу, т.к. по тем исходникам из #87 ничего не могу запустить. На твой пример из #86 ругается "Wrong definition", а напрямую подавfть выражение в PRINT пока не работает. По идее то, что написано рабочее, но глубины воображения что-то не хватает понять, где это можетнакосячить (если накосячит вообще) Добавлено через 2 минуты 46 секунд AND, OR и XOR ты назвал BINARY_OP. Название этого термина переводится как "двухаргументная операция". Правильное названия - "побитовая операция" (BIT_OP или BITWISE_OP) Добавлено через 2 минуты 19 секунд Из syntax_parserIdentLValue ты вызываешь syntax_parserBinaryExpr, что не есть верно, т.к. у тебя в этом случае будет по синтаксису разрешена операция типа "A&B = 5" Добавлено через 3 минуты 32 секунды Фрагмент процедуры void syntax_parserStmtKwLET:
1
|
||||||||||||
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|
| 19.08.2009, 22:37 [ТС] | |
|
Насчёт wrong definition,скорее всего ты скопипастил код прямо из сайта,я уже писал,что названия типов должны быть маленькими буквами,это движок сайта меняет на большие,я уже задумываюсь о том,чтобы сменить с int на INT.
Насчёт 3-х пробелов - это я подглядел в где-то в исходниках GNU,и мне понравилось,потому как в той IDE,где я работаю,folding находится очень близко к краю,и часто код закрывается случайно.Ещё причина,почему это показалось удобным-так лучше видно препроцессорные команды из общей массы.То есть это не религиозное что-то,причина есть ![]() Добавлено через 31 минуту 38 секунд Насчёт LET A&B = 5 ,вроде у меня не пропускает подобные выражения,пишет "Wrong let statement".То есть LET гарантирует присваивание сразу после первого идетификатора.А вот с goto есть проблема,и правда.Как раз о чём ты говорил,внутри IF.Это происходит в момент,если например,после одного прыжка мы уже не заходим в IF,а пропускаем этот блок. Насчёт выражений в PRINT-так и было задумано,выражения только в LET Я начал что-то ваять с промежуточным кодом,пока только интерфейс tree.h - идёт туговато )
0
|
|
|
|
||||||||||
| 19.08.2009, 23:03 | ||||||||||
![]() Добавлено через 4 минуты 59 секунд С заменой INT'а на int заработало. При вводе когда нажал Ctrl^D (т.е. фактически конец ввода), прога ушла в бесконечный цикл и начала срать на экран, потом терминал завис ![]() Добавлено через 1 минуту 42 секунды Для такого кода напечаталось 0. ОШибка
Я кстати понял причину этой ошибки. Текст спрячу. Если интересно - попробуй для начала сам разобраться qqq
То, как у тебя построена процедура syntax_parserTerm даёт эффект, что операции начинают считаться справа налево, хотя должны слева направо. 5 * 6 / 11 должно считаться как "(5*6)/11" а у тебя считается как "5*(6/11)" - почитай внимательно формальное описание синтаксиса в посте #29
1
|
||||||||||
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
||||||
| 20.08.2009, 01:36 [ТС] | ||||||
|
Вот это новость!
Как теперь это исправить,я даже не знаю )) Наверное я зря убрал динамическую память,помнится тогда всё работало (ну вроде )Добавлено через 12 минут 55 секунд Скорее всего это связано с тем,что передаваемое значение-это не просто значение,а объект.Видимо,объект по значению целиком не передаётся,если он не в динамической памяти,ведь это некая составная единица,и похоже,что так делать с объектами нельзя.То есть получается,что все промежуточные значения теперь теряются при передаче из функции,я попробую переделать.Но имеет ли смысл,вроде решено делать промежуточный код ? Добавлено через 1 час 1 минуту 0 секунд А может,ты прав,я заметил,что у меня выражение вроде как по другому сворачивается,но как теперь переделать-ума не приложу. Деревья как отдельное понятие не нужны,но ведь надо же куда-то свалить все эти структуры? Добавлено через 13 минут 30 секунд Вот поменял немного-вроде теперь ок
0
|
||||||
|
|
|
| 20.08.2009, 14:12 | |
|
С косяком при подсчёте выраения до конца разобрался? Или надо пояснить?
> Деревья как отдельное понятие не нужны,но ведь надо же куда-то свалить все эти структуры? В каком смысле сваливать? Создаёшь новый узел Expression (через new), цепляешь его к представлению. Т.е. в Statement'е будет торчать ссылка на созданный узел Expression. А из него будут торчать ссылки на другие Expression'ы и Variable'ы. Или я вопрос как-то не так понял Добавлено через 7 минут 58 секунд Не забудь на данную ошибку тест написать, чтобы в будущем не проявилось Добавлено через 4 часа 50 минут 57 секунд У меня всё-таки $опа зачесалась и я накатал-таки упрощённый вариант интерпретатора с промежуточным представлением. Если интересно будет - можешь попробовать посмотреть
1
|
|
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
||||
| 20.08.2009, 16:24 [ТС] | ||||
|
0
|
||||
|
|
|||||||||||||||||
| 20.08.2009, 16:57 | |||||||||||||||||
|
Оговорю сразу несколько моментов, которые у меня пока не сделаны:
Если какие-то косяки найдёшь - говори. Если будет время - попробую впараллель с тобой писать. Так проще будет твои проблемы понимать. Чтобы было перед глазами - кладу исходник и отладочную печатьпромежуточного представления (думаю, без комментариев будет понятно)
Вот исходники. interp.rar - в KOI-8, interp_w.rar - в WIN1251 (с виндовыми энтерами) Трассировочные макросы: lex.c - LEX_TRACE_TOKEN statement.c - STMT_TRACE interp.c - INTERP_TRACE Надеюсь, что после этого ты начнёшь понимать, что из себя представляет промежуточное представление и как с нима работают. А так же посмотри на сопосб, когда в лексическом и синтаксическом разборе работа построена так, что всегда подкачиваем на одну единицу вперёд (на один символ для лексическогоразбора, на один токен - для синтаксического) Добавлено через 1 минуту 25 секунд В печати промежуточного представления надо смотреть именнопорядок, в котором всё печатается. То, что номера печатаются не по порядку - это фича, связанная с механизмом создания меток для переходов вперёд
1
|
|||||||||||||||||
|
|
|
| 20.08.2009, 16:58 | |
|
Фалй забыл приаттачить
1
|
|
| 20.08.2009, 16:58 | |
|
Помогаю со студенческими работами здесь
100
пишем свой троян с нуля Пишем свой класс, спецификатор доступа protected Интерпретатор небольшого языка программирования на С++ Не удается откомпилировать интерпретатор М-языка
Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
|||
|
Использование SDL3-callbacks вместо функции main() на Android, Desktop и WebAssembly
8Observer8 24.01.2026
Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а привычная функция main(). . .
|
моя боль
iceja 24.01.2026
Выложила интерполяцию кубическими сплайнами www. iceja. net
REST сервисы временно не работают, только через Web.
Написала за 56 рабочих часов этот сайт с нуля. При помощи perplexity. ai PRO , при. . .
|
Модель сукцессии микоризы
anaschu 24.01.2026
Решили писать научную статью с неким РОманом
|
http://iceja.net/ математические сервисы
iceja 20.01.2026
Обновила свой сайт http:/ / iceja. net/ , приделала Fast Fourier Transform экстраполяцию сигналов. Однако предсказывает далеко не каждый сигнал (см ограничения http:/ / iceja. net/ fourier/ docs ). Также. . .
|
|
http://iceja.net/ сервер решения полиномов
iceja 18.01.2026
Выкатила http:/ / iceja. net/ сервер решения полиномов (находит действительные корни полиномов методом Штурма).
На сайте документация по API, но скажу прямо VPS слабенький и 200 000 полиномов. . .
|
Расчёт переходных процессов в цепи постоянного тока
igorrr37 16.01.2026
/ *
Дана цепь(не выше 3-го порядка) постоянного тока с элементами R, L, C, k(ключ), U, E, J. Программа находит переходные токи
и напряжения на элементах схемы классическим методом(1 и 2 з-ны. . .
|
Восстановить юзерскрипты Greasemonkey из бэкапа браузера
damix 15.01.2026
Если восстановить из бэкапа профиль Firefox после переустановки винды, то список юзерскриптов в Greasemonkey будет пустым.
Но восстановить их можно так.
Для этого понадобится консольная утилита. . .
|
Сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
|