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

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

20.06.2009, 20:03. Показов 242557. Ответов 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
Evg
Эксперт CАвтор FAQ
21280 / 8302 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
21.12.2009, 16:00 281
Author24 — интернет-сервис помощи студентам
Цитата Сообщение от RazorQ Посмотреть сообщение
[*]Во-вторых, хотелось бы, чтобы интерпретатор не требовал обязательного присутствия SDL. Т.е. пользователь в праве решать, компилировать программу с поддержкой графики или без неё. Понимаю, задача сложная, но я думаю что результат будет более высокого качества.[/LIST]
В той или иной степени это уже обсуждалось. Этот пункт из тех, что можно отлодить "на потом", т.к. на остальное он не должен влиять. Так же я на примере показывал, как правильно писать код, чтобы на низкий уровень можно было подкладывать любую библиотеку, а не только SDL

Насколько я понимаю, SDL сейчас не конфликтует с IDE?
1
591 / 357 / 16
Регистрация: 06.02.2009
Сообщений: 1,386
21.12.2009, 16:04 282
Цитата Сообщение от Evg Посмотреть сообщение
Насколько я понимаю, SDL сейчас не конфликтует с IDE?
Нет. Все в порядке.
1
Evg
Эксперт CАвтор FAQ
21280 / 8302 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
21.12.2009, 16:06 283
Цитата Сообщение от RazorQ Посмотреть сообщение
Нет. Все в порядке.
В общем, полезно в репозиторий положить текстовый файл, куда сваливать идеи и полезные мысли, чтобы они не потерялись. Либо рисовать FIXME, но когда их много, что в отдельном файле проще
1
591 / 357 / 16
Регистрация: 06.02.2009
Сообщений: 1,386
21.12.2009, 21:57 284
Вот самый черновой вариант программы. Назвал так же, Basin-IDE, т.к. это вольется в один проект. Для компиляции нужна Qt не ниже 4.5. Вообще это не жесткое ограничение, просто в этой версии появилась возможность добавлять кнопку закрытия на вкладку. Для работы программы, нужно наличие интерпретатора в том же каталоге. Насчет имен файлов: желательно чтобы путь к файлу не содержал пробелов и кириллицы (вообще это только в теории, сам не пробовал).
Вложения
Тип файла: zip basin-ide.zip (105.3 Кб, 19 просмотров)
1
591 / 357 / 16
Регистрация: 06.02.2009
Сообщений: 1,386
21.12.2009, 22:36 285
Я, конечно, не прочитав документации решил написать самую элементарную программу на basic
PureBasic
1
2
3
PRINT "input your name: "
INPUT nam$
PRINT nam$
Интересно то, что basin аварийно завершился
Код
$ ./basin test.bas 
terminate called after throwing an instance of 'std::out_of_range'
  what():  basic_string::at
Аварийный останов
1
Evg
Эксперт CАвтор FAQ
21280 / 8302 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
21.12.2009, 22:47 286
RazorQ, неплохо, только отработку ошибок интерпретатора не сделал

Ну и чисто по мелочи замечания:
- логически "undo" и "redo" должны находиться рядом с "cut", "copy", "paste"
- у меня язык в системе выставлен английский, а все надписи по русски. Я так понимаю, что для многоязыковости надо отдельные локализации писать?

Добавлено через 2 минуты
Попробуй код без input'а, потому как подозреваю, что после реорганизации внутреннего представления input попросту слетел. Ну и синтаксис смотри по примеру или в каталоге tests, т.к. #pragma на строгость синтаксиса языка не вылизывал, потому как приоритетным было построение промежуточного представления.

#pragma, соглашайся забрать этот IDE Он мне понравился
2
591 / 357 / 16
Регистрация: 06.02.2009
Сообщений: 1,386
21.12.2009, 22:48 287
Цитата Сообщение от Evg Посмотреть сообщение
- логически "undo" и "redo" должны находиться рядом с "cut", "copy", "paste"
Это без вопросов

Цитата Сообщение от Evg Посмотреть сообщение
- у меня язык в системе выставлен английский, а все надписи по русски. Я так понимаю, что для многоязыковости надо отдельные локализации писать?
Да, надо писать файлы-переводчики. Это не сложно, но руки не доходят. У меня есть в планах сделать поддержку как минимум английского и русского. Но сейчас в коде жестко закодирован русский язык, поэтому английский ты увидишь только в сообщениях об ошибках.
1
Evg
Эксперт CАвтор FAQ
21280 / 8302 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
21.12.2009, 22:51 288
Цитата Сообщение от RazorQ Посмотреть сообщение
Да, надо писать файлы-переводчики. Это не сложно, но руки не доходят. У меня есть в планах сделать поддержку как минимум английского и русского. Но сейчас в коде жестко закодирован русский язык, поэтому английский ты увидишь только в сообщениях об ошибках.
Это не к спеху, так, спросил. Я-то в этом не разбираюсь

Но отработка ошибок и позиционирование курсора на нужной строке - это делать по любому
1
RazorQ
21.12.2009, 22:57
  #289

Не по теме:

Вчера было полгода проекту! Поздравляю вас Evg и #pragma!

1
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
21.12.2009, 23:33  [ТС] 290
Выглядит неплохо - простенько,аккуратно и со вкусом. Мне понравилось. Я так быстро не умею
Кое-какие ньюансы(мелочи): если можно,добавь нужные регекспы для отображения текста более красочно,но,в принципе,если неохота,я доделаю.
Комментарии наверное лучше чтобы становились серыми и с наклоном,как в С++,так лучше воспринимается основной текст,когда кореллирует с другим стилем.
Ещё такую мелочь заметил:когда открывается окно программы,по умолчанию открывается поле нового файла,что,в принципе,верно,но если пользоваетль решает сразу открыть готовый исходник,то его лучше загружать в это же поле,так как оно остаётся висеть вкладкой просто так.
Осталось только доделать эмулятор терминала,чтобы похож был на xterm и cmd (просто для подражания )
Ещё надо будет как-то сделать обработку ошибок интерфейсом,чтобы строку выделял цветом,или что-то навроде того,как я делал. В принципе,можно опираться на вывод интерпретатора,при ошибках он выведет строку,которая содержит слова "line: error:" и между ними должен быть номер строки. Там,правда,могут быть ньюансы с длинными путями,я не знаю,что будет,если длина строки окажется больше 255 символов.
А так вообще всё классно! Иконки лучше ставить из твоего варианта,они менее агрессивны,и более приятны глазу,только нужно найти подходящие для run и interpret.

Добавлено через 14 минут
Нашел,где была ошибка,отправлю правку позже:
кусок кода из syntax.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
  static expr_Node_t *syntax_IdentRValueInput ()
  {
     s_count pos = source.tellg();
     string name = ::parser_CurTokenStr;
     size3 i = FindNameOverVector (name,defined_vars);
     size3 j = FindNameOverVector (name,defined_arrays);
     if (i < 0 && j < 0)
     {
        if (parser_GetToken() == TOKEN_LEFT_PARENTH)
           error(UNDEFINED_ARRAY,name);
        source.seekg(pos);
        Types t;
        switch (name.at(name.size()-1)) // name вместо ::parser_CurTokenStr
        {
           case '%': t = INT;   break;
           case '&': t = LINT;  break;
           case '!': t = FLOAT; break;
           case '#': t = DOUBLE;break;
           case '$': t = STRING;break;
           default : t = INT;   break;
        }
        Value zero("0",t);
        Variable *var = memalloc(var,name); // name вместо ::parser_CurTokenStr
        defined_vars.push_back(var);
        defined_vars.back()->SetValue(zero);
        return expr_NewVariable(&name,t); // name вместо ::parser_CurTokenStr
     }
// Ну и надо ещё будет проглядеть,там могут быть ещё недочеты подобного рода


Добавлено через 12 минут
Ещё есть такая идея - сделать(опционально) автоотступ и показывать вертикалную линию после 80 знаков на строку для того,чтобы в результате код мог с удобством просматриваться в консоли,не требуя перемотки вправо .
1
Evg
Эксперт CАвтор FAQ
21280 / 8302 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
22.12.2009, 09:55 291
Пока не забыл. В IDE надо сделать поиск и замену. При чём человеческие (вверх, вниз, case sensitive, whole word, regular expression, спрашивать или нет). При поиске уметь выделять все найденные подстроки. Так же "перейти на номер строки" и возможность включения нумерации строк (как в варианте #pragm'ы)
3
591 / 357 / 16
Регистрация: 06.02.2009
Сообщений: 1,386
22.12.2009, 13:35 292
Цитата Сообщение от #pragma Посмотреть сообщение
Я так быстро не умею
Я тоже У меня был недоделанный блокнот, вот я и взял его за основу.
Цитата Сообщение от #pragma Посмотреть сообщение
Кое-какие ньюансы(мелочи): если можно,добавь нужные регекспы для отображения текста более красочно,но,в принципе,если неохота,я доделаю.
Сделаю. Сейчас в подсветки синтаксиса только одна проблема: если ключевое слово находится в комментариях, то оно выделится как ключевое, а этого не должно быть. Возможно, нужно задать правильный regexp.
Цитата Сообщение от #pragma Посмотреть сообщение
Ещё есть такая идея - сделать(опционально) автоотступ и показывать вертикалную линию после 80 знаков на строку для того,чтобы в результате код мог с удобством просматриваться в консоли,не требуя перемотки вправо .
Хорошо. Хотя честно, для меня это будет сложнее, т.к. с графикой в Qt не работал, но это дело времени
Цитата Сообщение от #pragma Посмотреть сообщение
Ещё такую мелочь заметил:когда открывается окно программы,по умолчанию открывается поле нового файла,что,в принципе,верно,но если пользоваетль решает сразу открыть готовый исходник,то его лучше загружать в это же поле,так как оно остаётся висеть вкладкой просто так.
Да, сам заметил. Подправлю.
2
Эксперт С++
3211 / 1459 / 74
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
22.12.2009, 16:38 293
Цитата Сообщение от Evg Посмотреть сообщение
Пока не забыл. В IDE надо сделать поиск и замену.
qscintilla ?
1
Evg
Эксперт CАвтор FAQ
21280 / 8302 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
22.12.2009, 20:02 294
Цитата Сообщение от RazorQ Посмотреть сообщение
Хотя честно, для меня это будет сложнее, т.к. с графикой в Qt не работал, но это дело времени
#pragma тоже интерпретаторов не писал

> qscintilla ?

Ой.. это я уже не знаю. Как говорится, пользователю нужен поиск и замена, а как он сдела технически - его это не колышет
2
Эксперт С++
3211 / 1459 / 74
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
22.12.2009, 20:13 295
Я к тому, что это ооочень навороченный виджет, и создан именно для редакторов. там есть все что только может понадобиться. он так же кроссплатформенный как и Qt.
т.е. писать велосипед с нуля, при условии что получится все равно хуже, смысла нет
1
Evg
Эксперт CАвтор FAQ
21280 / 8302 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
22.12.2009, 20:16 296
Цитата Сообщение от niXman Посмотреть сообщение
Я к тому, что это ооочень навороченный виджет, и создан именно для редакторов. там есть все что только может понадобиться. он так же кроссплатформенный как и Qt.
т.е. писать велосипед с нуля, при условии что получится все равно хуже, смысла нет
А смотря какую цель перед собой ставить: написать редактор или научиться программировать под Qt
2
Эксперт С++
3211 / 1459 / 74
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
22.12.2009, 20:18 297
поверь мне, помимо самого виджета редактора, будем ооочень много возможностей поучиться.
я просто предложил, вам решать.
1
Evg
Эксперт CАвтор FAQ
21280 / 8302 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
22.12.2009, 21:55 298
Цитата Сообщение от niXman Посмотреть сообщение
поверь мне, помимо самого виджета редактора, будем ооочень много возможностей поучиться.
я просто предложил, вам решать.
А я чо? Я в этом вообще ничего не понимаю
2
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
23.12.2009, 09:47  [ТС] 299
Evg, я тут пытаюсь осмыслить всё вышесказанное с точки зрения технической реализации. Я дёрнулся наводить порядок,но нужно сначала представить,хотя бы примерно,как будет выглядеть программа дальше,и что конкретно в ней изменится. Про память я понял,но это касается больше стадии интерпретации run-time.

Мне непонятен такой момент. Вот в исходнике встречается слово SUB,после чего создаётся процедура со своими свойствами.Внутри исходника процедуры встречается некая переменная с именем.Понятно,что переменная содержит указатель на свой стек(если создана),как ты пишешь,но как мы узнаем по имени,в каком стеке(странице) искать переменную?Создавать ли новую или это глобальная переменная? А может,это ошибка пользователя и переменная уже есть,и она другого типа,ну и так далее. До слов END SUB все новые переменные нужно писать в определённую страницу,но как об этом узнает следующая функция,создающая представление программы? Просто ты написал,что мой вариант не верен,и теперь я немного сбит с толку,так как не представляю,как это будет выглядеть технически.В run-time вроде понятно,там уже будут не имена переменных,а объекты,и в них уже ссылки на нужные страницы,а вот при создании представления немного неясно.
0
Evg
Эксперт CАвтор FAQ
21280 / 8302 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
23.12.2009, 11:00 300
Цитата Сообщение от #pragma Посмотреть сообщение
Evg, я тут пытаюсь осмыслить всё вышесказанное с точки зрения технической реализации. Я дёрнулся наводить порядок,но нужно сначала представить,хотя бы примерно,как будет выглядеть программа дальше,и что конкретно в ней изменится. Про память я понял,но это касается больше стадии интерпретации run-time.
В теории промежуточное представление остаётся как есть, только вместо одной цепочки statement'ов мы имеем их несколько (на каждую процедуру). И меняется метод хранения value в переменных

Цитата Сообщение от #pragma Посмотреть сообщение
Мне непонятен такой момент. Вот в исходнике встречается слово SUB,после чего создаётся процедура со своими свойствами.Внутри исходника процедуры встречается некая переменная с именем.Понятно,что переменная содержит указатель на свой стек(если создана),как ты пишешь,но как мы узнаем по имени,в каком стеке(странице) искать переменную?Создавать ли новую или это глобальная переменная? А может,это ошибка пользователя и переменная уже есть,и она другого типа,ну и так далее. До слов END SUB все новые переменные нужно писать в определённую страницу,но как об этом узнает следующая функция,создающая представление программы? Просто ты написал,что мой вариант не верен,и теперь я немного сбит с толку,так как не представляю,как это будет выглядеть технически.В run-time вроде понятно,там уже будут не имена переменных,а объекты,и в них уже ссылки на нужные страницы,а вот при создании представления немного неясно.
В момент построения представления ты должен строить дополнительные списки переменных, относящихся к текущему контексту. Список содержит соотвестве имени и указателя на экземпляр класса Variable. Т.е. пока ты находишься ВНЕ процедур ты работаешь со списком, в котором у тебя находятся все глобальные переменные. Когда появляется новая переменная, то ты проверяешь в списке, есть ли уже такая переменная или нет. Если есть, то используешь её, если нет, заводишь новую. Когда ты зашёл в SUB, то заводишь дополнительный список (который удаляешь по выходу из SUB). Заметь, я говорю НЕ о списке переменных, а о списке соответствия имени и переменной. И когда встретил переменную, то проверяешь сначала локальный список, а потом глобальный. Если бы мы делали SUB'ы внутри SUB'ов, то пришлось бы заводить стек из списков, но такого в бэйсике вроде нет. Ещё надо уточнить, как там с локалами. Т.е. если первый раз переменная встретилась внутри SUB'а, то она является локальной или нет? Или все локальные переменные должны явно объявляться, а если встретилась необъявленная переменная, то она глобальная? В общем надо выяснить, как правильно делается в Q-бэйсике.

В итоге ты получаешь представление, которое по большому счёту ничем не отличается от текущего. Но у каждой процедуры надо иметь список локальных переменных. Когда ты в момент исполнения заходишь в процедуру, то проходишь по этому списку и все значения переменных копируешь "куда-то в строноу", после чего инициализируешь все переменные нулями (если в бэйсике для локалов это тоже должно выполняться). Это "куда-то" должно иметь стековую структуру. Таким образом если ты зашёл в процедуру рекурсивно, то этим действием ты спас старые значения переменных. Когда выполняешь возврат из процедуры, то из этого "куда-то" переписываешь значения обратно в переменные. Этим ты по сути моделируешь run-time стэк

Точку сохранения-восстановления можно изменить. Т.е. спасать не во время входа в процедуру, а в тот момент, когда внутри процедуры делается CALL, а спасать, соотвественно, когда ты вернёшься из этого CALL'а. Как получается технически проще, так и нужно делать.
1
23.12.2009, 11:00
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
23.12.2009, 11:00
Помогаю со студенческими работами здесь

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

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

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

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

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

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


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

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