Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
||||||||||||||||||||||||||||||||||||||||||||||
1 | ||||||||||||||||||||||||||||||||||||||||||||||
Пишем свой интерпретатор языка BASIC20.06.2009, 20:03. Показов 237724. Ответов 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 секунд Пришлось решать влоб с дебаггером.У Страуструпа опечатка (или намеренная ошибка,что более вероятно ![]()
Добавлено через 16 минут 19 секунд И ещё опечатка была
31
|
|
20.06.2009, 20:03 | |
Ответы с готовыми решениями:
464
Пишем свой интерпретатор языка BASIC
Пишем свой чекер пишем свой троян с нуля |
Флудер
194 / 32 / 11
Регистрация: 23.03.2007
Сообщений: 334
|
|
20.06.2009, 20:06 | 2 |
вот сейчас открыл книгу - нет там никакой опечатки, всё верно. это у вас была опечатка
а неявное преобразование для кода ошибки вполне приемлемо
10
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|
21.06.2009, 12:26 [ТС] | 3 |
Значит,у вас версия книги новее))
7
|
![]() 2924 / 1273 / 114
Регистрация: 27.05.2008
Сообщений: 3,465
|
|
21.06.2009, 12:30 | 4 |
Странный какой-то дебаггер..... Если условие (1) выполнилось, происходит не переход к switch, а выход из функции get_token() с возвратом значения END.
9
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|
21.06.2009, 12:32 [ТС] | 5 |
Да,я уже понял,что ступил)
7
|
![]() ![]() |
|
21.06.2009, 21:58 | 6 |
#pragma, а ты все задания просто передираешь из книги или всё-таки что-то пытаешься сделать сам? Вопрос задаю НЕ с целью, чтобы сказать "ай-ай-ай". Просто ты уже кучу вопросов вских задавал. Если ты действительно решил серьёзно занаться программированием, то постараюсь отвечать ещё более развёрнуто. Если интерес несерьёзный - то как обычно
![]()
10
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|
21.06.2009, 23:27 [ТС] | 7 |
Конечно,пытаюсь делать сам(в этом примере первым порывом было написать вообще по-своему),просто такое задание в книге(я учусь по ней и стараюсь выполнить все задания для начала) - заставьте работать данный код калькулятора,ну что я могу сделать? )) Просто в данном конкретном случае я немного не дотянул до решения,надо было ещё немного поковырять код до понимания(буду стараться впредь).Я даже специальную тему поднял,типа почему нельзя писать [решено] в первом сообщении темы,чтобы другие не тратили на это время.Согласен,некоторые мои вопросы из разряда тех,что "вот тут недодумал,вот тут недонапрягся",но некоторые действительно требуют хороших ответов.Я учусь сам,посоветоваться не с кем,надеюсь только на лучшее,и очень ценю любую помощь,особенно помощь настоящих хакеров.Интерес серьёзный,хочу достигнуть хорошего уровня.Не только в С++,но в программировании вообще.
P.S.Твоё "как обычно" тоже круто для меня )) но мотаю на ус всё сказанное и написанное)
4
|
![]() ![]() |
|
22.06.2009, 12:06 | 8 |
> но мотаю на ус всё сказанное и написанное)
Ну вот это самое главное. Остальное со временем придёт Добавлено через 12 часов 27 минут 44 секунды Наверное в страуструпе есть и дальнейшее развитие этой задачи. Со своей стороны могу дыть 3 предложения по дальнейшему апгрейду
4
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|
22.06.2009, 22:28 [ТС] | 9 |
3
|
![]() ![]() |
|
22.06.2009, 23:44 | 10 |
По возрастающей сложности (как мне кажется)
1. Работать со входным файлом (т.е. фактически получается некий простенький интерпретатор). Выдавать пользовательские ошибки с прявязкой к исходнику: т.е. печатать имя файла, номер строки, номер позиции в строке (последнее некритично), суть ошибки. Использование неинициализированной переменной считать ошибкой. При этом добавить конструкцию "print <var_name>". На вход программы подаём имя файла с текстом программы, которую будем интерпретировать 2. Заменить плавающий типа (double) на целочисленный и добавить операции битовой арифметики: & | ~ << >>. Приоритет операций такой же, как и в си (можешь посмотреть в том страуструпе). 3. Сделать типизацию. Т.е. понимать как плавающие типы, так и целые. При первой записи в перменную, её тип вычисляется по типу выражения, стоящей в правой части присваивания. Т.е. для "a = 5" переменная a заводится как целочисленная, для "a = 5.0" - как плавающая. Все дальнейшие присваивания в переменную делаются с учётом типа. Т.е. если изначально переменная была как целочисленная, то операция "a = 23.2" означает запись целого значения 23 (потому как a целое). При вычислении двухоперандногй операции выражения, второй операнд должен приводиться к типу первого операнда. Т.е. "12 + 34.5" должно вычисляться как (пишу в терминах си) "12 + (int)34.5", а "12.1 + 7" должно вычисляться как "12.1 + (float)7". При попытке построения битовых операций над плавающим типом выдавать ошибку (ибо считаем, что битовые типы разрешены только для целых чисел) Может быть эти задания тебе покажутся сложными, но всё же рекомендую сделать все три. Потому что это тебе сильно поможет в освоении проектирования программ. Если от этого не устанешь, а меня не заломает - попробуем дальше это дело наворотить. Таким образом, писать программу следует с учётом того, что её функциональность будет расширяться - это ещё добавит экспы в части проектирования. Да и на своих же ошибках, возможно, начнёшь лучше понимать, как НЕ надо делать
5
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
||||||||||||||||||||||||||
25.06.2009, 19:10 [ТС] | 11 | |||||||||||||||||||||||||
Итак,после длительного биения об стену
![]() 1)Программа читает входной файл,но как она это делает,я понятия не имею,потому что делал по описанию библиотеки из и-нета http://www.cplusplus.com 2)Есть некое подобие привязки к исходнику,есть сообщение об ошибке,но иногда работает некорректно из-за этих каскадных вызовов... 3)Я попытался добавить возможность программируемых пользователем функций,но в самом конце выяснилось,что это не работет,опять же из-за подобия рекурсии.Так как анализ посимвольный,после знака $ должно происходить вычисление,но при последующем вызове expr(true) происходит дальнейшее чтение строки и в итоге ошибка. 4)В функции get_resulting_expr (она ещё не доделана) ошибка в алгоритме(не заменяется последний параметр). 5)Задания твои я попытаюсь сделать,просто я ещё,например,понятия не имею о битовых операциях. 6)В-общем,пока не знаю,как всё это разгребать.Писалось всё это с целью просто сделать,хотя бы сделать,а не как сделать...На данный момент есть код: LexicalAnalyzer.h
LexicalAnalyzer.cpp
param_swapper.cpp
main.cpp
Входные данные в файле program.clc program.clc
0
|
![]() ![]() |
|
25.06.2009, 19:55 | 12 |
А можешь скомпилить бинарник, а то в этих чёртовых билдарах я не пойму, как консольное приложение сделать. Чисто интересно посотмреть
Для порядка разберись. В идеале надо это самому ручками написать, чтобы всё-таки понимать, что же там делается Вроде бы мелочь, но в результате надо тоже добиться нормальной работы. Как показывает практика, человеческий пользовательский интерфейс зачастую сделать куда труднее, чем внутреннюю логику. Я бы на твоём месте выхов функций пока отложил. Оно слишком геморно, чтобы аккуратно сделать. Я понятия не имею, как оно у тебя работает, но сильно подозреваю, что у тебя в месте вызова фактически подставляется тело функции. Т.е. вызов по сути нечестный (рекурсию таким образом не сделаешь) Суть была не втом, чтобы сделать битовые функции, а втом, чтобы добавить ещё один уровень приоритета. Чтобы понять, насколько хорошо ты усвоил разбор выражений. Ну и вторая часть смысла битовых операций - они только целые, т.е. уметь запрещать класс операций для какого-то типа данных (в данном случае запретить битовые операции для плавающих чисел) А ты не спеши. И разгребай по-тихоньку. Чем дольше ты будешь сидеть над программой, тем лучше начнёшь её "чувствовать". А начиная с какого-то момента появится стойкое ощущение, что какие-то места надо переделать. В этом случае не ленись и переделай Добавлено через 1 минуту 52 секунды Я собственно задание то со следующей целью дал. Вот ты сделал код по книге. А задание - это чтобы доработки сделать самому и без книги
2
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|
25.06.2009, 21:10 [ТС] | 13 |
Ладно,функции пока оставлю,буду потихоньку дальше продвигаться.Бинарник прилагается.
0
|
![]() ![]() |
|
25.06.2009, 21:43 | 14 |
А сам Exe'шник где? Если Calculator нужно просто переименовать в *.exe, то у меня он что-то завис
Добавлено через 1 минуту 0 секунд Пишет "Program too big to fit in memoty" Добавлено через 3 минуты 53 секунды Под линухом скомпилялось и запустилось. Щас вот только разберусь, как русские сообщения нормально печатать Добавлено через 10 минут 58 секунд Когда я делал поставновку задачи, для первого пункта я имел в виду следующее. Ты имеешь файл Код
a = 1 b = 2 c = a + b print c А так для начала очень даже неплохо. Правда пока, насколько я понимаю, тут в основном чужой код, но, тем не менее, начало положено. Я исходники не смотрел, только запускал программу. Даже деление на ноль отловилось. Из ошибок отловил только неправильную реакцию на "a=2.2.2" Добавлено через 2 минуты 31 секунду Но использование неинициализированной переменной нужно запретить. Скорее для тренировки в отработке ошибочных ситуаций, чем для практики (т.к. большинство интерпретируемых языков позволяет использовать неинициализированные переменные)
1
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|||||||||||||||||||||
28.06.2009, 02:43 [ТС] | 15 | ||||||||||||||||||||
1) Кое-что удалось сделать.Добавил битовые операции &,^,~,|,но способ,которым это сделано,мне не нравится.Вообще,вся эта программа-тихий ужас,не дай бог вот над такими программами придётся когда-нибудь сидеть и разбираться)) Кстати,результат проверить не мешало бы,но я поглядел по аналогии (в отдельной программе),вроде бы корректно.
2) Добавил вывод переменной на экран по желанию пользователя.Это делается командой #<var name> .Я до сих пор не додумался(мало думал?),как сделать интерпретацию нескольких символов подряд,"не теряя при этом нити беседы" - то есть чтобы предотвратить вызов посимвольно во время интерпретации зарезервированных слов.Как-то я поставил на все 300 с лишним строк программы точки разрыва для дебаггера,и у меня получилось,что,например,при попытке вычисления функции (case $: )после записи её тела в строку и возврате строка продолжает читаться,но в предыдущем вызове.Короче там такая путаница,ё-маё ![]() 3)Добавил возможность комментариев,это делается значком "(двойной апостроф),всё,что после значка,игнорируется. 4)Есть ограничение на битовые операции с числами с плавающей точкой.Типизацию пока не сделал.Просто хочется сделать наподобие "int x=1;" но всё упирается в проблему,описанную ранее. 5) Запретил использование неинициализированных переменных,а также программа прерывается после первой ошибки. 6)На данный момент программа такова: LexicalAnalyzer.h
LexicalAnalyzer.cpp
param_swapper.cpp
main.cpp
Входные данные: program.clc
#~0 "Печатаем дополнение нуля
a=3 b=4 "This is comment "Это комментарий #a "Ура!Каменты! : ) "Это тоже комментарий
0
|
![]() ![]() |
|
28.06.2009, 12:08 | 16 |
Код
a=10 b=11 c=12 d=13 e=a+b|c*d #e Код
Строка: 6 Ошибка: Неинициализированная переменная 0 2. Когда пишешь "неинициализированная переменная", надо ещё указывать, какая переменная. Написано, что строка 6 "#e", я могу догадаться, что это e. Но если бы ошибка была на строке 5, а там выражение из тридцати слагаемых, то надо долго разбираться, что же там неинициализировано. 3. В случае ошибки программа по прежнему отрабатывает до конца. Советую этот вопрос долго не откладывать, а отработать для себя механизм выдачи пользовательской ошибки, потому как чем раньше ты это сделаешь, тем меньше в будущем надо будет переделывать Когда доведёшь до более-менее логически завершённого состояния, не поленись переписать свои коды по-человечески. Только работающий исходник при этом законсервируй, чтобы всегда его можно было восстановить. Можешь просто rar'ом закатать. В идеале - положить под управление системы контроля версий (типа svn), но сейчас если ты в это полезешь, можешь много времени потерять на то, чтобы разобраться. Правда потерянное время себя оправдает И вообще, лучше пиши программу исходя из того, что в ней будет копаться кто-то ещё, кроме тебя (даже если в жизни этого не произойдёт) - приучай себя к этому. Поясни на конкретном примере, а то в общих словах я ничего не понял Следующий код отрабатывает без ошибок (хотя там число с плавающей точкой) Код
a = 10.0 | 11 Если вдруг ты ещё не понял, я хочу протолкнуть твою программу до интерпретатора бэйсика. Конечно же полноценный бэйсик не получится, но некое его примитивное подобие - а почему бы и нет? Поэтому я сначала хочу от тебя добиться стабильной работы твоей программы в простейших случаях (запись в переменные, их чтение и печать, выдача ошибок). Дальше попробуем навести некий структурный порядок в том, что ты сделал, а потом попробуем продвинуться дальше. Я специально продивгаю по чуть-чуть. Чтобы с появлением каждых новых фич тебе приходилось что-то в программе серьёзно переделывать. Только так можно научиться правильно строить программу с точки зрения её архитектуры. А мозг устроен так, что сначала нужно много раз сделать неправильно, чтобы чётко понимать в дальнейшем, как же нужно делать правильно Добавлено через 2 минуты 58 секунд А код по процедурным вызовам удали пока, чтобы не мешал. Ибо это большой паравоз, прицепленный к твоей программе, который ты пока не знаешь как работает - он только занимает место и мозолит глаза ![]() Добавлено через 10 минут 40 секунд Кстати, положи к себе в проект ещё и текстовый файл, в который будешь складывать все найденные ошибки. А исправленные ошибки переносить в другой файл (но не удалять - для истории полезно их сохранить)
1
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|||||||||||||||||||||||||||||||
29.06.2009, 01:02 [ТС] | 17 | ||||||||||||||||||||||||||||||
Хотел уточнить свои слова насчёт проблемы с вызовом функций(ну очень хочется доделать)
В-общем как я понимаю в данном конкретном случае проблема сводится к тому,как правильно послать готовую строку (которую я уже приготовил для вычисления,например "a*b") обратно в поток ввода.То есть у меня получается что когда из функции get_token() возвращается значение FUNC,за этим следует вызов expr(true) с последующими вызовами get_token(),но в потоке для чтения нет строки,которую я приготовил и отослал функцией putback в строке 342: source.putback(::result_expr[j]); В итоге при прилагаемых входных данных программа печатает 'a',которая следует за именем функции и находится в списке параметров,а моя готовая строка ещё до этого куда-то девается..Вот я думаю может я неправильно это сделал(в смысле работал с потоком)? Вот прилагаю исходник,если не лень поглядеть,конечно.А насчёт svn это в интернете репозиторий создается,навроде как в launchpad сделано?Бесспорно,это удобнее...есть ещё cvs какой-то. main.cpp
LexicalAnalyzer.h
LexicalAnalyzer.cpp
error_handler.h
error_handler.cpp
param_swapper.cpp
Входной файл: program.clc
a=10.6
b=2 @f(c,d){c*b} #$f(a,b)
0
|
![]() ![]() |
|
29.06.2009, 20:53 | 18 |
Видишь ли, такой подход он неправильный. Лексический разбор в таких простых случаях должен идти без putback'ов. Т.е. разобрал имя функции, разобрал левую скобку, дальше с текущей позиции запускается разбор выражения для параметра. Именно идёт разбор, а не формируется строка. Далее по выходу из процедуры разбора выражения ты будешь иметь уже вычисленное значение параметра, адальше тебе останется разобрать правую скобку, после чего сделать вызов. При этом в интерпретируемых языках, содержащих процедуры, как правило строится сначало некое промежуточное представление, а затем работа идёт на нём (без входного потока). Я, собственно, потому и предлагал тебе пока забить на вызов функций, потому как надо сначала до конца добить простые вещи. Но я тебе не навязываю своё мнение, если есть желание сделать функцию - попробуй
Я мельком пробегал. Моя идея состояла в том, чтобы довести до рабочего состояния то, что уже сделано. Затем привести в порядок структуру программы. Уже на текущий момент в программе имеется как минимум три логические единицы: грамматический анализатор, лексический анализатор и таблица переменных. И всё это пока свалено в одну большую кучу. Исходники погляжу дома. Но, вижу, уже обработка ошибок аккуратно выделена в отдельный модуль, т.е. процесс идёт и появляется понимание того, как надо делать аккуратную разбивку на отдельные независимые блоки Можно и на локальной машине ![]() Добавлено через 10 часов 14 минут 45 секунд Глубоко не смотрел, но поглядел поверхностно исходники. По теущему положению тебе действительно будет сложно дальше развивать интерпретатор. Со своей стороны могу тебе предожить для начала навести порядок. Затем чётко разбить на компоненты (потому как у тебя пока мешанина): аккуратно сделать механизм обработки ошибок, грамматический анализатор, лексический анализатор, разбиение на операторы (statement), коих у тебя пока работающих только два (оператор присваивания и оператор печати), таблицу переменных. Затем добавлять поддержку новых конструкций. Ну либо у тебя есть какие-то свои пожелания. Я вижу ты никак не угомонишься с процедурными вызовами. Моё личное мнение - по текущему состоянию их надо выкидывать, а потом попробовать добавить по-человечески. Либо добавить сейчас в том же виде, в котором ты пытаешься, с целью понять, что в таком бардаке поддерживать это будет слишком проблематично. Если есть какие-то идеи, вопросы и т.п. - не стесняйся, спрашивай. Пока я добрый, помогу ![]() Добавлено через 12 минут 53 секунды Для такого примера не ловит использование неинициализированной переменной b во 2-й строке Код
a=10.6 b=2+b #a #b Здесь в 3-й строке должна либо выдаваться ошибка, либо печататься все значения Код
a=10.6 b=2 #a b b b #b Аналогично долдна быть синтаксическая ошибка (ну или любое другое сообщение об ошибке) Код
b=2 2 Добавлено через 3 минуты 58 секунд Неправильно учитывается приоритет операций. Следующий пример демонстрирует это. При вычислении b поставлены скобки (которые по большому счёту не нужны, только для показывания в каком порядке должны идти вычисления). Оба выражения должны дать один и тот же результат Код
a=2+4|5*6 b=(2+4)|(5*6) #a #b Код
32 30
1
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
||||||
30.06.2009, 05:11 [ТС] | 19 | |||||
Пытаюсь избавиться от этой проблемы
1)Почему? 2) Как её поймать? Я уже успел поискать про машинную запись чисел с плавающей точкой,я так понимаю,этот ньюанс требует пересмотра посимвольного разбора с помощью putback? Где-то там по дороге эта точка и теряется между цифрами...
0
|
![]() ![]() |
|||||||||||
30.06.2009, 12:23 | 20 | ||||||||||
![]() Решение
Точка не должна отлавливаться. У тебя "10.0" должно идти как единая грамматическая единица (token). Собственно, потому я и предложил навести порядок, что логически у тебя некорректно написано.
Сейчас у тебя get_token выдирает число по одной циферке. Это не есть правильно. get_token за раз должен выдрать целиком грамматическую единицу. Т.е. если записано "123", то за раз будет выдрано "123", если "123.45", то "123.45". А вот если "123.45.67", то первая лексическая единица будет "123.45", а следующая "." (или ".67", если понимать дополнительный вариант записи плавающих чисел). Если это ключевое слово "print", то и будет "print" (с чем у тебя на текущий момент проблемы). Сейчас у меня под рукой нет формальных описаний, но если желаешь - ознакомлю тебя с формальными описаниями грамматики и лексики Добавлено через 1 минуту 40 секунд > Я уже успел поискать про машинную запись чисел с плавающей точкой,я так > понимаю,этот ньюанс требует пересмотра посимвольного разбора с помощью > putback? Нет. Как я уже писал, get_token за раз должен выдрать "123.45", котору затем стандартными функциями ты превратишь в плавающее число. Возможно, я пока объясняю слишком непонятно, но если ты морально готов к перелопачиванию своей программы, могу начать пояснять более подробно. Добавлено через 5 минут 0 секунд Хотя нашёл в инете пример формального описания грамматики. Так что если надо - могу вкратце пояснить суть работы грамматического анализатора Добавлено через 2 часа 51 минуту 6 секунд ============================================================ ==== В общем, появилось немного свободного времени на работе. Так что родил примерно следующее пояснение Есть две вещи разного уровня: грамматика и лексика. Грамматика - это по сути дела правила построения слов из отдельных букв. Лексика - построение предложений из слов (а последние построены по правилам грамматики) Давай рассмотрим простейший вариант того, какие грамматические единицы (token'ы) должны поддерживаться нашим интерпретатором:
Задача парсера, который по сути дела является грамматическим анализатором, является нарезка входного текста на слова (token'ы). При этом грамматический анализатор будет пропускать комментарии, ненужные пробелы и знаки табуляции. Мы будем считать, что один вызов GetToken (я всё-таки обзову именно так, чтобы не путать с тем, что сейчас есть у тебя) вынимает из входного потока одно слово (token). Как это будет представлено на уровне данных, пока не рассматриваем (чисто чтобы теорию понять) Вот для такого примера: Код
let a = 5.123 # комментарий print a
При этом комментарии за пределы парсера вообще не вылезают. Дабы остальным компонентам с ними не возиться Теперь, как это всё должно выглядеть технически. По результату вызова GetToken фактически должен возвращать в качестве результата некие два значения. Первым значением является непосредственное строковое представление слова, которое полезно для печати диагностики, отладки, а так же необходимо для разбора идентификаторов и констант. Т.е. для нашего примера этими строковыми значениями будут "LET", "A", "=", "5.123" и т.д. Вторым значением является значение некоего enum'а, которое удобно обрабатывать в виде целочисленного значения и которое является описанием того, что у нас записано в строке. Таким образом пара этих значений полностью описывает наш token Как конкретно сделать enum - зависит от того, как тебе удобно работать. Я бы сделал так:
В итоге интерфейс нашего грамматического анализатора будет примерно таким:
Ну и весь грамматический анализатор полезно выделить в отдельный файл Добавлено через 14 минут 34 секунды Вот примерное формальное описание грамматики: Код
Const = ConstInt | ConstFloat ConstInt = Digit { Digit } ConstFloat = Digit { Digit } "." Digit { Digit } Ident = Letter { Letter | Digit } Letter = "A" | "B" | ... | "y" | "z" Digit = "0" | "1" | ... | "9" KeywordLet = "LET" KeywordPRINT = "PRINT" Твой анализатор должен делать разбор, руководствуясь этими формальными правилами (глядя на них проще понмать, что в каком порядке должно разбираться). Исходя из этих правил, например, "12.ab" должно трактоваться как ошибка, потому как ни в одно правило такая конструкция не вписывается. Пробелы и знаки табуляции означают конец текущего слова. При этом получается, что "12. " опять-таки не вписывается, т.к. после десятичной точки мы требуем хотя бы одну цифру (хотя можем этого и не делать) Самая первая задача - научиться нарезать на слова в случае, когда нет грамматических ошибок. А уже потом пытаться отсекать ошибочные случаи
6
|
30.06.2009, 12:23 | |
Помогаю со студенческими работами здесь
20
Пишем свой класс, спецификатор доступа protected Интерпретатор небольшого языка программирования на С++ Не удается откомпилировать интерпретатор М-языка
Написать интерпретатор программного языка -помощь Интерпретатор/компилятор ассемблер-подобного языка Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |