Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
1

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

20.06.2009, 20:03. Показов 242501. Ответов 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
25.10.2009, 20:06 201
Author24 — интернет-сервис помощи студентам
Ребята, а исходники сего дела где-то есть?

Добавлено через 38 секунд
Сорри, нашел.

Добавлено через 1 минуту
Тут: https://www.cyberforum.ru/misc... ts&t=41218
Но он там не один. Какой из них?
1
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
25.10.2009, 20:12  [ТС] 202
Ненене,это уже в прошлом давно,вот где лежат последние версии(/thread41218-page6.html#post252723) Пишем свой интерпретатор языка BASIC там всё написано,можно просто скачать архив в формате .tar http://basin.svn.sourceforge.n... z?view=tar И этот архив и будет самой последней версии,так как я не часто просто релизю архив на главной странице.
0
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
25.10.2009, 20:19 203
А где качать SDL и как её устанавливать? А то оно уже не компилится без этого

Добавлено через 1 минуту
Цитата Сообщение от #pragma Посмотреть сообщение
Ненене,это уже в прошлом давно,вот где лежат последние версии(/thread41218-page6.html#post252723) Пишем свой интерпретатор языка BASIC там всё написано,можно просто скачать архив в формате .tar http://basin.svn.sourceforge.n... z?view=tar И этот архив и будет самой последней версии,так как я не часто просто релизю архив на главной странице.
Для порядку надо видимо ревизию 41 качать, где ещё без графики
1
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
25.10.2009, 20:26  [ТС] 204
Отсюда качаются исходники http://www.libsdl.org/ бинарники для винды тоже есть,а если доступен репозиторий,то нужно просто найти пакет libsdl1.2-dev или что-то похожее.Ну и конечно если на винде,то нужно в опциях линкера указать путь к нужному .dll или что-то вроде(сам не пробовал)
Может,сделать компиляцию графики как опцию препроцессора,чтобы кому не надо графику,не парились и не качали пакеты?
0
Эксперт С++
3211 / 1459 / 74
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
25.10.2009, 20:34 205
#pragma, Может задам тупой вопрос, но для чего интерпретатору SDL ?
п.с.
нужно прочитать все страницы этой темы
1
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
25.10.2009, 20:42  [ТС] 206
Цитата Сообщение от niXman Посмотреть сообщение
#pragma, Может задам тупой вопрос, но для чего интерпретатору SDL ?
Чтобы как-то работать с графикой.И желательно кроссплатформенное решение.Перечитав про разные библиотеки,остановился на этой.Вспомни,ведь есть же в QBASIC и SCREEN,и LINE,и т.д. и тут вот и нужна графическая библиотека.

P.S Да,кстати,вот тут уже самое место подумать о GNU Autotools?Чтобы юзер получил все сообщения,чего не хватает..
0
Эксперт С++
3211 / 1459 / 74
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
25.10.2009, 20:43 207
#pragma, Приблизительно понял...
1
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
25.10.2009, 20:55 208
Цитата Сообщение от #pragma Посмотреть сообщение
P.S Да,кстати,вот тут уже самое место подумать о GNU Autotools?Чтобы юзер получил все сообщения,чего не хватает..
В этом месте об этом уже надо думать. Но я этим сам никогда не пользовался, так что конструктивных советов наврядли дам

Добавлено через 4 минуты
Цитата Сообщение от #pragma Посмотреть сообщение
Отсюда качаются исходники http://www.libsdl.org/ бинарники для винды тоже есть,а если доступен репозиторий,то нужно просто найти пакет libsdl1.2-dev или что-то похожее.Ну и конечно если на винде,то нужно в опциях линкера указать путь к нужному .dll или что-то вроде(сам не пробовал)
А как ты это ставил? Потому что rpm не поставился, ибо там миллион зависимостей надо, а из исходников у меня не скомилилось, т.к. требует какие-то X'овые инклюды, которые у меня не установлены

Цитата Сообщение от #pragma Посмотреть сообщение
Может,сделать компиляцию графики как опцию препроцессора,чтобы кому не надо графику,не парились и не качали пакеты?
Это уже можно через Autotools сделать
1
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
25.10.2009, 21:00  [ТС] 209
У меня система основана на Debian,я просто нашёл в репозитории пакет libsdl1.2-dev,и все сделал в файле
#include <SDL/SDL.h> ,ну и линкеру путь указал.Ещё раз убеждаюсь,что нужно переделать структуру с Autotools.

>Это уже можно через Autotools сделать
Я тоже не знаю Autotools,придётся как-то разбираться.

>Потому что rpm не поставился, ибо там миллион зависимостей надо, а из исходников у меня не скомилилось, т.к. требует какие-то X'овые инклюды, которые у меня не установлены

Так что теперь,получается,на RedHat и других системах это вообще не поставится?
0
Эксперт С++
3211 / 1459 / 74
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
25.10.2009, 21:06 210
Серьезно поработали, респект!
1
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
25.10.2009, 21:06 211
Цитата Сообщение от #pragma Посмотреть сообщение
Так что теперь,получается,на RedHat и других системах это вообще не поставится?
Да всё поставится, только уметь надо. У меня вот вечные проблемы с тем, чтобы что-нибудь настроить и установить. У меня убунту
1
Эксперт С++
3211 / 1459 / 74
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
25.10.2009, 21:07 212
Цитата Сообщение от Evg Посмотреть сообщение
У меня убунту
C
1
sudo apt-get install libsdl-dev
1
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
25.10.2009, 21:14 213
niXman, а саму libsdl?

В общем в итоге всё поставил, как водится, через ж..у. Скачал бинарники в виде rpm'ов, то скачал установил rpm, ручками оттуда выдрал файлы и ручками скопировал

Добавлено через 16 секунд
В итоге чёрный экран-таки вылез

Добавлено через 1 минуту
По поводу autotools. Специально для этого со многими библиотеками ставится специальная программа. В данном случае имеется sdl-config, которая выдаст конфигурацию, где установлена libsdl (где библиотеки, где инклюды) с тем, чтобы нужный набор опций воткнуть в Makefile
1
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
26.10.2009, 04:39  [ТС] 214
Добавил PRESET(ревизия 43),пока по умолчанию рисует на экране точку зелёным цветом,завтра займусь цветами уже.Но уже можно,даже не имея LINE,разрисовать экран линиями ))
Вот этот исходник уже работает
PureBasic
1
2
3
4
5
6
SCREEN 12
FOR i=5 TO 640 STEP 5
   FOR j=1 TO 480
     PRESET (i,j)
   NEXT j
NEXT i
Только в глазах рябит от линий
Правда у меня там получается небольшая свалка в .h файле,я попробовал как-то сделать так,чтобы graphics.h не подключала value_class.h,конечно,нужно просто передавать массив из int-ов просто,я же сделал шаблоны,сам не знаю зачем,но я переделаю потом,уж больно не терпелось сделать хоть что-то..

Кстати,насчёт отображения всего дерева - я уже забыл,но ведь давно уже сделана отладка,просто заглянуть в debugger.h и поменять на DEBUG 1 и ещё STATEMENT_DBG 1
и тогда увидим дерево в файле data_file.dat или если SILENT 0 то в консоли.
0
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
26.10.2009, 08:30 215
А что такое PRESET? Точку рисует вроде бы оператор PSET

> Кстати,насчёт отображения всего дерева - я уже забыл,но ведь давно уже сделана отладка,просто заглянуть в debugger.h и поменять на DEBUG 1 и ещё STATEMENT_DBG 1

Там вроде бы только имена statement'ов печатались

Добавлено через 3 минуты
> Вот этот исходник уже работает

Только как-то он очень неторопливо работает....
1
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
26.10.2009, 12:10 216
На работе возникают warning'и (gcc-4.1.2)

Код
parser.cpp: In function 'parser_TokenType parser_CheckNumInStr(std::string)':
parser.cpp:465: warning: converting to 'size3' from 'double'
Код
function.cpp: In function 'Value func_Calculate(const expr_Node_t*, val_Arr_t*)':
function.cpp:184: warning: passing '_float_t' for argument 1 to '_char_t* c_itoa(_int_t, _char_t*)'
function.cpp:186: warning: passing '_float_t' for argument 1 to '_char_t* c_itoa(_int_t, _char_t*)'
function.cpp: In function 'Value func_Calculate(const stmt_Node_t*, val_Arr_t*)':
function.cpp:351: warning: passing '_float_t' for argument 1 to '_char_t* c_itoa(_int_t, _char_t*)'
function.cpp:353: warning: passing '_float_t' for argument 1 to '_char_t* c_itoa(_int_t, _char_t*)'
1
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
26.10.2009, 17:43  [ТС] 217
>А что такое PRESET? Точку рисует вроде бы оператор PSET
Есть такой оператор-и разница между PRESET и PSET только в выборе цвета по умолчанию

>Там вроде бы только имена statement'ов печатались
Да,верно,но можно ещё включить EXPRESSION_DBG 1 тогда уже будет видно более подробно.

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

Насчёт варнингов-функцию c_itoa нужно ещё доделывать,она умеет работать только с int-ами..
Код
parser.cpp: In function 'parser_TokenType parser_CheckNumInStr(std::string)':
parser.cpp:465: warning: converting to 'size3' from 'double'
А это я гляну.Просто я заметил такую штуку,что под виндой вылазят варнинги,которых не было под Линуксом,а доступ к винде не всегда есть
0
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
26.10.2009, 20:02 218
Цитата Сообщение от #pragma Посмотреть сообщение
Ну да,наверное,ведь всё это написано начинающим,да и рисовать линию приходится по точкам,там же промежуточный процесс-каждый раз заново вычисляются параметры и вызывается 61440 раз функция graphics_PRESET,если бы,например,рисовать линию сразу,то вызывалась бы только одна функция-graphics_LINE и она уже вызывала рисование попиксельно.Я просто не знаю,как в SDL рисовать вырожденные полигоны с заданным углом наклона,попиксельно конечно будет медленнее.Так получается,что функция graphics_PRESET для этого исходника вызывается 61440 раз(если не ошибся)
Я исходники не смотрел, но пока видится, что для начала в этом надо разобраться. А в чём официальный смысл SDL, если даже линию без поллитры не нарисуешь?

Добавлено через 8 минут
Цитата Сообщение от #pragma Посмотреть сообщение
>Там вроде бы только имена statement'ов печатались
Да,верно,но можно ещё включить EXPRESSION_DBG 1 тогда уже будет видно более подробно.
Что-то больше ясности не стало. Хотел посмотреть, как же у тебя представление выглядит. Ну да фиг с ним
1
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
26.10.2009, 20:22  [ТС] 219
>Я исходники не смотрел, но пока видится, что для начала в этом надо разобраться. А в чём официальный смысл SDL, если даже линию без поллитры не нарисуешь?
Да и сам не знаю,уверен что там всё можно,там и с OpenGl работа есть,просто нужно постоянно разбираться с библиотекой.По незнанию предмета я мог и не то что нужно выбрать.На официальном сайте пишут
Код
Simple DirectMedia Layer is a cross-platform multimedia library designed to provide low level access to audio, keyboard, mouse, joystick, 3D hardware via OpenGL, and 2D video framebuffer
Низкоуровневый доступ.Значит ли это,что всё придётся писать самому?Поворот предметов в 2-х мерном пространстве и т.д.Если так,то математику я не помню,или придётся вспоминать,или искать что-то более готовое.
0
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
26.10.2009, 21:13 220
Если низкоуровневый - то скорее всего самому. Но всё равно как-то медленно. В общем ты хотел что-то новенького - ты его получил Может заодно и полезное руководство по SDL напишешь
1
26.10.2009, 21:13
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
26.10.2009, 21:13
Помогаю со студенческими работами здесь

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

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

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

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

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

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


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

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

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru