Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
||||||||||||||||||||||||||||||||||||||||||||||
1 | ||||||||||||||||||||||||||||||||||||||||||||||
Пишем свой интерпретатор языка BASIC20.06.2009, 20:03. Показов 242534. Ответов 464
Метки нет (Все метки)
Благодаря форуму и Evg в частности интерпретатор развивается, потихоньку превращаясь в простенький интерпретатор QBASIC.
Некоторые из самых старых версий сохранились в теме и ссылки на них будут добавлены в это сообщение,а также ссылки на другие темы,связанные с этой. Репозиторий с проектом находится тут, там же есть возможность в браузере посмотреть историю ревизий (английский в логах весьма примитивен,комментарии и рекомендации можете писать в личку),а также скачать самый последний архив репозитория в формате .tar.gz Если кто-то пользуется Subversion,скачать исходники можно так: Код
svn co https://basin.svn.sourceforge.net/svnroot/basin basin Технический приём для формирования согласованных данных 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 Пишем свой strlen Пишем свой чекер пишем свой троян с нуля |
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|
23.09.2009, 00:27 [ТС] | 141 |
Беру на вооружение.Вообще сейчас займусь папкой с тестами,наберу небольшую базу,ну и попробую допилить DIM.
Это проверю. Ок,я понял,попытаюсь добавить. Да,в принципе,но возможны варианты этих конструкций,я просто не углублялся.Например,IF теперь,если не заканчивается на EOL,то должен заканчиваться на END IF именно двумя раздельными словами.Кстати,я уже задумываюсь о том,как делать правильный выход из программы,что нужно ведь,наверное,освободить сначала всю память,а потом уже делать выход? Да,я во всём разбирался,я именно делал сначала не подумав,а потом уже разбирался,почему мой вариант был плох,то есть,не просто содрал,а понял,почему так и так.Хотя сознаюсь,для меня изобретение велосипедов-очень тяжёлое занятие,и если я вижу,что есть уже что-то,что может подойти,я непременно это использую,и только в последнюю очередь буду напрягать мозги,прямо напасть какая-то. Можно сказать,что,по большому счёту,это твои исходники,я просто портировал их для компиляции на свой лад.. Просто так получилось методом проб и ошибок,и конечно,лени.. Конечно,там много мусора,я подумал,что,может стоит сделать Statement с помощью классов? А то у меня сокрытие данных превращается в кучу функций,ведь у меня сама структура только в .cpp файле...
0
|
23.09.2009, 09:28 | 142 |
По большому счёту можно не заморачиваться и выходить. Все данные у тебя живут в течение всей программы, а потому на проблему освобождения динамической памяти можно забить. Я вижу только две причины, чтобы сделать освобождение памяти:
- это хороший тон программирования - при помощи специальных программ можно будет отслеживать утечки памяти (т.е. в тот момент когда ты освободил всё, утилиты смогут найти фрагменты, который оказались неосвобождёнными) Тут я тебе не советчик. У меня нет С++'ного мышления. Когда я поначалу для тренировки решил попробовать написать на Си++, то понял, что при моём подходе нормальная концепция Си++ скорее мешает, чем помогает
1
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
||||||
23.09.2009, 22:40 [ТС] | 143 | |||||
Пришлось переделывать представление для LET в файле Statement.(это связано с тем,что в левой части присваивания может быть элемент массива,а его индекс,имя массива и значение элемента нужно где-то хранить).
Возник вопрос,скорее,относящийся к чистому С,поскольку данная конструкция пришла оттуда и в принципе это ты мне показал данный способ организации данных.Промежуточная схема теперь выглядит так:
0
|
24.09.2009, 00:18 | 144 |
Только дополнительную переменную. И это не костыль. Ибо если хранить данные в union'е, то обязательно нужно дополнительное поле, по которому возможно понять, какое из полей union'а у нас инициализировано
Добавлено через 33 минуты Я всё это храню в в виде выражения (которое может быть либо узлом переменной, либо декомпозицией массива) - см. interp_InterpStatementLET
1
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|||||||||||
26.09.2009, 02:20 [ТС] | 145 | ||||||||||
Кое-как смог сделать массивы,хотя не уверен,полностью ли правильно,буду тестировать.Как-то у меня громоздко получилось,запутано всё так.У тебя по виду всё так просто сделано с массивами,мне же пришлось добавлять функциональности чуть ли не по всей программе,и ещё осталось (особенно связано с типизацией).
Но с виду работает.Рабочий пример (в ревизии 30):
С таким примером
Добавлено через 19 минут Всё,вроде поправил.Evg,а утебя работают цвета в консоли,если скриптом прогоняешь тесты? А то я сделал,но не знаю,будет ли везде работать. Я слышал,что это может не работать на некоторых терминалах/системах (в смысле другие управляющие символы для цветов).
0
|
26.09.2009, 12:54 | 146 |
Красным цветом по крайней мере выделяется. У тебя по ходу не влиты файлы с эталонными выдачами. А вообще цвета - это от терминала зависит. В своё время сталкивался с тем, что на солярисовых родных терминалах это не работает. Так что на цвета я уже давно забил. Обычно я пишу "PASS" и "****** FAIL ******", чтобы "FAIL" на фоне всего чётко выделялось. Но ты можешь пока оставить себе цвета, если это удобнее
По поводу индексации массивов - в бэйсике она начинается с 1, а не с нуля. Т.е. при формировании номера элемента в многомерной декомпозиции из каждого индекса надо вычесть 1. А так же есть DIM A (10 TO 20) - в этом случае надо вычитать 10. У меня пока это не сделано, но в комментариях обозначено. А 0 это частный случай (вычитаем 0, а потому ничего не меняется). В принципе ты сам волен выбирать, как оно должно быть, но просто лучше делать так, как принято. Я по крайней мере буду приближать максимально к настоящему qbasic'у А строковые массивы у тебя работают? А то основные конструкции вроде бы как уже реализованы, а потому уже пора заниматься наведением порядка. И в программе и в синтаксисе
1
|
26.09.2009, 13:00 | 147 | ||||||||||
**
Добавлено через 1 минуту > С таким примером прога вылетает Потому что у меня индексация с 1, а у тебя с нуля Добавлено через 3 минуты
1
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|
26.09.2009, 17:19 [ТС] | 148 |
Я где-то прочитал,что по умолчанию все элементы массива равны нулю.Они все обнуляются в interp_stmtDIM.
Про идексацию я тоже прочитал что с нуля начинается якобы,но,видимо,книга была не правильная Значит,надо переделать. Насчёт эталонных выдач - не держу их в проекте.Задумка такая - там есть файл README в корневом каталоге,в нём написано,что если планируются изменения в исходниках,то сначала запускается скрипт tmpl_maker,он всё создаёт,а после изменений уже запускается test_script.
0
|
26.09.2009, 17:48 | 149 |
На самом деле в бэйсиках вообще все переменные по умолчанию обнуляются, а не только массивы. А строковые переменные и массивы пробиваются пустыми строками. Просто мы по началу сделали так, чтобы проще было жить (да и что-то типа отладочного средства получилось). В идеале мне видится так, что всё должно быть, как в обычном бэйсике, но по доп. опции включается поддержка контроля неинициализированных переменных. В любом случае это совйство для обычной переменной и для элемента массива должно быть одинаковым
Это неправильно. Предположим у тебя работает. Далее я копирую к себе твои исходники и перекомпиливаю. Но на моей машине оно работает неправильно - например есть косяк, зависящий от использования неинициализированной переменной. У тебя он проявляется одним способом, у меня другим. Далее я получаю типа эталон, который на самом деле оказывается неправильным. Поэтому эталонная выдача должна обязательно рядом с тестом лежать. Если при изменении интерпретатора эталонная выдача меняется (изменился формат печати, справлена ошибка и т.п.), то эталонную выдачу надо править. И никуда от этого не денешься
1
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
||||||
28.09.2009, 05:00 [ТС] | 150 | |||||
Кое-что переделал,теперь неинициализированное значение в массиве вызывает ошибку.Поправил работу со строками и контроль типов для массивов.Попробовал переделать индексацию с нуля на 1,но что-то запутался с индексами и вернул всё назад.Надо просто сесть нарисовать как-то для себя,что-бы иметь представление,где точно менять индексы,а то у меня там кавардак с векторами.Ведь и общая формула доступа к элементу должна измениться? Сейчас она выглядит так(я её на всякий случай прописал в комментах(частный случай для 3-мерного массива),а то там цикл непонятный такой =) ) :
Я вот незнаю,а как лучше сделать выключающуюся поддержку проверки неинициализированных переменных: через параметр командной строки,или через перекомпиляцию с помощью препроцессора? В принципе,и тот и другой вариант можно оправдать.Командная строка - удобство,гибкость.Препроцессор - всё-таки это не стандартная версия QBASIC,и вроде как надо перекомпилить,да и бинарник уменьшит,хоть и ненамного.Хотя стандартная версия всё равно не получится,так вроде командная строка перевешивает.Как считаешь? Ещё есть вопрос про FOR: по идее,эту инструкцию тоже можно отнести к Conditional Branch,но нужно тогда правильно сгенерировать условие,так? Я имею в виду,что условие придётся генерировать как-то вручную,ведь это не стандартное выражение,а ещё как-то вручную добавить в конце блока новый LET чтобы менял значение счётчика на нужную величину.Или всё таки лучше делать FOR как отдельную конструкцию?
0
|
28.09.2009, 09:31 | 151 | ||||||||||
Да. В правой части должно быть "linear_array[(a-1)*y*z + (b-1)*z + (c-1)]". А в общем случае надо вычитать стартовый индекс (который по умолчанию равен 1, но по синтаксису можно задавать самому)
Любая пользовательская настройка должна быть в виде опции. ТОлько поведение на мой взгляд надо инвертировать. По умолчанию работать так, как принято в бэйсиках, а по опции - ломаться на неинициализированных данных. Эта опция - по сути дела отладочное средство. Технически удобнее всего делать так, что в момент заведения новой переменной ей сразу прописывать нулевую инициализацию Да, нужно сгенерировать правильный набор операций сравнений, условных переходов и т.п. Т.е. при поддержке FOR'а изменения вносятся только в синтаксический разборщик. В промежуточном представлении и интерпретаторе не надо делать ничего. Имено поэтому такой вид промежуточного представления даёт дополнительные бонусы: т.е. многие сложные высокоуровневые конструкции реализуются через один и тот же маленький набор низкоуровневых примитивов Т.е. промежуточное представление для
1
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|||||||||||||||||||||
29.09.2009, 06:42 [ТС] | 152 | ||||||||||||||||||||
При попытке сделать индексацию с единицы нашёл какой-то странный баг.При печати в данном исходнике печать первого и второго цикла расходятся.
Исходник
Сначала грешил на формулу,но когда вставил печать в первый цикл,вообще попал в тупик,так как она верная.Вообще,если после первого цикла менять значение array(3,1) или array(2,1),то меняются также значения array(2,10) и array(1,10) соответственно.Считал по формуле - получается,что у них в линейном массиве тот же индекс.
0
|
29.09.2009, 11:05 | 153 | ||||||||||
Вычитать 1 нужно только из индекса. Размерность массива остаётся прежней
Вместо
Пока не забыл, что на будущее. Чего нужно было бы сделать, но что нужно, а что нет - решай сам. В идеале надо сделать всё 1. Поддержать массивы с произвольного стартового индекса. Типа "DIM A(5 TO 10) 2. По возможности поддержать все синтаксические реализации для IF, WHILE, FOR (ну и какие там ещё есть циклы) 3. Видимо придётся наводить порядок в исходниках программы. Когда много чего работает - наверняка накопилось куча мест, которые неплохо бы переделать 4. Возможно сразу же попытаться реализовать вариант с генерацией исходника на Си++ с целью получения бинарника (о чём я уже рассказывал). Такой вариант уже имеет рассматривать с той точки зрения, что при дальнейшем развитии можно будет поддерживать обе ветки (интерпретация и генерация текста Си++), а потому многие неоптимальности видны будут сразу. Из разряда того, что при нынешней схеме реализация конструкции FOR НЕ затронула бы процесс интерпретации и генерации текста, т.к. в промежуточное представление мы не вносили новых конструкций Ну и дальнейшим пунктом развития будет реализация встроенных функций (SIN, COS, VAL, STR$, ...)
1
|
30.09.2009, 14:25 | 154 |
Если смотрел мои исхожники, там есть конструкция var_DimDescr_t, описывающая размерность массива. Эту же конструкцию я использую и для описания элемента массива (которая по научному называется "декомпозиция"). Это неправильно (мне тогда просто лень было, а потом забыл). Просто должны быть две вещи:
- Описатель размерностей массива (на каждую размерность хранится стартовый индекс и размер). Этот описатель является свойством переменной - Описатель декомпозиции элемента массива (на каждую размерность хранится текущее значение индекса). Этот описатель является свойством операции Номер элемента вычисляется на основании двух этих конструкций.
1
|
30.09.2009, 21:16 | 155 |
Кстати, вот ещё идея. Сделать "OPTION TRACE_CMD <val>", "OPTION TRACE_WRITE <val>". Пользовательские фичи для включения трассировки исполнения операций и трассировки записей. Т.е. если есть блок кода, который предположительно работает неправильно, то командами "OPTION TRACE_WRITE 1" и "OPTION TRACE_WRITE 0" соотвественно включаем и выключаем трассировку
1
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|
30.09.2009, 21:33 [ТС] | 156 |
В смысле навроде того,что у нас пишется в логи? Только там что будет писаться,что-то недопонимаю? UPD Всмысле будут писаться текущие значения какой-то переменной?
0
|
30.09.2009, 21:41 | 157 |
Ну навроде того, только это то, что для пользователя предназначено. При печати записей печатать что-то типа
Код
a.bas:10 WRITE A = 10 a.bas:11 WRITE B = 11 ... Код
exec a.bas:10 exec a.bas:11 exec a.bas:12 Добавлено через 56 секунд Когда у тебя два заумных вложенных цикла с кучей ветвлений внутри, тяжело "теоретически" разбирать ошибки
1
|
39 / 17 / 1
Регистрация: 21.08.2009
Сообщений: 63
|
|
01.10.2009, 14:48 | 158 |
Господа, увидел вашу тему, решил наваять что-то подобное, но у меня возникла проблема:
сначала сделал линейно и у меня выходило что 2+2*2=8, хотя 6; потом немного видоизменил код добавив рекурсию в итоге предыдущее считает правильно а 3-1+2=0 хотя 4. Как вы решали проблему приоритета умножения/деления над сложением/вычитанием? ЗЫ: если брать все в скобки - считает правильно.
0
|
01.10.2009, 23:28 | 160 |
Я что-то смотрю, у тебя одни негативные тесты. А позитивные-то есть?
0
|
01.10.2009, 23:28 | |
01.10.2009, 23:28 | |
Помогаю со студенческими работами здесь
160
Пишем свой класс, спецификатор доступа protected Интерпретатор небольшого языка программирования на С++ Не удается откомпилировать интерпретатор М-языка Интерпретатор музыки стандарта BASIC PLAY на С++ Написать интерпретатор программного языка -помощь Интерпретатор/компилятор ассемблер-подобного языка Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |