|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
Пишем свой интерпретатор языка BASIC20.06.2009, 20:03. Показов 253459. Ответов 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.07.2009, 20:15 | |
|
Из файла value_class подключается syntax_parser.h (класс Value ещё не определён). Из syntax_parser.h подключается value_class.h, на этот раз впустую, т.к. макрос CONST_CLASS_H_INCLUDED взведён (кстати, макрос переименуй), класс Value по прежнему неопределён, затем подключается variable_class.h, из которого опять вхолостую подключается value_class.h. Далее идёт использование класса, но он неопределён (неизвестен его размер).
Если у тебя проблемы с этими делами, то можно поступать просто. Создаёшь файл common.h, и делаешь в нём все нужные инклюды в нужном порядке. Из каждого модуля *.cpp подключаешь common.h и больше ничего. В файлах *.h вообще ничего не подключаешь.
1
|
|
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|
| 15.07.2009, 17:32 [ТС] | |
|
Я попробовал всякие комбинации,но пока не смог сделать так,чтобы всё лежало по порядку и без ошибок,а суть ошибки ясна.Я пока просто положил реализацию функций,возвращающих Variable в variable_class.cpp,но описание сделал в заголовках syntax_parser.h,чтобы было видно,что они относятся к модулю syntax_parser. Придётся пока это дело прокомментировать,и оставить так,потому как я не знаю,как иначе разрешить данный конфликт
0
|
|
|
|
|
| 15.07.2009, 17:48 | |
|
Просто всё долно быть аккуратно разложено по файлам. У тебя я наблюдал много бардака, но я про него ничего не пишу, ибо со временем сам поймёшь. А порядок примерно такой (что должно подключать в каком порядке):
1. debug: самый ниский уровень, в котором должны быть просто описаны флаги и, возможно, какие-то базовые общеиспользуемые функции. Не подключает ничего 2. parser (лексический парсер): тоже низкий уровень. Работает напрямую с файлом (который получает параметром) и отдаёт "наверх" значения. Функции собственной отладочной печати должен содержать в себе (а не в модуле debugger). Не подключает ничего 3. value: низкий уровень. Из себя ничего не вызывает, а наоборот, его вызывают "сверху". Аналогично отладочные печати должны быть внутри. Не подключает ничего 4. variable: более высокий уровень. Содержит внутри себя value, а потому подключает value. Должен содержать свои отладочные печати 5. syntax_parser: более высокий уровень. Использует parser, value и variable, а потому подключает эти три компоненты. Как таковых отладочных печатей нет (т.к. по сути дела не имеет своих структур данных), есть только трассирующие печати (типа "зашли в правило Expr" и т.п.) 6. driver: верхний управляющий уровень. Напрямую вызывает только syntax_parser, во всех других компонентах должен вызывать только инициализацию и завершение (если это сложно реализовывать через конструкторы и деструкторы). Передача именеи файла в parser не совсем верно, имя файла должно передаться в syntax_parser, а оттуда уже в parser Просто всё это на бумажке в виде блоков надо аккуратно рисовать, чтобы более понятно стало
1
|
|
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
||||||
| 21.07.2009, 03:11 [ТС] | ||||||
|
Ура! Прога работает
Теперь можно сделать такой исходник:
![]() Многое,конечно,ещё нужно доделать,но даже от этого я чуть не прыгал Добавил имена типов,для последующего контроля,правда,у меня не получилось запихать значение строки в union в классе Value,постоянно выбивало в segfault в Си-функции strcat,я так и не разобрался,почему,поэтому пока сделал обычную строку,которую придётся таскать с собой,пока не переделаю.Скобки даже пока не сделал,увлёкся.Ещё пришлось сделать доступ к параметрам экземпляра Value внутри класса Variable,так уж увидел решение для INPUT.Добавил строковые константы,но пока прибавление float к ним проблематично,нужно ещё написать функцию перевода c_itof.Строковые константы возможны для печати,для облегчения пользовательского интерфейса,а также для вывода вспомогательных сообщений в инструкции INPUT. Буду теперь думать,как сделать инструкцию IF,в принципе,есть идея,что IF внутри себя должна запускать функцию с остальными инструкциями,чтобы реализовать независимый блок.Надо ещё подумать над тем,как лучше реализовать условие.. Вообще,программа разрастается потихоньку,парсер разросся уже не на шутку,но,с другой стороны,расширять её пока не так трудно.Код выкладывать в просмотре не имеет смысла,так как уже слишком громоздкий. Контроля ошибок пока нет,но будет. 1) Реальная проблема,с которой я столкнулся(это,по идее и есть вопрос)- это как освобождать всю ту память,которая выделяется динамически?А там её выделяется уйма.Я пока не разбираюсь в теме,и вот не знаю,что там реально происходит,походу дикая утечка памяти,и я не знаю,как это вообще решается в данном случае. Вот исходник: P.S. Имена типов в исходнике должны быть маленькими буквами,просто движок сайта поменял на большие
2
|
||||||
|
|
|
| 03.08.2009, 21:22 | |
|
Собственно, поздравляю. Я тебе уже писал, что со временем сам сможешь сделать всё, что надо и как надо. Но когда самостоятельно смог расширить до нужной функциональности - значит базовый принцип понял, что очень даже радует
По поводу динамической памяти - вопрос так с ходу осилить не могу. Полностью ковыряться в исходнике пока морально не готов По поводу IF'а. Надо понимать, что при работе IF'а у тебя может быть пропущен либо один (THEN), либо другой (ELSE) фрагмент кода. Более того, есть ещё циклы, где какой-то код придётся исполнять по нескольку раз. А ещё есть GOTO, где осуществляется переход на произвольный участок кода (который может быть как до, так и после оператора GOTO). И это мы с тобой ещё пока отложили в далёкий ящик реализацию функций (процедур). Если интересно подумать самому и есть соображения - выкладывай. Если нет - тогда расскажу как это можно сделать
1
|
|
|
146 / 146 / 32
Регистрация: 26.10.2008
Сообщений: 782
|
|
| 04.08.2009, 02:57 | |
|
А как называется книга из которой этот пример? Судя по коду она не для начинающих.
0
|
|
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
||||||||||||||||||||||||||
| 04.08.2009, 03:45 [ТС] | ||||||||||||||||||||||||||
|
Я уже заждался
Надеюсь,отпуск прошёл нормально. ![]() 1) Ну во-первых,хочу сказать,что уже многое изменилось в программе,я понял некоторые из ошибок,некоторые ещё не исправил,но займусь и этим.Одна из них - это насчёт неявного приведения типов.Я успел немного проштудировать материал по C,и узнал,что приведение выполняется всегда к большему типу(в смысле диапазона значений),учавствующему в выражении.Может,я не понял то,что говорил ты,но я тогда сделал не правильно.То есть если в выражении участвуют два операнда,к примеру, и первый из них int,а второй double,то приводить нужно не к первому встречному,а к большему,чтобы избежать излишних переполнений.Это я взял себе на заметку,но пока ещё не исправил.Были ещё недочёты,и ещё кучу я заметил,но пока оставил в покое.Сделал единую типизацию для функций,переменных и констант.Имеется ввиду не со стороны парсера,а просто общее перечисление типов для всех,используемое уже в синтаксическом анализаторе:
3) Также мне удалось добавить цикл WHILE с проверкой условия. 4) Сами проверки условия я ещё не доработал,и пока в выражении может быть только один оператор сравнения,то есть могут учавствовать только два выражения по обеим сторонам.Пока я оставил так,просто нужно сделать подобие обычных операций,с таким же спуском как и везде. 5) В настоящий момент я как раз делаю функции,это будет выглядеть примерно так:
1)я всё ещё не разобрался с выделением динамической памяти,и как её освобождать.Пока тема сыровата. 2) Есть такая специфическая проблема: например если внутри инструкции IF сделать цикл WHILE,то если написать
3) Логика внутри функций if и while довольно запутанная,что отношу к недостатку,вообще код мне кажется довольно "грязным".Сейчас делаю функцию объявлений для процедур,и сегодня не побрезговал конструкциями типа :
Ну вот,вроде все новости пока.Код прилагаю,но с учётом,что функция syntax_parserStmtKwFUNC () должна быть закомментирована,так как ещё в процессе(синтаксические ошибки и пр.). P.S. Только сейчас обнаружил,что ELSE перестала работать .Видимо,пока правил и менял,поломал ELSE ...ну ладно,разберёмся.Вот такой,к примеру можно сделать исходник:
0
|
||||||||||||||||||||||||||
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
||
| 04.08.2009, 03:46 [ТС] | ||
Но тот код,что был в самом начале,это из книги "Б.Страуструп.Язык программирования С++.Специальное издание."
1
|
||
|
|
||||||||||||
| 04.08.2009, 17:44 | ||||||||||||
|
Сам понимаешь, после отпуска с ходу сложно что-то сделать полезное для человечество. Некоторое время должно пройти в традиционно российском виде спорта - борьбе с ленью
![]() По поводу ошибок, грязности кода и прочее - это совершенно нормальное явление. Тем более для тебя, как для начинающего. После того, как интерпретатор придёт в более-менее устаканившееся состояние, в любом случае нужно будет выделить время и заняться генеральной чисткой мусора. Потому как без этого дальнейшее развитие будет затруднённым По поводу неявного приведения типа. Приведение к более широкому типу - я в первый раз такое слышу. По стандарту, как мне казалось, всегда второй операнд приводится к типу первого. Т.е. int+double эквивалентно "int+(int)double". Но на всякий случай уточню Про GOTO я не зря разговор затеял. Потому как "хорошее" решение повлечёт за собой серьёзную переделку программы. Принцип останется тот же, но начинка немного поменяется. При этом ситуация "рабочая". Т.е. в реальной жизни с реальными коммерческими продуктами с похожей ситуацией сталкиваются часто Как у тебя реализованы IF'ы? То, что ты ввёл FI, даёт мне повод заподозрить, что одну из альтернатив ты просто пропускаешь без разбора. А потому, если в пропущенной альтернативе есть синтаксическая ошибка, то ты её в этот момент не поймаешь. А поймаешь только тогда, когда исполнение пойдёт по этой альтернативе. Сие означает, что твоя программа, содержащая синтаксическую ошибку, может довольно долго работать (к примеру, несколько дней), но потом сломаться из-за досадной опечатки. Понятно, что для тренировочной программы это мелочь, но вообще проблема серьёзная. Добавлено через 6 минут 49 секунд Изначально #pragma делал просто задачу из книги, в которой простенький разбор выражений с печатью результата. В одной из других тем, я спросил его, насколько серьёзно он собирается заниматься программированием. Он ответил, что серьёзно. А потому данную задачу я предложил ему "чуть-чуть" расширить, а потом это "чуть-чуть" вылилось в довольно серьёзную задачу. В книжках этого ты нигде не найдёшь (разве что готовое решение с краткими пояснениями). Ну и большая практическая польза была в том, что pragma в данном случае прошёл по пути, когда делается неправильное решение, потом переделывается на более правильное. При этом весь процесс работы он ведёт самостоятельно, я лишь делаю небольшие теоретические выкладки (которых тоже, к сожалению, в книжке скорее всего не встретишь). К тому же параллельно зацепляется очень много моментов по технике программирования: задача из нескольких модуле, правильная организация структур данных да и просто программирование на Си++. Всё это делается "под конкретного человека", потому как многие идеи и технические решения pragm'ы остаются за кадром. С моей стороны вся теоретическая часть в теме присутсвует. Так что если есть интерес, попробуй прочти всю тему с начала и повторить всё это безобразие на практике Добавлено через 1 час 52 минуты 30 секунд На текущий момент мне видится следующий порядок действий (именно в таком порядке):
Более далёкая перспектива
Добавлено через 6 часов 58 минут 9 секунд отом могу забыть. Ещё в линуксовом разделе заведи отдельную тему по Makefile. Покажу, как с использованием gcc строить автоматические зависимости от .h файлов (чтобы постоянно Makefile не хачить при изменении структуры include'ов) Добавлено через 13 минут 5 секунд Немного по стилю написания
Этот же кусок можно написать с проинвертированными условиями. При этом он будет выглядет линейно. А все нелинейные вызовы error - это "плохие" случаи, которые нас не интересуют. При таком написании получается, что мы идём по прямой и отметаем в сторону ошибки. А небольшой комментарий позволяет быстро и ненапряжно оценить код
1
|
||||||||||||
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|||
| 05.08.2009, 09:03 [ТС] | |||
|
ELSE я починил,дело было не в самой инструкции,а в неправильном алгоритме пропуска фигурных скобок в WHILE. Поэтому я сделал ключевое слово LOOP.Но вообще,со всем этим пропуском без проверки реальная проблема. Добавлено через 15 минут 16 секунд Насчёт Makefile я сделал тему Makefile: как с использованием gcc строить автоматические зависимости от .h файлов? надеюсь,никто не огорчится, в гугле ведь тоже много чего есть на эту тему,но то,что ты говоришь,довольно специфично..
0
|
|||
|
|
||||||||||
| 05.08.2009, 09:40 | ||||||||||
![]()
Чтобы было понятно, вкратце схематично опишу, что из себя приблизительно представляет промежуточное представление
Опять-таки это представление не совсем хорошее для интерпретатора. Оно больше подходить для случаев, когда строится какой-то промежуточный код: для компилятора или для интерпретатора с дальнейшим построением промежуточного кода. Реально язык у нас простой, а потому реально можно будет обойтись без дерева и сразу строить некое подобие промежуточного кода. Но я для начала предлагаю вариант именно через промежуточное дерево, потому как при таком подходе проще понять, что же это такое, промежуточное представление (да и в любом случае практический опыт, который пригодится в дальнейшем). Да и написал я его схематично для того, чтобы у тебя было хоть какое-то понимание того, что будет дальше. Пока будешь разбираться с тестированием, эти знания в голове утрясутся. Почему так работает мозг - хз, но это действительно так Работу скриптов так же лучше обсудить в отдельной теме
1
|
||||||||||
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
||||||||||||||||
| 09.08.2009, 17:10 [ТС] | ||||||||||||||||
|
В-общем я сделал темку насчёт скриптов тестирования,начал искать - очень много информации,это новый язык по сути.
Мне,наконец,удалось заполнить буфер для функции,я долго бился об непонятную проблему,да и вообще разбирался с буферизацией.Проблема вообще странная.У меня был такой исходник:
0
|
||||||||||||||||
|
|
||
| 09.08.2009, 17:31 | ||
|
По поводу &. Я плохо разбираюсь в си++, но проблема, возможно, в следующем. Без & ты весь вектор передаешь по значению, т.е. формируется копия. При создании копии вектора вызывается конструктор копии для каждого элемента. Может где-то в конструкторе Variable тащится выделение памяти, которая затем не освобождается?
А вообще, глядя на подобные коды во мне всё больше крепнет уверенность, что какие-то вещи всё-таки надо писать на Си. В том плане, что реально используется компилятор Си++, но при этом код выглядит как код на Си. Ибо все эти stl'вские конструкции в данном месте вносят больше проблем, чем пользы. Либо это нужно как-то правильно переписывать, но я, не имея опыта работы на Си++, не могу сказать как именно В любом случае исходники интерпретатора надо будет причёсывать Добавлено через 1 минуту 37 секунд Програма в какойто момент времени начинала превращаться в большой набор всяческих затычек. А поскольку никаких комментариев не было, то через 3 дня уже ничерта невозможно было понять, как это работает (и работает ли)
1
|
||
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|
| 09.08.2009, 18:01 [ТС] | |
|
Ну вот ещё не хватало,чтобы мой код кого-то отверг от С++
С++ со своей STL мне кажется весьма удобным средством,для самых ленивых и для профанов.Но,конечно,порой тонкости весьма сложны.Если ты заметил,в моём коде ни разу(!) не используется оператор delete.А new стоит на каждом шагу.Вот это и требует изменения,только вот я пока не знаю,как.Может имеет смысл сделать некоторые переменные static(те что не попадают в вектор),и тогда можно будет освобождать память в следующем узле.Но я не уверен,можно ли так сделать.А вот с переменными,которые попадают в вектор,довольно интересная ситуация.Мы выделяем память,указатель на эту память помирает,но сама память попадает под управление контейнера,то есть к ней возможен доступ через контейнер,и может быть,это как раз случай,когда delete не нужен?
0
|
|
|
|
||||
| 10.08.2009, 14:00 | ||||
|
Добавлено через 18 часов 37 минут 50 секунд Для истории: тема про svn: Вопрос по svn (Subversion) тема про тестирование: Создание системы тестирования ПО.
1
|
||||
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|
| 13.08.2009, 21:51 [ТС] | |
|
Я тут немного подзастрял на функциях.Система тестирования ещё в процессе.
Я сделал определение функции,и поскольку мало смыслю в работе с буферизацией(попробовал и так и так,но в итоге решил,что проще отказаться от этого варианта),я подумал будет проще просто запоминать место в коде,где начинается тело функции,а после разбора тела функции и получения результата возвращаться назад в то же место в коде,где были раньше.Что-то вроде того.Написал всё,поменял функцию,отвечающую за rValue в выражениях,чтобы сделать возможным вызов функций в выражениях.Дошёл до реализации разбора самого тела внутри экземпляра класса.И вот тут встал такой вопрос: привызове функции ведь нужно использовать локальные переменные,поэтому получается,что нельзя использовать syntax_parser,ведь он работает с глобальными переменными программы,или тогда придётся отказаться от идеи локальных переменных,но тогда будет не так интересно,или,как второй вариант,писать отдельный парсер специально для функций,так,получается?Иначе как объяснить парсеру,что он работает внутри тела функции и все переменные находятся внутри экземпляра класса,который его вызвал?
0
|
|
|
|
||||||
| 14.08.2009, 09:53 | ||||||
|
Насколько я понял, вызов функции ты хочешь инерпретировать прямо из файла. Но при таком варианте задолбаешься с этим работать и вскоре интерпретатор превратится в болото. Полезно было бы это попробовать, дабы поиметь негативный опыт, но тут слишком много времени уйдёт в пустую, а последствия разгребать будет сложно
Тут надо работать через промежуточное представление. Хотя всё равно будет возникать вопрос о заведении переменной - в глобальной части или в локальной. Вообще, об этом я уже писал (пост 37, предпоследний абзац). Если перевести на текущее положение дел, то фактически тебе надо будет иметь две таблицы переменных (два вектора, или как у тебя называется). Локалы записываешь в локальную таблицу,глобалы в глобальную. При поиске переменной по имени сначала проверяешь в локальной таблице (если ты внутри процедуры), а потом в глобальной. При завершении работы процедуры локальная таблица удаляется Если делать промежуточное представление, тот это место немного меняется. У тебя появляются три вещи. Таблицы переменных непосредственно, которые будут жить на протяжении времени жизни всей программы. А из промежуточного представления будут торчать обращения в одну из таблиц переменных. Второе - таблица символьных имён (о ней чуть ниже). И третье - таблица текущих значений: у тебя же процедура может рекурсивно саму себя вызывать, а у каждой активации процедуры своё значение переменных (об этом тоже ниже) В итоге будем иметь что-то типа того в качестве промежуточного представления. Я пишу в своих упрощённых терминах, а дальше ты корячься со своими Си++'ными векторами и т.п. ![]()
Теперь таблица значений. В чём-то смысл похож на таблицу имён, только таблица о сути хранит набор всех значений (struct Value) для переменных текущего контекста. Одна таблица будет хранить набор значений для глобалов и будет жить всегда. В глобальной переменной будет торчать ссылка на struct Value, которая за всё время работы не поменяется (имею ввиду, что из переменной всегда будет торчать ссылка на одну и ту же запись Value). При входе в процедуру в момент ИНТЕРПРЕТАЦИИ (не парсенья) заводится новая таблица значений (каждое значение прописывается как Неинициализированное), а в представлении обходятся все локалы процедуры и поля value замыкаются на соответсвующую запись в твблице значений. При выходе из процедуры таблица значений удаляется (а ссылки на Value внутри локальных переменных на всякий случай устанваливается в NULL). Таким образом мы сможем рекурсивно вызывать процедуру? при каждой активации будет заводиться новая таблица значений (которая по большому счёту выполняет роль окна в стеке, как если бы это был код из-под компилятора). Тут есть тонкий момент: при рекурсивном возврате нам нужно уметь восстанавливать правильные связки "переменная-значение". Т.е. в момент интерпретации операции CALL нужно каким-то образом сохранить эти привязки переменной к значению, а после возврата - восстановить.Смысл этого понятен - в представлении (как и в тексте программы), локальная переменная присуствует в количестве одной штуки, но в момент исполнения их может быть несколько (из-за того, что может быть несколько активаций процедуры) После всего написанного - ты ещё горишь желанием связываться с процедурами (и локальными объектами в них)? Потому как есть простые версии бейсика, где процедур как таковых нет. Формально они есть - за счёт оператора GOSUB (уход на подпрограмму), но при этом нет понятия локльной переменной, а потому работа ведётся через глобальные. Для использования это неудобно, т.к. не является полноценной процедурой, но очень и очень сильно упрощает интерпретатор. Именно поэтому я тебе изначально предлагал не связываться с процедурами. Не потому что это трудно по своей сути, а потому что для начинающего слишком большой объём работ, который тяжело выполнить аккуратно
1
|
||||||
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|
| 14.08.2009, 13:23 [ТС] | |
|
Тут еще есть одна неувязка.Я почитал,что ты писал про промежуточное представление,а также последний пост,и подумал,а ведь промежуточное представление это не меньший геморрой,ведь внутри некоторых стэйтментов могут быть вложенные инструкции,а сколько их,заранее не известно.. Есть такая идея - просто модифицировать синтаксический парсер так,чтобы он проходил исходник 2 раза,используя некое логическое значение.Просто нужно хорошенько подумать,какие операции делать в первом проходе(то есть создавать ли переменные,ведь нужно проверять их на инициализацию и т.д.).Или просто сделать какие-то исключения только для пропускаемых блоков,и проходить по блоку в любом случае,просто затем освобождать переменные и не делать печати и т.д.Это бы позволило сократить объём работы,и продвигаться в чём-то ещё(например интерпретация различных вариантов ошибок и т.д.).Или ты считаешь,что без промежуточного представления невозможно двигаться дальше,и переделка начинки необходима ?
0
|
|
|
|
||||
| 14.08.2009, 13:43 | ||||
Но пока мне кажется именно так. К тому же в таком варианте гораздо проще приделать встроенный отладчик (понятно, что довод про отладчик не стОит учитывать при выборе метода, ибо хз когда до него доберёмся, если доберёмся вообще)Сейчас как бы не получилось так, что ты замахнулся слишком высоко, а потом это реализоватьне получится. Вариант с двумя проходами по файлу вот ещё чем хорош. Поскольку нет промежуточного представления, то внутренние структуры данных не будут претерпевать сильных изменений, в случае если делать язык без процедур, а потом добавить процедуры. В идеале меняться не должо ничего, только добавляться
0
|
||||
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
||||||||
| 14.08.2009, 14:18 [ТС] | ||||||||
.Так что я за парсинг два раза,просто пока отказываемся от процедур.Я пока стараюсь немного причесать код,кое-где подправил условия,как ты предложил,так действительно лучше(проинвертированные условия),также добавил работу с препроцессором,что немного уменьшило выходной файл.Ещё я поубавил отступы,код выглядит поплотнее,но не знаю,я только надеюсь,что это не ухудшило читабельность,мне то трудно судить,я его уже знаю от и до ..
0
|
||||||||
| 14.08.2009, 14:18 | |
|
Помогаю со студенческими работами здесь
80
пишем свой троян с нуля Пишем свой класс, спецификатор доступа 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/
|