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

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

Восстановить пароль Регистрация
Другие темы раздела
C++ Меню и список http://www.cyberforum.ru/cpp-beginners/thread41194.html
Здравствуйте форумчане. Помоги пожалуйста в следующем вопросе: У меня есть 2связный список, написано меню. Но в моменте когда написано make a list и delete custom необходимо чтобы выводились: Введите элемент и номер. вот сам код: #ifndef __list_h #define __list_h #include <iostream>
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!!! Вот текст программы, которая выводит на экран набор треугольников и квадратов, которые произвольно двигаются и меняют размер только квадратов. Проблема в том, что необходимо исправить код, чтоб фигуры не исчезали за экран (т.е. 640х460) и были компактным набором, т.е. двигались неменяя своего положения относительно друг друга и стукаясь об стенку экрана меняли свое...
C++ Округление дробного числа до целого в большую сторону. http://www.cyberforum.ru/cpp-beginners/thread41139.html
Доброго дня. Я новичок в программирование на Visual C++. Проблема такая программа должна считать кол-во месяцев, если числа целые то программа шла дальше, если дробное то (например 3.33333) программа не округляет это число (в большую сторону) до 4. Перелопатил тонны литературы, но пропустил или не нашёл этого, большая просьба написать функцию которая могла бы это делать, или способ какой.
C++ Код из Delphi в C++ Нужно написать курсовую на C++. Сам я в программировании плохо шарю (не программист). Попросил у народу помощи, помогли. Но решение на Delphi: {$APPTYPE CONSOLE} type byteset=set of byte; var d:array of longint; procedure c; var a,b,i:longint; подробнее

Показать сообщение отдельно
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16824 / 5245 / 319
Регистрация: 30.03.2009
Сообщений: 14,121
Записей в блоге: 26
05.07.2009, 11:42     Пишем свой интерпретатор языка BASIC
> то есть важно только количество "токенов",а не строк и др

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

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

Вопрос в том, а как понимать, что мы имеем последний токен. 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)
 
Текущее время: 14:38. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru