Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

Пишем свой интерпретатор языка BASIC - C++

Войти
Регистрация
Восстановить пароль
Другие темы раздела
C++ Меню и список http://www.cyberforum.ru/cpp-beginners/thread41194.html
Здравствуйте форумчане. Помоги пожалуйста в следующем вопросе: У меня есть 2связный список, написано меню. Но в моменте когда написано make a list и delete custom необходимо чтобы выводились:...
C++ Здравствуйте! Не могу поместить class в один файл с программой. file.hpp #include "Cat.hpp" // здесь классы "2)" Cat::Cat(int initialAge) { itsAge = initialAge; } Cat::~Cat() { http://www.cyberforum.ru/cpp-beginners/thread41186.html
Массивы строк C++
Привет всем! Задан массив строк. Как узнать который символ встечаетса найбольшое количество раз в етом массиве?
C++ вывод на экран набор треугольников и квадратов, которые произвольно двигаются и меняют размер
Please, help me!!! Вот текст программы, которая выводит на экран набор треугольников и квадратов, которые произвольно двигаются и меняют размер только квадратов. Проблема в том, что необходимо...
C++ Округление дробного числа до целого в большую сторону. http://www.cyberforum.ru/cpp-beginners/thread41139.html
Доброго дня. Я новичок в программирование на Visual C++. Проблема такая программа должна считать кол-во месяцев, если числа целые то программа шла дальше, если дробное то (например 3.33333) ...
C++ Код из Delphi в C++ Нужно написать курсовую на C++. Сам я в программировании плохо шарю (не программист). Попросил у народу помощи, помогли. Но решение на Delphi: {$APPTYPE CONSOLE} type byteset=set of byte; ... подробнее

Показать сообщение отдельно
Evg
Эксперт CАвтор FAQ
17936 / 6164 / 409
Регистрация: 30.03.2009
Сообщений: 16,925
Записей в блоге: 27
05.07.2009, 11:42
> то есть важно только количество "токенов",а не строк и др

Да. Именно исходя из этих соображений должен писаться парсер. Ведь синтаксическому разборщику всё остальное неважно (ему не нужны комментарии, лишние проблеы и т.п.)

> Последующие вызовы функции (когда "токенов" уже нет) бесполезны

Вопрос в том, а как понимать, что мы имеем последний токен. EOF нужен только для этого. EOL нужен для обозначения конца оператора (statement). Чтобы конструкция "LET a=1 LET b=2" трактовалась как ошибочная (ибо считаем, что положено не более одного оператора в строке). Так же EOL служит разделителем между операторами, что упростит процесс синтаксического разбора. Но, оставь так, как сделал. Потому что более полезно учиться на своих ошибках, а не на том, как другие тебе их указывают

> обработку ошибок даже пока не знаю,как делать

Предлагаю такой вариант. Для начала сделай хоть как-то, чтобы оно работало в самом примитивном варианте. Лишь бы потом можно было просто найти все места, которые надо исправить. КОгда интерпретатор более-менее задышит и будет поддерживать несколько конструкций - тогда будет проще спроектировать конкретную реализацию обработки ошибок, потому как уже можно будет охватить широким взглядом всё то, что уже есть (а не виртуально то, что предположительно будет, как это сейчас)

> Как делаются такие вещи в нормальных программах?

Все интерпретаторы работают до первой ошибки. Компилятор (поскольку он не исполняет программу, а лишь преобразует её из языкового вида в машиннный код) работает до конца, и ищет по пути максимальное количество ошибок. Но, возможно сам наблюдал, что пропущенная запятая после описания внешней процедуры способна навести две страницы сообщений об ошибках. Как аккуратно восстанавливаться из ошибочных ситуаций - написаны целые научные труды. Я бы тебе пока не рекомендовал лезть в это дело, дабы не забивать голову вещами, которые тебе пока не нужны

> Ну вот,теперь помоему,самое время приступить к организации рекурсивного спуска

Можно конечно и так. Но есть ещё две компоненты, которые неплохо было бы реализовать. Это таблица переменных и пакет констант. Таблица переменных сейчас у тебя сделана просто ввиде шаблонного массива, хотя удобнее было бы её выделить в отдельную компоненту и накрыть интерфейсом. Константы у тебя представлены в виде double'а, а нужно их сделать в виде класса, в котором хранится вся информация (её тип и значение), а так же реализованы операции над константами (чтобы не заниматься этим при синтаксическом разборе)

Хотя действительно, понятнее всего было бы сделать так. Для начала сделать разбор синтаксиса, полгатаь, что константы у нас только double, сделать какой-то примтивный вариант, чтобы работал, а потом уже станет видно, как из всего этого отделить рабуоту с константами и работу с таблицей переменных

> Я так полагаю,мне придётся искать инфу по бейсику в сети?

А зачем. У тебя же не стоИт задача реализовать полноценный бэйсик. Ты пока только учишься, а потому можно сделать что-то очень простое бэйсикоподобное. Когда ты реализуешь до конца свою простую задачу, я тебя уверяю, ты сам сможешь её расширить до нормального интерпретатора. И синтаксис потом поменять как угодно

Щас погляжу твоё творение

Добавлено через 22 минуты 6 секунд
Для твоего исходника напечаталось так

Код
File: source.bsc Line: 1	CurToken: TOKEN_NULL    	NextToken: TOKEN_NULL    	TokenStr:  
File: source.bsc Line: 1	CurToken: TOKEN_KW_PRINT	NextToken: TOKEN_NULL    	TokenStr: PRINT 
File: source.bsc Line: 1	CurToken: TOKEN_KW_PRINT	NextToken: TOKEN_NULL    	TokenStr:  
File: source.bsc Line: 1	CurToken: TOKEN_IDENT    	NextToken: TOKEN_NULL    	TokenStr: aa 
File: source.bsc Line: 1	CurToken: TOKEN_IDENT    	NextToken: TOKEN_NULL    	TokenStr:  
File: source.bsc Line: 1	CurToken: TOKEN_KW_LET    	NextToken: TOKEN_NULL    	TokenStr: LET 
File: source.bsc Line: 1	CurToken: TOKEN_KW_LET    	NextToken: TOKEN_NULL    	TokenStr:  
File: source.bsc Line: 6	CurToken: TOKEN_IDENT    	NextToken: TOKEN_EOL    	TokenStr: a 
File: source.bsc Line: 7	CurToken: TOKEN_IDENT    	NextToken: TOKEN_EOL    	TokenStr:  
File: source.bsc Line: 7	CurToken: TOKEN_IDENT    	NextToken: TOKEN_EOL    	TokenStr: jj 
File: source.bsc Line: 8	CurToken: TOKEN_IDENT    	NextToken: TOKEN_EOL    	TokenStr:  
File: source.bsc Line: 9	CurToken: TOKEN_CONST_FLOAT	NextToken: TOKEN_EOL    	TokenStr: 7.9 
File: source.bsc Line: 10	CurToken: TOKEN_CONST_FLOAT	NextToken: TOKEN_EOL    	TokenStr:  
File: source.bsc Line: 11	CurToken: TOKEN_CONST_INT	NextToken: TOKEN_EOL    	TokenStr: 4 
m
Почему на каждый токен по две печати - я особенно разбираться не стал. Правда всё равно не понял корелляции между CurToken и NextToken. Т.е. мне казалось, что NextToken это то, что мы получим при следующем вызове GetToken. Но не суть. Главное, что мысль того, что должен делать GetToken, ты понял правильно

В parser.cpp есть фрагмент (строки 89-93)

C++
1
2
3
if ((PARSER_DEBUG == 1)&&(DEBUG == 1)) debugger_Print(PARSER_GET_TOKEN);
if (::parser_NextToken == TOKEN_EOL) ++::parser_CurLine;
return ::parser_CurToken;
Т.е. увеличение текщуего номера строки у тебя идёт после печати. Т.е. глазами в печати ты будешь видеть одно, а реально у тебя будет другое. Это доволно частая ошибка

Добавлено через 14 минут 37 секунд
Вот примерное формальное описание синтаксиса на текущий момент

Код
StatementList = Statement { EOL Statement } EOF
Statement = LetStatement | PrintStatement
LetStatement = IDENT "=" Expr
PrintStatement = "PRINT" Expr
Expr = Term { "+" | "-" Term }
Term = Factor { "*" | "/" Factor }
Factor = CONST | IDENT | "(" Expr ")"
Битовые операции пока включать не стал, из соображений минимизации. Да и хотелось бы, чтобы ты сам прикинул, как добавить операции с ещё одним уровнем приоритета. Для PRINT'а сделал чуть пошире, чем у тебя было - он печатает не просто переменную, а произвольное выражение (переменная тоже является выражением)

Так что предлагаю тебе сначала реализовать такой синтаксис, а потом начать выделять константы и таблицу переменных

Сейчас получается всё просто. Верхний уровень (по сути дела обработка StatementList) что-то типа того. Пишу в своём предположенииналичия EOL'ов и EOF'ов

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
while ((parser_GetToken()) != EOF)
{
  switch (parser_CurToken)
  {
    case KW_LET:
      stmt_LET();
      break;
    case KW_PRINT:
      stmt_PRINT();
      break;
    default:
      синтаксическая ошибка
  }
 
  if (parser_GetToken() != EOL)
    синтаксическая ошибка
}
 
если дошли до этой точки, значит программа проинтерпретирована до конца
Процедуры stmt_LET и stmt_PRINT внутри себя дальше дёргают parser_GetToken и работают согласно описанному синтаксису

Добавлено через 6 минут 57 секунд
На начальном этапе с EOL'ами можешь не заморачиваться, но тогда у тебя будут разрешены операции типа "LET a=1 LET b=2". В скриптовых языках принято операции разделять энтером или знаком ";"

Добавлено через 14 минут 52 секунды
Кстати, в 20-м посте я ещё в терминологии по ходу дела ошибся. Тут куча тонких моментов, но по ходу дела общепринятые термины такие. Парсер является лексическим анализатором (т.е. процесс формирования токенов из символов называется lexical analyser). А вот построение операторов - это синтаксический разбор (а правила называются syntax rules)
1
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru