Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 1509, средняя оценка - 4.80
#pragma
Временно недоступен
955 / 226 / 14
Регистрация: 12.04.2009
Сообщений: 921
#1

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

20.06.2009, 20:03. Просмотров 197652. Ответов 464
Метки нет (Все метки)

*****************
Благодаря форуму и Evg в частности интерпретатор развивается, потихоньку превращаясь в простенький интерпретатор QBASIC.
Некоторые из самых старых версий сохранились в теме и ссылки на них будут добавлены в это сообщение,а также ссылки на другие темы,связанные с этой.

Репозиторий с проектом находится тут, там же есть возможность в браузере посмотреть историю ревизий (английский в логах весьма примитивен,комментарии и рекомендации можете писать в личку),а также скачать самый последний архив репозитория в формате .tar.gz
Если кто-то пользуется Subversion,скачать исходники можно так:
Код
svn co https://basin.svn.sourceforge.net/svnroot/basin basin
Эти темы возникли в результате моих вопросов по ходу написания:
http://www.cyberforum.ru/c-beginners/thread47863.html
http://www.cyberforum.ru/c-linux/thread46096.html
http://www.cyberforum.ru/linux-soft/thread43910.html
http://www.cyberforum.ru/cpp-linux/thread46502.html
http://www.cyberforum.ru/basic/thread47169.html
http://www.cyberforum.ru/cpp-beginners/thread50660.html
http://www.cyberforum.ru/cpp-linux/thread58874.html
http://www.cyberforum.ru/cpp-linux/thread95685.html
http://www.cyberforum.ru/cpp-beginners/thread106657.html
http://www.cyberforum.ru/c-linux/thread61324.html
Альтернативная версия интерпретатора от Evg на C
Это простая реализация разбора выражений, написанная Evg на C:
http://www.cyberforum.ru/cpp-beginners/thread34719.html
*****************
Первое сообщение:
*****************
Задание(Страуструп,из книги,по готовому коду): Введите программу калькулятора и заставьте её работать.Например,при вводе
C++
1
2
r = 2.5
area = pi*r*r
Программа калькулятора выведет:
C++
1
2
2.5
19.635
Получили такой код:
LexicalAnalyzer.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// LexicalAnalyzer.h
#ifndef LEXICALANALYZER_H_INCLUDED
#define LEXICALANALYZER_H_INCLUDED
 
#include <cctype>
#include <string>
#include <map>
#include <iostream>
 
enum Token_value {
    NAME,       NUMBER,      END,
    PLUS = '+', MINUS = '-', MUL = '*', DIV = '/',
    PRINT = ';',ASSIGN = '=',LP = '(',  RP = ')'
};
extern Token_value curr_tok;
extern std::map<std::string,double>table;
extern int no_of_errors;
 
Token_value get_token();
 
double expr(bool);
double term (bool);
double prim (bool);
int error(const std::string&);
 
#endif // LEXICALANALYZER_H_INCLUDED

LexicalAnalyzer.cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// LexicalAnalyzer.cpp
#include "LexicalAnalyzer.h"
 
 
std::map<std::string,double>table;
Token_value curr_tok=PRINT;
 
double expr (bool get)
{
    double left = term(get);
 
    for (;;)
        switch (curr_tok) {
            case PLUS:
                 left += term(true);
            break;
            case MINUS:
                 left-= term(true);
            break;
            default:
                 return left;
        }
}
 
double term (bool get)
{
    double left = prim (get);
 
    for (;;)
        switch (curr_tok) {
            case MUL:
                 left*=prim(true);
            break;
            case DIV:
                 if (double d = prim (true)) {
                     left /= prim (true);
                     break;
                 }
                 return error("Деление на ноль");
            default:
                 return left;
        }
}
 
double number_value;
std::string string_value;
 
double prim (bool get)
{
    if (get) get_token();
    switch (curr_tok){
        case NUMBER:{
            double& v = number_value;
            get_token();
            return v;
        }
        case NAME:{
            double& v = table[string_value];
            if (get_token()==ASSIGN) v = expr(true);
            return v;
        }
        case MINUS:
            return -prim(true);
        case LP:{
            double e = expr(true);
            if (curr_tok!=RP) return error("Ожидалась )");
            get_token();
            return e;
        }
        default:
            return error("Ожидалось первичное выражение");
    }
}
 
Token_value get_token()
{
    char ch = 0;
 
    do {
        if (!std::cin.get(ch)) return curr_tok = END;
    } while (ch!='\n'&&isspace(ch));
 
    switch (ch) {
        case 0:
             return curr_tok = END;
        case ';':case '\n':
             return curr_tok = PRINT;
        case '*':case'/':case '+':case '-':case '(':case ')':case '=':
             return Token_value(ch);
        case '0':case '1':case '2':case '3':case '4' :
        case '5':case '6':case '7':case '8':case '9':case '.':
             std::cin.putback(ch);
             std::cin>>number_value;
             return curr_tok=NUMBER;
        default:
             if (isalpha(ch)) {
                 string_value = ch;
                 while (std::cin.get(ch)&&isalnum(ch)) string_value.push_back(ch);
                 std::cin.putback(ch);
                 return curr_tok = NAME;
             }
             error ("Неправильная лексема");
             return curr_tok = PRINT;
    }
}
int no_of_errors=0;
int error (const std::string& s)
{
    no_of_errors++;
    std::cerr<<"Ошибка: "<<s<<'\n';
    return no_of_errors;
}

main.cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// main.cpp
#include "LexicalAnalyzer.h"
 
 
int main()
{
    table["pi"]=3.1415926535897932385;
    table["e"]=2.7182818284590452354;
    while (std::cin) {
        get_token();
        if (curr_tok==END) break;
        if (curr_tok==PRINT) continue;
        std::cout<<expr(false)<<'\n';
    }
    return no_of_errors;
}

Анализатор-то работает,но конечное значение не вычисляется.Более того,если вводим
C++
1
a = 3 + 6
,то получаем "a", равное первому элементу в выражении,то есть 3.В чём логическая ошибка данной программы?С этими каскадными вызовами она слегка запутана.Уверен,что кто-то уже делал это задание.

Добавлено через 2 часа 5 минут 30 секунд
Пришлось решать влоб с дебаггером.У Страуструпа опечатка (или намеренная ошибка,что более вероятно ) Вот в этом куске кода в функции get_token():
C++
1
2
        case '*':case'/':case '+':case '-':case '(':case ')':case '=':
             return Token_value(ch);
Нехватает смены значения curr_tok,что и приводит к ошибочной работе.
C++
1
2
        case '*':case'/':case '+':case '-':case '(':case ')':case '=':
             return curr_tok=Token_value(ch);
Теперь всё пашет,всем спасибо,вопрос можно считать закрытым,но есть вопрос поважнее: В функциях prim и term возвращается int при ошибке,но ведь они имеют тип double,как вообще это работает?Происходит неявное преобразование типа,так?Мне интересно,почему Страуструп прибег к такому способу,это распространённая практика?

Добавлено через 16 минут 19 секунд
И ещё опечатка была
C++
1
2
3
                 if (double d = prim (true)) {
                     left /= d;// было left /= prim (true)
                     break;
31
Лучшие ответы (1)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
20.06.2009, 20:03
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Пишем свой интерпретатор языка BASIC (C++):

Пишем свой чекер
Я хочу написать свой чекер, но не знаю с чего начать? Кто знает основные...

пишем свой троян с нуля
Всем привет)))соглашусь, что изобретаю велосипед, но хочется сделать все своими...

Пишем свой класс, спецификатор доступа protected
Всем привет! Из книги Р. Лафоре относительно спецификатора доступа protected:...

Интерпретатор небольшого языка программирования на С++
Здравствуйте, уважаемые форумчане! Я тут где-то год назад прочитал тему Evg...

Не удается откомпилировать интерпретатор М-языка
Задача: взять интерпретатор М-языка на сайте...

Написать интерпретатор программного языка -помощь
Здраствуйте! Ребят, кто хорошо разбирается в C++ помогите пожалуйста с...

464
niXman
Эксперт С++
3202 / 1451 / 73
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
23.03.2010, 19:56 #361
#pragma, слушай, а где репозитарий проекта?
если не сложно, запость в первый пост. чтоб не искать.
1
#pragma
Временно недоступен
955 / 226 / 14
Регистрация: 12.04.2009
Сообщений: 921
23.03.2010, 22:08  [ТС] #362
Цитата Сообщение от niXman Посмотреть сообщение
#pragma, слушай, а где репозитарий проекта?
если не сложно, запость в первый пост. чтоб не искать.
Вот тут https://sourceforge.net/projects/basin/develop ссылка для SVN,
отсюда http://basin.svn.sourceforge.net/ можно скачать последний архив с репозитория,
а тут https://sourceforge.net/projects/basin/ просто архивы,которые я вручную закачиваю.
Я бы с радостью отредактировал, но у меня нет прав на редактирование данной темы,к сожалению.
1
niXman
Эксперт С++
3202 / 1451 / 73
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
23.03.2010, 22:15 #363
Цитата Сообщение от #pragma Посмотреть сообщение
Я бы с радостью отредактировал, но у меня нет прав на редактирование данной темы
так напиши модератору, заранее скинь ему в ПМ текст который хочешь чтоб он вставил.

Добавлено через 25 секунд
за ссылки спасибо.
1
#pragma
Временно недоступен
955 / 226 / 14
Регистрация: 12.04.2009
Сообщений: 921
24.03.2010, 21:48  [ТС] #364
RazorQ: Попробовал сейчас скомпилить твою версию, не компилится.Видимо,ты ещё что-то забыл
Код
$ make
/usr/bin/uic-qt4 finddialog.ui -o .ui/ui_finddialog.h
Warning: name layoutWidget is already used
Warning: name layoutWidget is already used
g++ -c -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtGui -I/usr/include/qt4 -I. -I.moc -I.ui -o .obj/highlighter.o highlighter.cpp
g++ -c -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtGui -I/usr/include/qt4 -I. -I.moc -I.ui -o .obj/main.o main.cpp
g++ -c -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtGui -I/usr/include/qt4 -I. -I.moc -I.ui -o .obj/basinmainwindow.o basinmainwindow.cpp
basinmainwindow.cpp: In member function ‘void BasinMainWindow::createActions()’:
basinmainwindow.cpp:172: error: ‘Quit’ is not a member of ‘QKeySequence’
make: *** [.obj/basinmainwindow.o] Error 1
Ещё я хотел спросить: там у тебя все иконки в одну тему,а одна большая из моей версии,и она вообще не вписывается,может,поменяем? Где ты такие иконки нейтральные нашёл?
0
RazorQ
582 / 349 / 15
Регистрация: 06.02.2009
Сообщений: 1,386
25.03.2010, 08:02 #365
Цитата Сообщение от #pragma Посмотреть сообщение
Ещё я хотел спросить: там у тебя все иконки в одну тему,а одна большая из моей версии,и она вообще не вписывается,может,поменяем? Где ты такие иконки нейтральные нашёл?
Я их брал из примеров к Qt. Кнопки запуска там не было. Можно попробовать поискать в tango-icon-theme

Добавлено через 3 минуты
Цитата Сообщение от #pragma Посмотреть сообщение
Попробовал сейчас скомпилить твою версию, не компилится.Видимо,ты ещё что-то забыл
Скорее всего у тебя Windows, потому что только там не определен элемент QKeySequence::Quit. Я задал константу для всех платформ
1
pmo
0 / 0 / 0
Регистрация: 13.03.2010
Сообщений: 17
25.03.2010, 20:03 #366
Evg, скажите как вы считаете что нужно каждому программисту
0
Evg
Эксперт CАвтор FAQ
18938 / 6899 / 513
Регистрация: 30.03.2009
Сообщений: 19,438
Записей в блоге: 30
25.03.2010, 20:47 #367
Цитата Сообщение от pmo Посмотреть сообщение
Evg, скажите как вы считаете что нужно каждому программисту
Читаем здесь
2
#pragma
Временно недоступен
955 / 226 / 14
Регистрация: 12.04.2009
Сообщений: 921
25.03.2010, 20:49  [ТС] #368
Цитата Сообщение от RazorQ Посмотреть сообщение
Скорее всего у тебя Windows, потому что только там не определен элемент QKeySequence::Quit. Я задал константу для всех платформ
Думаешь, я вру,когда говорю,что на Убунте? могу скриншот прикрепить.. Не компилится и всё
0
RazorQ
26.03.2010, 08:32
  #369

Не по теме:

Цитата Сообщение от #pragma Посмотреть сообщение
Думаешь, я вру,когда говорю,что на Убунте? могу скриншот прикрепить.. Не компилится и всё
не, не все в порядке Ладно, разберемся

1
Evg
Эксперт CАвтор FAQ
18938 / 6899 / 513
Регистрация: 30.03.2009
Сообщений: 19,438
Записей в блоге: 30
21.04.2010, 23:15 #370
qqqqq
2
Вложения
Тип файла: rar basic.rar (51.7 Кб, 42 просмотров)
#pragma
Временно недоступен
955 / 226 / 14
Регистрация: 12.04.2009
Сообщений: 921
28.05.2010, 19:58  [ТС] #371
Сделал 79 ревизию,где была добавлена инструкция SUB,но уже понял,что поторопился,у меня там отсутствует механизм выхода из функции(точнее выход реализован с помощью метки,которая меняется в зависимости от места вызова,но я там конкретно напутал),так как я хотел обойтись без дополнительных списков.Теперь буду думать,как всё это поправить с минимальными правками.
0
HIMen
4251 / 1418 / 101
Регистрация: 12.04.2009
Сообщений: 2,346
08.06.2010, 01:05 #372
#pragma, Извини, лень читать километр темы в поисках вопроса. Как ты делал переменные во вложенных блоках?
Например
C
1
2
3
4
5
6
7
8
9
function main()
{
    int i = 0;
    while (i < 10)
    {
        int k = i;
        i = i + 1;
    }
}
Если без вложенных блоков или сделать инициализацию переменных только в одном месте, то все просто - заводим словарь с переменными.
Но как сделать со вложенным блоком? Там ведь эта переменная k каждую итерацию новая? А старая должна быть уничтожена?

Добавлено через 5 минут
Кстати как ты делал: чисто интерпретатор или с генерацией внутреннего представления?
1
Evg
Эксперт CАвтор FAQ
18938 / 6899 / 513
Регистрация: 30.03.2009
Сообщений: 19,438
Записей в блоге: 30
08.06.2010, 08:26 #373
Теорию можешь посмотреть пост 37 последний абзац

Добавлено через 2 минуты
С генерацией представления
1
HIMen
4251 / 1418 / 101
Регистрация: 12.04.2009
Сообщений: 2,346
08.06.2010, 19:52 #374
Цитата Сообщение от Evg Посмотреть сообщение
С генерацией представления
Каким именно?
1
Evg
Эксперт CАвтор FAQ
18938 / 6899 / 513
Регистрация: 30.03.2009
Сообщений: 19,438
Записей в блоге: 30
08.06.2010, 19:55 #375
Что каким?
1
HIMen
4251 / 1418 / 101
Регистрация: 12.04.2009
Сообщений: 2,346
08.06.2010, 20:00 #376
Какое именно внутренне представление программы?
Просто я до этого делал чисто интерпретатор и с циклами было совсем плохо - на каждой итерации все лексемы считывались заново.
Сейчас хочу переделать, думаю как лучше? Полностью записать программу в виде полиза, или дерева, или просто записать все лексемы последовательно в список, чтобы не читать по сто раз?
1
Evg
Эксперт CАвтор FAQ
18938 / 6899 / 513
Регистрация: 30.03.2009
Сообщений: 19,438
Записей в блоге: 30
08.06.2010, 20:12 #377
По части представления проще посмотреть исходники, чем объяснять на пальцах. В посте 139 есть некая печать промежуточного представления моего варианта в виде цепочки statement'ов. Хз будет ли понятно. У #pragma'ы то же что-то наподобие этого.

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

Добавлено через 1 минуту
Мой вариант в посте 232. Там в общем-то нужно смотреть файл statement.h (вроде). Там более менее откомментировано
1
#pragma
Временно недоступен
955 / 226 / 14
Регистрация: 12.04.2009
Сообщений: 921
08.06.2010, 22:37  [ТС] #378
>Но как сделать со вложенным блоком? Там ведь эта переменная k каждую итерацию новая? А старая должна быть уничтожена?
В нашем интерпретаторе все переменные глобальны,и только в последнее время,с появлением функций ,должны появится локальные списки переменных. Надеюсь скоро подумать над этим,так как то,что я сделал в 79 ревизии-полная лажа.

>Там ведь эта переменная k каждую итерацию новая? А старая должна быть уничтожена?

У списков переменных должна быть стековая структура,также,возможно,нужно делать стек выходов из функции(в C/С++ вспомогательную роль для этого,как я понял,выполняет слово return). Или возможно,нужно делать что-то,о чём говорил Evg (если я понял правильно) - подобие двух представлений,что-то навроде представления первого уровня со всеми точками входа и выхода из функций,пока даже слабо это вижу,как это должно быть технически.

А вообще в этой теме есть как раз мои биения с циклами,и закономерный вывод,на который меня наталкивал Evg-нужно делать промежуточное представление. Если у тебя блок программы пропускается по тем или иным причинам-то как проверить синтаксис в этом блоке(это была проблема в моём случае,с IF)?
0
HIMen
4251 / 1418 / 101
Регистрация: 12.04.2009
Сообщений: 2,346
08.06.2010, 23:46 #379
Цитата Сообщение от #pragma Посмотреть сообщение
А вообще в этой теме есть как раз мои биения с циклами,и закономерный вывод,на который меня наталкивал Evg-нужно делать промежуточное представление. Если у тебя блок программы пропускается по тем или иным причинам-то как проверить синтаксис в этом блоке(это была проблема в моём случае,с IF)?
Думаю, если делать чистый интерпретатор без внутреннего представления, то надо пользоваться его плюсами, т.е. допусканием ошибок в коде.
1
Evg
Эксперт CАвтор FAQ
18938 / 6899 / 513
Регистрация: 30.03.2009
Сообщений: 19,438
Записей в блоге: 30
09.06.2010, 00:09 #380
Цитата Сообщение от HIMen Посмотреть сообщение
Думаю, если делать чистый интерпретатор без внутреннего представления, то надо пользоваться его плюсами, т.е. допусканием ошибок в коде.
Например, bash, сделан по такой схеме. Но в bash'е нет меток и операторов goto. Из-за этого же нельзя вызывать функцию, если она описана ниже по тексту. Если ты хочешь делать нормальный интерпретатор с языка программирования, то без промежуточного представления заколебёшься делать
1
09.06.2010, 00:09
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
09.06.2010, 00:09
Привет! Вот еще темы с решениями:

Написать Интерпретатор Программного Языка(собственного)
Здраствуйте! Кто знает C++ помогите пожалуйста с реализацией данного...

Интерпретатор/компилятор ассемблер-подобного языка
Привет! Чую, что изобрёл велисипед, даже скорее велопарк, но всё же, поделюсь:...

Интерпретатор музыки стандарта BASIC PLAY на С++
У кого нибудь есть функция или класс, который сможет воспроизводить в С++...

Задание: разработать "Интерпретатор языка". С чего начать?
Здравствуйте, вручили темку на курсовик, ну точнее как вручили, не успел взять...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
380
Закрытая тема Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru