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

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 1509, средняя оценка - 4.80
#pragma
Временно недоступен
 Аватар для #pragma
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
#1

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

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

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

Репозиторий с проектом находится тут, там же есть возможность в браузере посмотреть историю ревизий (английский в логах весьма примитивен,комментарии и рекомендации можете писать в личку),а также скачать самый последний архив репозитория в формате .tar.gz
Если кто-то пользуется Subversion,скачать исходники можно так:
Код
svn co https://basin.svn.sourceforge.net/svnroot/basin basin
Эти темы возникли в результате моих вопросов по ходу написания:
Технический приём для формирования согласованных данных
Makefile: как с использованием gcc строить автоматические зависимости от .h файлов?
Вопрос по svn (Subversion)
Создание системы тестирования ПО.
Вопрос про разные реализации бэйсиков
[C/C++] Можно ли выразить порядковый номер элемента массива через индексы?
[C++] Какие флаги указать линкеру для компиляции программы?
Как можно определить переменную в файле configure.in,чтобы её можно было использовать в Makefile?
Странный SIGSEGV, или что зависит от порядка написания интерфейса класса
[C++]Можно ли как-то указать в Makefile,чтобы часть файлов компилировал компилятор C?
Альтернативная версия интерпретатора от 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;
Лучшие ответы (1)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
20.06.2009, 20:03     Пишем свой интерпретатор языка BASIC
Посмотрите здесь:

C++ Написать интерпретатор программного языка -помощь
Написать Интерпретатор Программного Языка(собственного) C++
C++ пишем свой троян с нуля
C++ Интерпретатор небольшого языка программирования на С++
C++ Интерпретатор музыки стандарта BASIC PLAY на С++
Интерпретатор/компилятор ассемблер-подобного языка C++
Пишем свой чекер C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
17014 / 5419 / 335
Регистрация: 30.03.2009
Сообщений: 14,667
Записей в блоге: 26
20.12.2009, 14:11     Пишем свой интерпретатор языка BASIC #261
Цитата Сообщение от RazorQ Посмотреть сообщение
Evg, ты не мог бы дать мне список ключевых слов и саму программку. Я пока поэкспериментирую.
Пишем свой интерпретатор языка BASIC

Скачиваешь, пишешь make. Запускаешь "./basin source.bas"
Только нужно будет libSDL установить

Добавлено через 15 минут
Правда последняя версия из-под cvs у меня что-то не компилится

Код
In file included from editor.cpp:22:
editor.h:22:26: error: QPlainTextEdit: No such file or directory
Та версия, которая у меня осталась (хз как посмотреть номер ревизии), тоже не компилится. После переустановки линуха может Qt не той версии или ещё чего

Код
libgui/src/libgui.so: undefined reference to `QString::indexOf(QRegExp&, int) const'
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
RazorQ
20.12.2009, 14:14
  #262

Не по теме:

Выполнил make. Всё собралось как надо, потом выполнил make clean и basin тоже удалился. Т.е. остаются только исходники. Так задумано?

И ошибка в программе: после выполнения тестовой программы source.bas остается окно с квадратиками.

Evg
Эксперт CАвтор FAQ
 Аватар для Evg
17014 / 5419 / 335
Регистрация: 30.03.2009
Сообщений: 14,667
Записей в блоге: 26
20.12.2009, 14:20     Пишем свой интерпретатор языка BASIC #263
Цитата Сообщение от RazorQ Посмотреть сообщение
Выполнил make. Всё собралось как надо, потом выполнил make clean и basin тоже удалился. Т.е. остаются только исходники. Так задумано?
Ну в общем-то все программы, собирающиеся через make делают так. А что у тебя вызвало сомнение?

Цитата Сообщение от RazorQ Посмотреть сообщение
И ошибка в программе: после выполнения тестовой программы source.bas остается окно с квадратиками
Я так понимаю, что там пробел надо нажать (чтобы окно раньше времени не пропадало). Или ты имеешь в виду какие-то артефакты?
RazorQ
 Аватар для RazorQ
576 / 343 / 9
Регистрация: 06.02.2009
Сообщений: 1,386
20.12.2009, 14:23     Пишем свой интерпретатор языка BASIC #264
Цитата Сообщение от Evg Посмотреть сообщение
Ну в общем-то все программы, собирающиеся через make делают так. А что у тебя вызвало сомнение?
Я имею в виду, что исполняемый файл тоже удаляется. Если программа устанавливается в систему, то тогда все в порядке, но т.к. я её не устанавливаю, то рассчитываю на то, что исполняемый файл останется.

Цитата Сообщение от Evg Посмотреть сообщение
Я так понимаю, что там пробел надо нажать (чтобы окно раньше времени не пропадало). Или ты имеешь в виду какие-то артефакты?
Нажал пробел и окно пропало, но если нажимать на крестик, то оно остается.
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
17014 / 5419 / 335
Регистрация: 30.03.2009
Сообщений: 14,667
Записей в блоге: 26
20.12.2009, 14:33     Пишем свой интерпретатор языка BASIC #265
Цитата Сообщение от RazorQ Посмотреть сообщение
Я имею в виду, что исполняемый файл тоже удаляется. Если программа устанавливается в систему, то тогда все в порядке, но т.к. я её не устанавливаю, то рассчитываю на то, что исполняемый файл останется.
А... в "нормальном" случае так действительно не делается. Но #pragma пока всё "под себя" в первую очередь пишет. Хотя для порядка наверное стОит учесть

Цитата Сообщение от RazorQ Посмотреть сообщение
Нажал пробел и окно пропало, но если нажимать на крестик, то оно остается.
Насколько я понимаю, это какие-то особенности libSDL. В общем #pragma придёт - он тебе на все вопросы ответит

Добавлено через 3 минуты
RazorQ, может ты знаешь, чего надо в убунте нажать, чтобы qt установилось?
RazorQ
 Аватар для RazorQ
576 / 343 / 9
Регистрация: 06.02.2009
Сообщений: 1,386
20.12.2009, 14:35     Пишем свой интерпретатор языка BASIC #266
Цитата Сообщение от Evg Посмотреть сообщение
RazorQ, может ты знаешь, чего надо в убунте нажать, чтобы qt установилось?
У тебя есть на компьютере SDK или исходники? Или ты хочешь из репов загрузить?
#pragma
Временно недоступен
 Аватар для #pragma
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
20.12.2009, 20:24  [ТС]     Пишем свой интерпретатор языка BASIC #267
Ой,сколько интересного я пропустил
Ну во-первых,спасибо RazorQ за инициативу с помощью.В принципе я хотел сделать сам,но в-общем я уже сделал какой-то минимальный GUI,выглядит сейчас так:
http://itmages.ru/src/preview/15536/c86421.png
Окно с ошибками теперь показывается только когда они есть.
Т.е. заготовка есть (хотя по большому счёту там просто слепленные примеры с документации Qt4).Поковырявшись с Qt4,я примерно понял,как с ней работать,мне этого достаточно,так что можно даже полностью переделать GUI (только надо позаботиться,чтобы первоначальный вариант не пропал)
У меня есть несколько альтернатив решения этого вопроса.
1) Можно просто скачать исходники отсюда http://basin.svn.sourceforge.net/viewvc/basin/ там внизу есть ссылка на tar-ball.Это будет всегда последняя версия репозитория.
2) Скачать через svn тут https://sourceforge.net/projects/basin/develop
В этих случаях придётся как-то менятся исходниками потом.
3) По идее я бы мог добавить для RazorQ свою ветку в svn-репозитории,а также права на доступ,на странице проекта эту ветку видно не будет,но знающие смогут скачать,зная адрес.
4) Можно добавить git-репозиторий,а также cvs,и это будет как отдельная ветка.
5) Ну или ещё какой-нибудь вариант.
Насчёт пропадания окошка - там нужно нажать любую клавишу,и окно пропадёт.Просто я не знал,как правильно сделать это в SDL,и добавил в деструктор код по отлавливанию нажатия любой клавиши(по идее костыль):
выглядит так (graphics.cpp)
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  inline Graphics::~Graphics ()
  {
     bool flag = false;
     if (initialized)
     {// FIXME !
        SDL_Event event;
        cout << "\nPress any key to continue.\n";
        while (true)
        {
           SDL_PollEvent(&event);
           switch (event.type)
           {
              case SDL_KEYDOWN: SDL_Quit();flag = true;
              break;
              default:;
           }
           SDL_Delay(1); // this is because otherwise this code taking 100% CPU
           if (flag) break;
        }
     }
  }
А про удаление проги - это просто надо главный Makefile поменять,я это сделал для тестовой компиляции,чтобы сразу после проверки отправлять правки в хранилище,и чтобы на этот момент ничего лишнего в папках не было.Все файлы,генерирующиеся автоматом,тоже удаляются (moc_* и другие).

P.S. на счёт написанного Evg про функции,надо подумать,потом я ответ напишу.

>Evg, ты не мог бы дать мне список ключевых слов и саму программку. Я пока поэкспериментирую.
Кстати,у нас разные версии интерпретаторов,у Evg-на C,у меня - смесь С и С++ (основной костяк промежуточного представления я взял из версии Evg ).

Добавлено через 10 минут
Мой список синтаксиса есть в файле SYNTAX,который прилагается к проекту,вот на него ссылка - http://basin.svn.sourceforge.net/vie...70&view=markup
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
17014 / 5419 / 335
Регистрация: 30.03.2009
Сообщений: 14,667
Записей в блоге: 26
20.12.2009, 23:11     Пишем свой интерпретатор языка BASIC #268
Цитата Сообщение от RazorQ Посмотреть сообщение
У тебя есть на компьютере SDK или исходники? Или ты хочешь из репов загрузить?
Мне всё равно что. Я хочу скомпилять исходники интерпретатора. SDK установленная есть

> У меня есть несколько альтернатив решения этого вопроса.

Для начала можно просто отдать RazorQ'у исходники, а он из нич что-то склепает. Если тебе понравится - включишь в свой репозиторий и будешь думать, как доступ организовывать. Даже если пароль взломают - всего можно будет откатить на нормальную версию, ибо взломанным паролем можно только испортить исходники, но нельзя испоганить хранилище (по идее)
#pragma
Временно недоступен
 Аватар для #pragma
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
20.12.2009, 23:26  [ТС]     Пишем свой интерпретатор языка BASIC #269
Цитата Сообщение от Evg Посмотреть сообщение
Мне всё равно что. Я хочу скомпилять исходники интерпретатора. SDK установленная есть
По идее под Линухом должно всё компилиться,если устанавливал qt4-qmake,а также libqt4-dev,ну и может libqt4-gui.
Под виндой надо читать доку,как скомпилить Qt4 там что-то вроде запускаешь config,указываешь платформу(компилятор) ,и всё должно скомпилиться.

Самое правильное - запусти ./configure скрипт,он должен все зависимости выявить,и что нужно поставь.
niXman
Эксперт C++
 Аватар для niXman
3134 / 1446 / 49
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
20.12.2009, 23:37     Пишем свой интерпретатор языка BASIC #270
Цитата Сообщение от Evg Посмотреть сообщение
RazorQ, может ты знаешь, чего надо в убунте нажать, чтобы qt установилось?
так
sudo apt-get install libqt4-dev
Добавлено через 5 минут
в каталоге с сорцами должен быть .pro файл(это файл сценарий для qmake).
вводишь:
qmake
make
#pragma
Временно недоступен
 Аватар для #pragma
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
20.12.2009, 23:59  [ТС]     Пишем свой интерпретатор языка BASIC #271
Цитата Сообщение от niXman Посмотреть сообщение
в каталоге с сорцами должен быть .pro файл(это файл сценарий для qmake).
вводишь:
У меня там несколько иначе,.pro файл генерируется автоматом при запуске главного Makefile,у меня там написано:
Bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
TARGET    = basin
SUBTARGET = Basin-IDE
CP        = /bin/cp
LS        = /bin/ls
CURRDIR   = `pwd`
OPT       = *.h *.cpp */*.h */*.cpp
LSFLAGS   = -R $(OPT)
SUBDIR    = ./Basin-IDE
MAKE      = /usr/bin/make
QMAKE     = /usr/bin/qmake
QMKFLAGS  = -project
 
$(SUBDIR)/$(TARGET):        
     cd $(SUBDIR) && $(QMAKE) $(QMKFLAGS) $($(LS) $(LSFLAGS)) \
     && $(QMAKE) && $(MAKE) \
     && cd .. && $(CP) ./$(TARGET) $(SUBDIR)/$(TARGET)
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
17014 / 5419 / 335
Регистрация: 30.03.2009
Сообщений: 14,667
Записей в блоге: 26
21.12.2009, 00:07     Пишем свой интерпретатор языка BASIC #272
Цитата Сообщение от #pragma Посмотреть сообщение
По идее под Линухом должно всё компилиться,если устанавливал qt4-qmake,а также libqt4-dev,ну и может libqt4-gui.
Про первое пишет, что нет такого, вторые два установлены (по итогу qmake присутсвует)

Цитата Сообщение от #pragma Посмотреть сообщение
Самое правильное - запусти ./configure скрипт,он должен все зависимости выявить,и что нужно поставь.
Вообще говоря, configure обычно запускают ПЕРЕД сборкой.

Код
$ ./configure
checking for ./basin and define PATH_TO_INTERPRETER... configure: error: in `/home/mareev/basin':
configure: error: ./basin program not found.Please view configure.in file,string number 39-42 to fix the problem.
See `config.log' for more details.
Но если сначала запустить make, дождаться, пока он обломается на сборке IDE, а после этого опять запустить configure, то всё будет нормально. Как-то это немного с ног на голову

Код
$ export QTDIR=/opt/qtsdk-2009.04/qt 
$ ./configure
...
checking for main in -lQtCore... yes
checking for main in -lQtGui... yes
...
Однако дальше всё равно облом

[code]g++ -c -pipe -fpermissive -g -Wall -W -D_REENTRANT -DQT_SHARED -DQT_GUI_LIB -DQT_CORE_LIB -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. -I. -o editor.o editor.cpp
In file included from editor.cpp:22:
editor.h:22:26: error: QPlainTextEdit: No such file or directory[code]

Т.е. система конфигурации не подхватила правильные настройки установленного Qt из SDK (по крайней мере по части инклюдов) и полагается на то, что оно установлено по стандартным путям. Либо переменная QTDIR в нынешних версиях как-то по другому отрабатывается

Сейчас я имею по сути две Qt: одну из SDK, установленную в /opt, другую установленную через "apt-get" по стандартным путям. В /opt/qtsdk-2009.04/qt/include/QtGui этот файл у меня есть, а в /usr/include/qt4/QtGui - нету

Цитата Сообщение от niXman Посмотреть сообщение
так
Это сделал, но чего-то там не хватает

Добавлено через 2 минуты
До генерации qmake.pro у меня дело не дошло
#pragma
Временно недоступен
 Аватар для #pragma
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
21.12.2009, 00:11  [ТС]     Пишем свой интерпретатор языка BASIC #273
Ой,точно,я перепутал с configure скриптом ,это исправлю,правда как через configure проверить путь и сделать define,если интерпретатор ещё не собран? В-общем,там где-то по мелочи надо поменять,чтобы этот define делался после сборки первой цели.
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
17014 / 5419 / 335
Регистрация: 30.03.2009
Сообщений: 14,667
Записей в блоге: 26
21.12.2009, 00:17     Пишем свой интерпретатор языка BASIC #274
Хм... на ubuntu-9.10 всё нормально установилось, а проблема была на ubuntu-8.04.1

Добавлено через 3 минуты
И даже запустилось

В общем на мой взгляд IDE нужно вылизывать как минимум с пользовательской точки зрения (удобство пользования и т.п.). Если ты считаешь, что с Qt для самообразования более-менее разобрался, то имеет смысл отдать кому-то IDE на доработку и доведение до нормального пользовательского уровня.

Короче, думай

Добавлено через 2 минуты
Кстати, ещё бы встроенный отладчик сделать надо. Хотя его надо делать только после того, как окончательно утрясётся с низкоуровневым представлением (если решишь всё-таки поддерживать функции)
niXman
Эксперт C++
 Аватар для niXman
3134 / 1446 / 49
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
21.12.2009, 00:20     Пишем свой интерпретатор языка BASIC #275
Цитата Сообщение от Evg Посмотреть сообщение
имеет смысл отдать кому-то IDE на доработку и доведение до нормального пользовательского уровня.
могу помочь консультацией, советом, и на вопросы поотвечать
#pragma
Временно недоступен
 Аватар для #pragma
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
21.12.2009, 06:32  [ТС]     Пишем свой интерпретатор языка BASIC #276
Да,я не против,если RazorQ хочет сделать - пожалуйста,предоставлю любой из возможных вариантов.Можно и в главной ветке,какая разница,всё равно есть ревизии и т.п.,и кроме того,я уже не планировал добавлять что-то в сделанный GUI,а просто доделать его,там,сделать окошко настройки пути к интерпретатору,чтобы запоминалось в файле .conf,ну и ещё кое-какие мелочи.
А насчёт функций я так представляю - можно добавить переменную-указатель(и) на текущую функцию во всех Statements,при разборе её стек будет подаваться параметром ( у меня уже есть функция проверки отдельных блоков,можно до слова RETURN,или END SUB, или END FUNCTION),туда будут писаться все переменные,а при интерпретации в run-time эти указатели будут использоваться для поиска переменных,и придачи им начальных значений. Придётся,конечно,перелопатить пол-программы,но основной структуры это коснуться не должно. Evg,твоё предложение наверняка более рациональное,но я пока в него не очень въехал,надо покумекать ещё

>могу помочь консультацией, советом, и на вопросы поотвечать
Ну вот,ещё желающий помочь,спасибо,выслушаю советы =),хотя наверное доделывать будет RazorQ

Добавлено через 5 часов 57 минут
Сейчас подумал,наверное,попробую сделать так:
Создаём таблицу функций.Минимальный размер таблицы единица и там будет создаваться главная функция.У неё глобальный стек переменных,массивов. Метки наверное стоит сделать только глобальными,но можно и локальные метки.В структуре Statements будет указатель на текущую функцию,в которой находится инструкция.
Потом по мере создания представления,если встречается слово SUB или FUNCTION,создаётся функция а также её стеки,и указатель на неё передаётся дальше при провязывании в список или ещё как-то.
Возможно,ещё придется где-то хранить указатель на предыдущую функцию,или просто переходить к предыдущей (они в одной таблице) после того как заканчивается построение представления для функции.Имя функции в программе - просто безымянная метка перехода на нужное место в памяти.
При вызове функции считаются начальные значения параметров,присваиваются нужным переменным,и далее интерпретация идёт как обычно,только с той разницей,что переменные берутся из локального стека. Правда придётся организовать какую-то "кучу",или как там это называется,чтобы при рекурсивном вызове все предыдущие значения переменных вызывающей функции запоминались,а после вычислений брались значения с самого "верха". Можно сделать общий для всех функций контейнер только для тех переменных,которые передаются параметрами,и в нём и складировать все их значения при рекурсии... Или не общий,а для каждой функции по спец.контейнеру. Вот.
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
17014 / 5419 / 335
Регистрация: 30.03.2009
Сообщений: 14,667
Записей в блоге: 26
21.12.2009, 10:01     Пишем свой интерпретатор языка BASIC #277
По поводу функций. Твой вариант реализации - типичная затычка. Можешь его попробовать из тех же самый соображений - нужно испытать на себе неправильные варианты реализации.

То представление, которое мы имеем сейчас формально не совсем является представлением исходной программы. Statement'ы отражают операторы языка и на самом деле отражают языковые конструкции. Variable'ы точно так же отражают переменные языка. НО. Внутри Variable'ов у нас содержится Value, которое НЕ является конструкцией языка, а является run-time свойством программы. Таким образом сейчас в наше представление замешаны сразу две вещи: отображение исходной программы и отображение run-time состояния программы (которое в нашем случае является значением всех переменных).

Пока мы имели простой язык без функций, технически "два в одном" выглядело просто и без сложных зависимостей компонент одна от другой. Когда появляются функции, то run-time состояние (т.е. значения всех переменных) больше не могут однозначно коррелировать с представлением программы, поскольку для каждой функции отображение программы только одно, а run-time состояний может быть несколько (по количеству активаций процедуры в стеке процедурных вызовов). Поэтому представление нужно выбирать таким образом, чтобы на один экземпляр представления процедуры легко привинчивалось несколько состояний переменных. Т.е. в представлении надо аккуратно отделить отображение языковых конструкций (statement'ы, expression'ы, variable'ы) от run-time сосотояния (Value'ы). Другими словами надо ввести некое понятие "память". И из каждой Variable должна торчать ссылка на Value, а вот сама Value должна храниться в "памяти". При этом к моменту запуска (начало фазы интерпретации) программы, в "памяти" уже расположены значения глобальных переменных. В "памяти" так же создаётся некое подобие стека. При входе в процедуру в этом стеке мы выделяем окно под количество переменных в процедуре и у всех Variable'ов процедуры настраиваем Value на этот стек.

В конечном итоге представление вроде бы как остаётся одно, но в нём меняется механизм соответствия Variable и Value. Главное правильно отделить мух от котлет: представление программы отдельно, run-time состояние отдельно
#pragma
Временно недоступен
 Аватар для #pragma
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
21.12.2009, 11:00  [ТС]     Пишем свой интерпретатор языка BASIC #278
Хорошо.Пока смутно,но понимаю,о чём ты толкуешь. Значит надо начать наводить какой-то порядок,чтобы потом было проще.Тогда я вернусь обратно на 71-ю ревизию и начну делать отладочные печати. Попробую сделать как надо. Дальше уже виднее будет.
Был такой вопрос у меня ещё- может,стоит сделать define-ы для доступа к полям структур представления? коли уж классы не использую,так зачем там пихать кучу ненужных функций.Там есть очень много таких,которые просто возвращают значение,и больше ничего не делают.
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
17014 / 5419 / 335
Регистрация: 30.03.2009
Сообщений: 14,667
Записей в блоге: 26
21.12.2009, 13:04     Пишем свой интерпретатор языка BASIC #279
Цитата Сообщение от #pragma Посмотреть сообщение
Хорошо.Пока смутно,но понимаю,о чём ты толкуешь. Значит надо начать наводить какой-то порядок,чтобы потом было проще.Тогда я вернусь обратно на 71-ю ревизию и начну делать отладочные печати. Попробую сделать как надо. Дальше уже виднее будет.
Собственно, переход на новую концепцию как минимум требует времени на осмысливание всего этого добра. А порядок он никогда лишним не будет. Заодно в процессе наведения исходи из новой концепции

Цитата Сообщение от #pragma Посмотреть сообщение
Был такой вопрос у меня ещё- может,стоит сделать define-ы для доступа к полям структур представления? коли уж классы не использую,так зачем там пихать кучу ненужных функций.Там есть очень много таких,которые просто возвращают значение,и больше ничего не делают.
На мой взгляд лучше всё-таки делать классы и методы Set, Get. Всё то, что у меня сделано в виде процедур (типа stmt_NewStmtLET) - это всё так же должно быть методом класса. Попросту говоря, нужно перписать всё это на Си++. Я на Си пишу макросы только для Get'ов, а Set'ы не делаю, т.к. идеологически они все запрятаны внутри процедур типа той же самой stmt_NewStmtLET (т.е. снаружи не должны использоваться вообще). Такая несимметричность зачастую помогает при наведении порядка. Когда ты просто изменил поле структуры и изменил Set и Get, то всё автоматически срастается. А когда нет Set'ов, то надо все записи в поля править ручками - а это всегда означает, что лишний раз отсмотришь все записи в поля "глазками". По природе Set'ов всегда меньше, чем Get'ов и они в "нормальных" случаях сильно локализованы. Поэтому в данном случае я не боюсь потерять лишних 5 минут на замену, зато в очередной раз убедиться, что там всё в порядке (или не в порядке)
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
21.12.2009, 15:31     Пишем свой интерпретатор языка BASIC
Еще ссылки по теме:

Задание: разработать "Интерпретатор языка". С чего начать? C++
По русскому названию языка программирования определить английское название этого языка C++
C++ Перепишите пожалуйста код программы с языка Visual Basic в C++
Не удается откомпилировать интерпретатор М-языка C++
Пишем свой класс, спецификатор доступа protected C++

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

Или воспользуйтесь поиском по форуму:
RazorQ
 Аватар для RazorQ
576 / 343 / 9
Регистрация: 06.02.2009
Сообщений: 1,386
21.12.2009, 15:31     Пишем свой интерпретатор языка BASIC #280
Разработка IDE идет полным ходом. Я раньше писал редактор с возможностью работы с несколькими документами, вот решил его взять за основу для будущей IDE. Немного просмотрел исходники Basin-IDE, которую написал #pragma, и позволю несколько замечаний:
  • Во-первых, мне кажется не лучшим вариантом мешать STL и Qt. В частности, лучше использовать QVector вместо std::vector. Так же не нужно использовать char*. При работе с Qt вообще можно забыть о существовании этого типа (по крайней мере явно создавать переменные этого типа не надо). Гораздо удобней использовать QString. Это заметка для начинающего программиста на Qt.
  • Во-вторых, хотелось бы, чтобы интерпретатор не требовал обязательного присутствия SDL. Т.е. пользователь в праве решать, компилировать программу с поддержкой графики или без неё. Понимаю, задача сложная, но я думаю что результат будет более высокого качества.
Yandex
Объявления
21.12.2009, 15:31     Пишем свой интерпретатор языка BASIC
Закрытая тема Создать тему
Опции темы

Текущее время: 03:12. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru