|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
Пишем свой интерпретатор языка BASIC20.06.2009, 20:03. Показов 256063. Ответов 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
Пишем свой чекер |
|
|
|||
| 20.08.2009, 20:43 | |||
|
Добавлено через 3 часа 9 минут 34 секунды Сейчас твоя цель - разобраться с промежуточным представлением: правильно его строить и интерпретировать. Когда это всё будет работать ннормально, чисто теоретически для интересе можно попробовать поддержать синтаксис близко к оригиналу. Но, повторюсь, это непринципиально. Задача-минимум - реализовать хоть хоть в каком-то виде. При этом желательно, чтобы поддерживались IF, FOR, WHILE (в любом синтаксическом проявлении) и крайне желательна поддержка массивов. Свой вариант я набросал в первую очередь как пример на промежуточное представление. Пока с ходу не соображу, как _аккуратно_ туда ввинтить массивы. При этом появилось некоторое понимание, что держать строковые константы внутри Value - слишком геморойно получается
1
|
|||
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
||||||
| 20.08.2009, 21:22 [ТС] | ||||||
|
Не мог бы ты прокомментировать,как именно работает данная интересная конструкция и по каким соображениям она сделана?
0
|
||||||
|
|
|
| 21.08.2009, 14:32 | |
|
Оформил в отдельную тему https://www.cyberforum.ru/cpp/thread47863.html
Если что непонятно - спрашивай там Добавлено через 14 часов 20 минут 53 секунды В общем думал, как работать с массивами, в итоге получилась примерно следующая концепция. У нас есть две независимые вещи: Value (числовое значение, которое может быть целым или плавающим) и String (строка, которую, как и во многих бэйсиках, ограничиваем размером в 255 байт). У переменной есть признак, она хранит Value или String. При этом в Value нельзя записывать String и наоборот. Технически и в моей и в твоей реализации переменная содержит Value по значению. Думаю, что лучше делать по косвенности. Т.е. Value, хранимая в переменной, выделяется динамически (т.е. имеем поле Value_t *value). При этом выделяем фактически массив Value'ов. Если переменная скалярная (т.е. НЕ массив), то мы выделяем массив из 1 элемента, если же наша переменная массив - то мы выделяем массив из нужного количества элементов. Далее при разборе левой части присваивания мы фактически получаем указатель на нужное нам Value_t* (хоть для скалярной переменной, хоть для произвольного элемента массива). Всё аналогично делается со String'ами, а переменная внутри себя через union рядышком хранит Valut_t* и String_t*. При этом признак Value или String хранится на всю переменную. Т.е. если мы имеем массив, то нельзя в одном элементе хранить строку, а вдругом число Что касается синтаксиса, то видимо будет удобнее делать как у людей. Строковые переменные отмечать признаком $ на конце (т.е. этот символ входит в имя переменной, при этом в момент заведения новой переменной по этому символу мы понимаем, что будет храниться в переменной - строка или число) Что касается регистра букв, то проще всего это локализовать в лексическом анализаторе. При чтении токена из файла для keyword'ов и ident'ов сразу переводить их в заглавные буквы. Тогда будет работать и "int" и "INT" и всё, что пожелаешь По поводу типа переменной. У себя я предполагаю сделать примерно так: переменную можно использовать без дополнительного объявления. В этом случае тип будет "AUTO" (т.е. тип будет определяться записанным значением). Так же можно будет объявлять переменные через "DIM A AS INTEGER" (или как там правильно в синтаксисе). В этом случае тип переменной будет INT, FLOAT или STRING Добавлено через 20 минут 32 секунды Надо ещё при этом в промежуточном представлении как-то левую часть по другому описывать. Теперь там может быть не только переменная, но и элемент массива Добавлено через 2 часа 12 минут 19 секунд > Надо ещё при этом в промежуточном представлении как-то левую часть по другому описывать В общем думать тут особо и нечего. Левая часть так же описывается в виде Expression. Только нужно при разборе понимать, что там допустимо только обращение к переменной или к элементу массива. А так же при обходе в момент интерпретации должно возвращаться не значение, а указатель на Value
1
|
|
|
|
||||||
| 23.08.2009, 15:08 | ||||||
|
Тестовый пример, на котором моя версия ведёт себя некорректно. Я работал в таком ключе, что запись в переменную (т.е. появление переменной в левой части присваивания) автоматически означает её определение (т.е. этим мы задаём новую переменную). Я полагал, что в момент разбора синтаксиса если встретили несуществующую переменную в правой части присваивания - то это ошибка (по сути использование неинициализированной переменной)
1
|
||||||
|
|
|
| 24.08.2009, 16:17 | |
|
> У нас есть две независимые вещи: Value (числовое значение, которое может быть
> целым или плавающим) и String (строка, которую, как и во многих бэйсиках, > ограничиваем размером в 255 байт). Что-то фигово получается, когда одно делишь от другого. Буду дальше экспериментировать с тем, как делать "хорошо"
1
|
|
|
|
|
| 25.08.2009, 15:29 | |
|
Итого, примерно надумал следующее. Ввожу понятие типа, который может быть целочисленный (NUMERIC), строковой (STRING) и логический (LOGICAL). Переменные могут быть только первых двух типов, промежуточное значение выражения - всех трёх. Тип изначально является свойством значения (Value), но при этом засовывается в Variable и Expression, поскольку они так же оперируют значениями. Целочисленный тип разбиваю далее на два подтипа: целый и плавающий. Любые двухаргументные операции разрешены только над одинаковыми типами (в этом отношении int и float имеют одинаковый тип NUMERIC). Присваивание разрешено только для одинаковых типов
На текущий момент есть вроде бы всё основное: переменные, арифметика, операции управления, строки, массивы (в том числе и многомерные). Для полного сачтья надо поддержать встроенные функции (обычно их называют термином "builtin functions" или сокращённо просто "builtin"). Ну и с технической стороны надо поддержать пользовательские метки, FOR'ы, нормально поддержать двухсимвольные операции сравнения (">=", "<=", "<>"), но это всё уже мелкая работа, т.к. структуру уже затрагивать не должно - просто будет допиливаться код. Что мне сейчас не нравится принципиально - это реализация строк. Она сделана в виде массива, а потому структура Value получается большой. Нормально строку надо хранить не по значению, а по косвенности, но в Си это означает мегагеморрой с динамической памятью, слежение за удалением и копированием и т.п. А вот на Си++ это делается нормально за счёт деструкторов и реализации конструктора копирования (либо ваще тупо использовать стандартный String) Собственно программу выдаю для изучения того, как всё это примерно выглядит. Понятно, что тебе не нужно пытаться всё это повторить. Делай так, как понимаешь. Но с моей прогой возможно удетнекое общее понятие того, что в итоге должно быть. Словами это фиг объяснишь Выкладываю опять в двух вариантах: basic.rar в кодировке KOI-8 и basic_w.rar в кодировке WIN-1251
1
|
|
|
|
|||||||||||||||||||||
| 25.08.2009, 16:12 | |||||||||||||||||||||
|
Для такого кода
Вот ещё что забыл сказать. При работе в качестве интерпретирующей части можно повесить модуль, который вместо интерпретации будет генерить код на Си. Например, для исходника
По такой технологии сейчас поддерживаются некоторые устаревшие языки программирования. Особенно у военных, которые ни за что не пойдут на то, чтобы переписать какие-то военные программы, написанные много лет назад, потому как писали их гении того времени, а потому в коде разобраться невозможно. И гораздо более надёжным вариантом оказывается написать интерпретатор или конвертер в Си
1
|
|||||||||||||||||||||
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|
| 25.08.2009, 19:01 [ТС] | |
|
Вот про конвертер в Си немного не понял идею,как именно это будет работать.Мне теперь остаётся только наблюдать за твоим ходом написания,и потихоньку ковырять свой вариант.
0
|
|
|
|
|||||||||||||||||||||||
| 25.08.2009, 22:07 | |||||||||||||||||||||||
Это при том, что я себе совершенно чётко представлял, что должно быть, у меня ушло на это неделя времени. Так что твои два месяца - это вполне нормально. Как говорится "тяжело в учении..." ![]() Просто перед отпуском на работе резких телодвижений лучше не делать, а потому вот занялся интерпретатором. Да и если дальше меня не заломает, то следить там уже особо будет нечего - вся необходимая база уже вроде бы как отписана. Тебе нужно только понять принцип, по которому построено промежуточное представление и его интерпретация. Возможно не так просто будет разобрать тот низкоуровневый код на Си, когда привык работать с высокоуровневыми конструкциями типа списка и т.п.Так что если есть вопросы - задавай, до вечера пятницы я ещё тут. Добавлено через 1 час 18 минут По поводу генерации кода на Си (Си++). Относительно совтояния твоих исходников из поста #86 Допустим, имеем исходник на бэйсике:
Надеюсь, так понятнее. Если непонятно - забей. Если понятно - имей в виду. Такую хрень можно будет потом привинтить к интерпретатору. Можно конечно и сразу такое ваять, но сначала написать интерпретатор будет проще.
1
|
|||||||||||||||||||||||
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|
| 25.08.2009, 22:47 [ТС] | |
|
Да,это круто! Как я понял просто работаем с выходным файлом и записываем туда строки в зависимости от интерпретации файла на псевдо-бейсике.Затем можно дать команду типа system("g++ a.cc") (если в линукс,ну в другой среде можно команду поменять) и он скомпилируется на месте.
0
|
|
|
|
|
| 25.08.2009, 23:33 | |
|
Ну как и что потом запустить - уже не важно. В общем суть главное понял. Это большой бонус удобства работы с промежуточным представлением. Хочешь - интерпретируй, хочешь - генери с него текст на Си\Си++, хочешь - можешь напрямую делать компиляцию (фактически формирование ассемблерного файла). Представление в процессе построения заведомо очищается от пользовательских ошибок и, в отличие от файла, по нему можно ходить взад и вперёд, в том числе и заниматься оптимизациями (типа "A*4" заменять на "A<<2" или "A+5+6" заменять на "A+11"). Так что после того, как ты поймёшь, что же это за зверь такой, у тебя опять появится оптимизм
1
|
|
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
||||||
| 29.08.2009, 08:35 [ТС] | ||||||
|
Не знаю,зачем,но сделал проект на sourceforge.net
- https://sourceforge.net/projects/basin/ (basin - Basic Interpreter),теперь у кого установлена Subversion,смогут просто скачать исходники командой
Всё это дело вывешено под лицензией "BSD license",надеюсь возражений не будет? Просто хотел добавить опцию для скачивания,да и чтобы не лазить по теме в поисках исходников.Заодно снять лишний трафик с форума.Предлагаю держать исходники там.Можно попросить модераторов просто отредактировать первый пост,чтобы там были все ссылки относящиеся к данной теме. Если,например,нужно просто посмотреть историю изменений,то сделать это можно отсюда http://basin.svn.sourceforge.net/viewvc/basin/
0
|
||||||
|
|
||
| 16.09.2009, 09:22 | ||
|
Добавлено через 16 минут Уж коли пошло на то, что начал делать как серьёзную программу, то тебе надо бы удалить признак "exec" из исходников (т.е. часть файлов имеет права на исполнение). Видимо, ты пользуешься каким-то аналогом винlузового проводника, где это не видно Ещё где-то для порядку надо описать, какие конструкции понимает твой интерпретатор. Чтобы хоть можно было поэкспериментировать и самому что-то написать. Я в репозитории храню исходник, в котором присутсвуют все образцы поддерживаемых конструкций Пока особо не смотрел, но в бэйсиках вроде бы сделано так, что переменная без суффикса по умолчанию имеет плавающий тип, а у тебя целый. Но это мелочь Добавлено через 6 минут В value у тебя присуствуют поля типа int и long. Но для 32-битных машин как правило их размеры совпадают. Более аккуратно было бы в файле с настройками host'ового компилятора завести typedef'ы с именами тиа int32_t, int64_t и везде использовать их. И в начале исполнения программы поставить run-time контроль, что "assert (sizieof(int32_t) == 4); assert (sizieof(int64_t) == 8);". Аналогично для плавающих. Вроде бы как это мелочь, но такие вещи лучше делать сразу, чтобы потом в миллион местах не исправлять Добавлено через 1 минуту И сделай при интерпретации print'а чтобы энтеры рисовались, а то лепит всё в одну кучу - неудобно. Или как-то можно самому энтер напечатать? Добавлено через 15 минут И если у тебя есть какой-то набор тестовых ситуаций - для порядка его тоже можно под cvs положить (создать отдельный каталог и свалить туда). ТОже полезно, а то когда работаешь с одним файлом, добавляешь туда и удаляешь, то интересные тесты пропадают
1
|
||
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|||||||
| 16.09.2009, 12:58 [ТС] | |||||||
|
Добавлено через 26 минут Напиши,какая маска прав в восьмеричном формате должна быть у папок и файлов,я поставлю... Добавлено через 27 минут Как мне это сделать вообще с правами,сначала все файлы удалить из репов,а потом опять закачать с новыми правами?В репозиторий руками же не залезешь.
0
|
|||||||
|
|
|||||
| 16.09.2009, 13:44 | |||||
|
0
|
|||||
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|||||||
| 16.09.2009, 14:06 [ТС] | |||||||
P.S. А вообще у меня уже навроде паранойи насчёт типов везде где можно было поставил size3 для счётчиков привязанных к размерам векторов,потому что поглядел,какой у них max_size() на моей машине.Насчёт репов-боюсь попортить репозиторий,поэтому можно попробовать сделать это постепенно,по одному,просто удаляя старые и добавляя новые переименованные файлы.Потом можно попробовать переименовать их обратно.
0
|
|||||||
|
|
|
| 16.09.2009, 14:28 | |
|
Просто я смотрел revision 16 (ибо 20 у меня не компилится), а там в классе Value используются int и long
32 и 64 необязательно (просто удобно), можно назвать venik и prjanik, лишь бы не использовать напрямую базовые типы (чтобы править нужно было в одном месте)
1
|
|
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|
| 16.09.2009, 14:32 [ТС] | |
|
На что ругается компилятор?У меня всё ок,работает.Видимо,тут уже сказывается разность версий компиляторов?А-а,может надо makefile подправить,ты наверное только через командную строку работаешь?так я makefile только иногда обновляю,проверь
0
|
|
|
|
|||||||||||||||||
| 16.09.2009, 14:39 | |||||||||||||||||
|
Вот такой код на исполнении должен зацикливаться, но он не зацикливается
Я глубоко не копался, просто мысль для такого теста появилась после того, как я увидел реализацию того, как ты IF делаешь. Я ожидал увидеть переполнение стека в процессе интерпретации (из-за возникающей рекурсии в твоей схеме), но тут похоже какой-то другой косяк
1
|
|||||||||||||||||
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
||
| 16.09.2009, 16:00 [ТС] | ||
|
Да,косяк вроде в том,что при создании IF сначала проверяются (и создаются,конечно) его под-программы,а уже потом только сама инструкция IF,а это меняет глобальный порядок инструкций в программе.Выход-сначала создавать инструкции ,у которых есть свои подпрограммы "всухую",а уже потом создавать лист и проверять его на синтаксис,причем не меняя порядка следования,то есть сначала создаются все инструкции для THEN,а потом для ELSE,когда IF уже создан(ну в принципе это логично).А затем уже эти подпрограммы записывать в IF.Я ещё в начале заметил,что у меня в логах творится беспорядок: инструкции печатаются не по порядку,просто сначала не придал такого значения,что это баг.
Такой вариант должен исправить проблему,я полагаю. P.S.Я кажется понял,почему ты так подумал.Нет-нет,у меня GOTO работает только в runtime,то есть создание IF будет только 1 раз.
0
|
||
| 16.09.2009, 16:00 | |
|
Помогаю со студенческими работами здесь
120
пишем свой троян с нуля Пишем свой класс, спецификатор доступа protected Интерпретатор небольшого языка программирования на С++ Не удается откомпилировать интерпретатор М-языка
Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
|||
|
[golang] Угол между стрелками часов
alhaos 12.05.2026
По заданным значениям часа и минуты необходимо определить значение меньшего угла между стрелками аналогового циферблата часов.
import "math"
func angleClock(hour int, minutes int) float64 {
. . .
|
Debian 13: Установка Lazarus QT5
ВитГо 09.05.2026
Эта инструкция моя компиляция инструкций volvo
https:/ / www. cyberforum. ru/ blogs/ 203668/ 10753. html
и его же старой инструкции по установке Lazarus с gtk2. . .
|
Нейросеть на алгоритме "эстафета хвоста" как перспектива.
Hrethgir 06.05.2026
На десерт, когда запущу сервер.
Статья тут https:/ / habr. com/ ru/ articles/ 1030914/ . Автор я сам, нейросеть только помогает в вопросах которые мне не известны - не знаю людей которые знали-бы. . .
|
Асинхронный приём данных из COM-порта
Argus19 01.05.2026
Асинхронный приём данных из COM-порта
Купил на aliexpress термопринтер QR701. Он оказался странным. Поключил к Arduino Nano. Был очень удивлён. Наотрез отказывается печатать русские буквы. Чтобы. . .
|
|
попытка написать игровой сервер на C++
pyirrlicht 29.04.2026
попытка написать игровой сервер на плюсах с открытым бесконечным миром.
возможно получится прикрутить интерпретатор питон для кастомизации игровой логики.
что есть на текущий момент:. . .
|
Контроль уникальности выбранного документа-основания при изменении реквизита
Maks 28.04.2026
Алгоритм из решения ниже разработан на примере нетипового документа "ЗаявкаНаРемонтСпецтехники", разработанного в КА2.
Задача: уведомлять пользователя, если указанная заявка (документ-основание). . .
|
Благородство как наказание
Maks 24.04.2026
У хорошего человека отношения с женщинами всегда складываются трудно. А я человек хороший. Заявляю без тени смущения, потому что гордиться тут нечем. От хорошего человека ждут соответствующего. . .
|
Валидация и контроль данных табличной части документа перед записью
Maks 22.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа, разработанного в КА2.
Задача: контроль и валидация данных табличной части документа перед записью с учетом регламента компании. . .
|