![]() |
|
Модераторы: Daevaorn |
![]()
|
|
| Fixin |
|
|||
![]() Ёжик ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1357 Регистрация: 6.1.2004 Репутация: 2 Всего: 18 |
Мне нужно сделать интерпритатор скриптового языка (условного, нужного для проги). Язык со структурами и функциями. Структуры данных меня не интересуют. (а то все с этого начинают). Мне нужна инфа по разбору выражений (матических) и по вызову функций (подпрограмм) и организация эмуляции цикла. Свои мысли есть, но хочу ознакомиться с опытом других людей.
Короче, нужны исходники с примерами и разъяснениями по этому всему на человеческом языке. За**ся разбирать заумные стать про "слово, являющимся своим концом"! Начинают вообще с поиска подстроки. Не надо ругаться, знаю что где-то об этом кучу написали, но сам найти не могу. Хелп мни! |
|||
|
||||
| ManiaK |
|
||||
![]() Homo Sapience ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1145 Регистрация: 3.8.2004 Где: ИУ5-93 Репутация: 5 Всего: 29 |
Fixin, сам когда-то читал книжки по этой гадости и так же как и ты ничего не понял. Зато потом, примерно месяц назад захотелось написать свой язычок программирования и, без книг, сам во всём разобрался. Всё намного проще, чем они там расписывают..
Берём допустим выражение:
И рассуждаем: как мы его считаем? Сначала считаем то, что в скобках, потом операции приоритетом ниже и так далее до самых простых - сложения и вычитания. Получаем такой алгоритм: 1. Выделяем все выражения с наивысшим приоритетом. В нашем примере: (3+1) и (6+7). 2. Откидываем скобки, для каждого запускаем пункт 1. 3. Если скобок больше нет - находим плюсы и минусы (умножение/деление и пр. прелести не описываю - додедуктируешь). Точнее нужно получить первое слагаемое, второе и операнд. Второе слагаемое - только последние части (в нашем примере в скобках из пункта 1 это 1 и 7). Для первого операнда - всё остальное. [3+5] - [8] ^ 1-ое слагаемое ^ второе слагаемое 4. Для первого слагаемого запускаем пункт 3. 5. Считаем, подставляем вместо выражения результат. И так пока всё не посчитаем. Коряво описал, но пока лучше не могу. С умножением и делением додумать несложно по тому же принципу. Оно будет между скобками и сложением/вычитанием. Вот отрыл раннюю версию своего парсера, там только сложение/вычитание и скобки. Зато принцип.
Этот вариант лучше парсеров, приводимых в книгах Б. Страустропа и Г. Шилдта тем, что считает выражения с разными типами (плавающей точкой и целые). Разумеется это только набросок, скорее всего там есть глюки, но идея, думаю, должна быть ясна. |
||||
|
|||||
| Любитель |
|
|||
|
Программист-романтик ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 3645 Регистрация: 21.5.2005 Где: Воронеж Репутация: 24 Всего: 92 |
Я, конечно, не профи, но подобное писал, поэтому скажу кое-что. Во-первых, для выполнения скрипта есть 2 способа:
1. Преобразовать его во внутренний код (со всякими условными, безусловными переходами и пр.), а затем выполнить; я делал так. 2. Выполнять непосредственно команды скрипта. Как я понял, тебе нужен 2ой способ. При считывании скрипта из файла его не плохо бы сразу разбить на команды, получим массив команд. Тогда же надо отметить границы различных блоков (тех же циклов, например). То есть встречаем команду начала блока - кидаем её в стек (точнее её №), при закрытии блока ставим в команду его начлала адрес конца (№ элемента массива), добавляем команду конца, где указываем адрес начала (вроде ENDBLOCK 17) и убираем № из стека. Инициализируем счётчик команд 0 (№ следующей выполняемой команды). Выполняем циклом команды, пока счётчик не дойдёт до несуществующего эелемента (счётчик==количество_элементов_в_массиве) или очередной командой не будет завершение скрипта (вроде exit). После каждой команды, естественно, увеличиваем счётчик на 1. Циклы при таком подходе работают довольно просто: при выполнении команды while (с другими циклами принцип тот же) вычисляем выражение, приводим его к целому типу, если оно равно 0, присваиваем счётчику команд номер команды конца блока (после добавления 1 это будет 1ая команда после цикла), иначе ничего не делаем (1 к счётчику команд прибавляется всегда). При выполнении команды ENDBLOCK, если она указывает на while присваиваем счётчику команд адрес While минус 1. Выражения. Где-то на форуме (по-моему где-то в билдере) давали ссылку на страницу с обсуждением парсинга выражений. Я её тогда сохранил себе. Выкладываю здесь. Сам я, правда, не читал, что там есть. Как это делать по моему. Во-первых ищем открывающую скобку, ближайшая скобка после которой вообще - закрывающая. Если перед скобкой (пропуская пробелы, табы и пр.) стоит не знак операции, то это либо вызов функции (это отдельный вопрос), либо синткасическая ошибка. Если там знак операции, тогда вычисляем выражение в скобках (само оно бесскобочное) и заменяем всю эту скобку на значение. В итоге получим бесскобочное выражение. Самое главное - вычисление бесскобочного выражения. Первым делом надо вычислить однооперандовые операции (в порядке приоритета) и ?:. Затем есть много способов. С ипользованием внутреннего кода (как делал я) будет, конечно, по другому, а так можно сделать поиск всех операций (в порядке приоритета), учитывая всякие пробелы, вычислить простые бинарные операции (это, я думаю, не сложно) и заменить в выражении их значениями. Вот, наверно, всё. Если тебе всё же интересно использование внутреннего кода, могу прислать setup от того, что я делал на выпускной экзамен по информатике 3 месяца назад, кстати написав программу на этом языке и скомпилировав, получим *.elic файл, который (если программа установлена setup-ом или корректно всё прописано вручную) запускается двойным кликом Присоединённый файл ( Кол-во скачиваний: 8 )
parsear.zip 3,12 Kb |
|||
|
||||
| maxim1000 |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 3334 Регистрация: 11.1.2003 Где: Киев Репутация: 17 Всего: 110 |
помнится, в книге Страуструпа "Описание С++" парсер использовался в качестве примера...
...Глава 6 -------------------- qqq |
|||
|
||||
| ManiaK |
|
|||
![]() Homo Sapience ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1145 Регистрация: 3.8.2004 Где: ИУ5-93 Репутация: 5 Всего: 29 |
maxim1000 даже Страустроп не смог нормально объяснить, как этот алгоритм работает. Во всяком случае терминология в русской версии была чертовая...
|
|||
|
||||
| gm |
|
|||
|
Unregistered |
Если просто потренироваться, то сюда: http://algolist.manual.ru/syntax/index.php
Может нужно что-либо вроде этого: http://root.cern.ch/ (С++ интерпретатор) ? |
|||
|
||||
| Fixin |
|
||||
![]() Ёжик ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1357 Регистрация: 6.1.2004 Репутация: 2 Всего: 18 |
Хе
Скриптовый будет преобразовываться в бинарик по типу асмовской компиляции (или как в Java). Так вот, парсер мне нужен такой, чтоб выражение мог превратить в набор простых последовательных операций, поэтому я склоняюсь к методу обратной польской нотации, но в таком виде: Есть выражение
А с циклами я разобрался, остались функции. Добавлено @ 17:36 По этим ссылкам я был, когда искал. но Спасиб. |
||||
|
|||||
| Void |
|
||||||
![]() λcat.lolcat ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2206 Регистрация: 16.11.2004 Где: Zürich Репутация: 40 Всего: 173 |
Еще как переведешь
будет переведено примерно в такую последовательность команд:
Результат окажется на вершине стека. Циклы и функции для такой виртуальной машины тоже реализуются сравнительно просто. (Параметры передавать на стеке, результат возвращать на вершине стека). Вот пример маленького скриптового языка, реализованного с помощью Spirit: DScript P.S. А можно поинтересоваться для какой конкретной задачи это нужно? Может статься, удобнее будет прикрутить существующий скриптовый язык, например Lua с помощью Luabind. Это сообщение отредактировал(а) Void - 26.7.2005, 19:32 -------------------- “Coming back to where you started is not the same as never leaving.” — Terry Pratchett |
||||||
|
|||||||
| ManiaK |
|
|||
![]() Homo Sapience ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1145 Регистрация: 3.8.2004 Где: ИУ5-93 Репутация: 5 Всего: 29 |
Fixin а мы с тобой одной ерундой страдаем
Ты хотишь написать фактически транслятор в псевдокод? Дык может состыкуемся? Я в ближайший месяц только этим и заниматься буду (практически). "Вдвоём вселей" Я пишу для Си++-подобного языка (синтаксис очень похож). Добавлено @ 20:20 У меня идея на днях возникла: для каждой выполняемой такой проги полностью эмулировать 8086. Для моих задач больше возможностей не нужно, зато можно будет транслировать не в псевдокод, а даже во что-то осмысленное. Хотя это снижает эфективность - ведь в чистом псевдокоде можно своих команд понатыкать удобных... |
|||
|
||||
| Fixin |
|
||||
![]() Ёжик ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1357 Регистрация: 6.1.2004 Репутация: 2 Всего: 18 |
На счет стековой машины... странная штука какая - программирование - почему, после столькой литературы по стековому парсингу, я об этом не догадался. Спасибо
|
||||
|
|||||
| Void |
|
|||
![]() λcat.lolcat ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2206 Регистрация: 16.11.2004 Где: Zürich Репутация: 40 Всего: 173 |
Fixin
Существующие решения вполне бы подошли (тот же Lua или даже Prolog). Но раз уж "just for fun", то - святое дело P.S. Я надеюсь, генераторы парсеров - это не "не интересно" Это сообщение отредактировал(а) Void - 26.7.2005, 21:43 -------------------- “Coming back to where you started is not the same as never leaving.” — Terry Pratchett |
|||
|
||||
| Fixin |
|
|||
![]() Ёжик ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1357 Регистрация: 6.1.2004 Репутация: 2 Всего: 18 |
Не сказалбы, что сейчас весело
|
|||
|
||||
| Fixin |
|
||||||
![]() Ёжик ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1357 Регистрация: 6.1.2004 Репутация: 2 Всего: 18 |
Возникла проблема с унарным минусом:
Теперб выходные строки исправил. Это сообщение отредактировал(а) Fixin - 28.7.2005, 18:15 |
||||||
|
|||||||
| ManiaK |
|
|||
![]() Homo Sapience ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1145 Регистрация: 3.8.2004 Где: ИУ5-93 Репутация: 5 Всего: 29 |
Fixin чем тебя не устроил мой метод, я не понимаю?
Сравни с тем, что я приводил сначала - один-в-один почти. Приоритеты, унарные операции работают сами собой. Этот алгоритм содран с человеческого; что думаем - то и пишем. Может я, конечно, что-то упустил... |
|||
|
||||
| Fixin |
|
|||
![]() Ёжик ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1357 Регистрация: 6.1.2004 Репутация: 2 Всего: 18 |
Ну. да, метод хороший
|
|||
|
||||
![]()
|
| Правила форума "С++:Общие вопросы" | |
|
|
Добро пожаловать!
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | C/C++: Общие вопросы | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |