Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.69/1283: Рейтинг темы: голосов - 1283, средняя оценка - 4.69
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
1

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

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

Author24 — интернет-сервис помощи студентам
Благодаря форуму и 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:
Представление выражения в двоичном дереве
*****************
Первое сообщение:
*****************
Задание(Страуструп,из книги,по готовому коду): Введите программу калькулятора и заставьте её работать.Например,при вводе
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)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
20.06.2009, 20:03
Ответы с готовыми решениями:

Пишем свой интерпретатор языка BASIC
Добрый день. Я смотрю, тут на форуме была тема коллективного написания интерпретатора BASIC на...

Пишем свой strlen
Всем привет, вырвал часть задание из общего задание по написанию своего string. На данном этапе...

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

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

464
Эксперт С++
3211 / 1459 / 74
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
23.03.2010, 19:56 361
Author24 — интернет-сервис помощи студентам
#pragma, слушай, а где репозитарий проекта?
если не сложно, запость в первый пост. чтоб не искать.
1
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
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
Эксперт С++
3211 / 1459 / 74
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
23.03.2010, 22:15 363
Цитата Сообщение от #pragma Посмотреть сообщение
Я бы с радостью отредактировал, но у меня нет прав на редактирование данной темы
так напиши модератору, заранее скинь ему в ПМ текст который хочешь чтоб он вставил.

Добавлено через 25 секунд
за ссылки спасибо.
1
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
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
591 / 357 / 16
Регистрация: 06.02.2009
Сообщений: 1,386
25.03.2010, 08:02 365
Цитата Сообщение от #pragma Посмотреть сообщение
Ещё я хотел спросить: там у тебя все иконки в одну тему,а одна большая из моей версии,и она вообще не вписывается,может,поменяем? Где ты такие иконки нейтральные нашёл?
Я их брал из примеров к Qt. Кнопки запуска там не было. Можно попробовать поискать в tango-icon-theme

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

Не по теме:

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

1
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
21.04.2010, 23:15 370
qqqqq
Вложения
Тип файла: rar basic.rar (51.7 Кб, 45 просмотров)
2
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
28.05.2010, 19:58  [ТС] 371
Сделал 79 ревизию,где была добавлена инструкция SUB,но уже понял,что поторопился,у меня там отсутствует механизм выхода из функции(точнее выход реализован с помощью метки,которая меняется в зависимости от места вызова,но я там конкретно напутал),так как я хотел обойтись без дополнительных списков.Теперь буду думать,как всё это поправить с минимальными правками.
0
4337 / 1506 / 101
Регистрация: 12.04.2009
Сообщений: 2,342
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
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
08.06.2010, 08:26 373
Теорию можешь посмотреть пост 37 последний абзац

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

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

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

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

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

А вообще в этой теме есть как раз мои биения с циклами,и закономерный вывод,на который меня наталкивал Evg-нужно делать промежуточное представление. Если у тебя блок программы пропускается по тем или иным причинам-то как проверить синтаксис в этом блоке(это была проблема в моём случае,с IF)?
0
4337 / 1506 / 101
Регистрация: 12.04.2009
Сообщений: 2,342
08.06.2010, 23:46 379
Цитата Сообщение от #pragma Посмотреть сообщение
А вообще в этой теме есть как раз мои биения с циклами,и закономерный вывод,на который меня наталкивал Evg-нужно делать промежуточное представление. Если у тебя блок программы пропускается по тем или иным причинам-то как проверить синтаксис в этом блоке(это была проблема в моём случае,с IF)?
Думаю, если делать чистый интерпретатор без внутреннего представления, то надо пользоваться его плюсами, т.е. допусканием ошибок в коде.
1
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
09.06.2010, 00:09 380
Цитата Сообщение от HIMen Посмотреть сообщение
Думаю, если делать чистый интерпретатор без внутреннего представления, то надо пользоваться его плюсами, т.е. допусканием ошибок в коде.
Например, bash, сделан по такой схеме. Но в bash'е нет меток и операторов goto. Из-за этого же нельзя вызывать функцию, если она описана ниже по тексту. Если ты хочешь делать нормальный интерпретатор с языка программирования, то без промежуточного представления заколебёшься делать
1
09.06.2010, 00:09
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
09.06.2010, 00:09
Помогаю со студенческими работами здесь

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

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

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
380
Закрытая тема Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru