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

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

Войти
Регистрация
Восстановить пароль
Другие темы раздела
C++ Меню и список http://www.cyberforum.ru/cpp-beginners/thread41194.html
Здравствуйте форумчане. Помоги пожалуйста в следующем вопросе: У меня есть 2связный список, написано меню. Но в моменте когда написано make a list и delete custom необходимо чтобы выводились:...
C++ Здравствуйте! Не могу поместить class в один файл с программой. file.hpp #include "Cat.hpp" // здесь классы "2)" Cat::Cat(int initialAge) { itsAge = initialAge; } Cat::~Cat() { http://www.cyberforum.ru/cpp-beginners/thread41186.html
Массивы строк C++
Привет всем! Задан массив строк. Как узнать который символ встечаетса найбольшое количество раз в етом массиве?
C++ вывод на экран набор треугольников и квадратов, которые произвольно двигаются и меняют размер
Please, help me!!! Вот текст программы, которая выводит на экран набор треугольников и квадратов, которые произвольно двигаются и меняют размер только квадратов. Проблема в том, что необходимо...
C++ Округление дробного числа до целого в большую сторону. http://www.cyberforum.ru/cpp-beginners/thread41139.html
Доброго дня. Я новичок в программирование на Visual C++. Проблема такая программа должна считать кол-во месяцев, если числа целые то программа шла дальше, если дробное то (например 3.33333) ...
C++ Код из Delphi в C++ Нужно написать курсовую на C++. Сам я в программировании плохо шарю (не программист). Попросил у народу помощи, помогли. Но решение на Delphi: {$APPTYPE CONSOLE} type byteset=set of byte; ... подробнее

Показать сообщение отдельно
Evg
Эксперт CАвтор FAQ
17826 / 6036 / 388
Регистрация: 30.03.2009
Сообщений: 16,566
Записей в блоге: 26
10.07.2009, 14:28
Цитата Сообщение от #pragma Посмотреть сообщение
Я тут подумал,не лучше ли будет для переменных организовать свой класс,в который,в свою очередь,будет содержать в себе экземпляр класса констант?
Именно так. Только я это условно называю "таблицей переменных". Хотя ты пока пишешь простой интерпретатор (а не полноценный бэйсик). Я бы пока глубоко с этим не заморачивался и понятие "переменная" наверх не вытаскивал. Сделал бы модуль, а к нему интерфейсы: "записать значение в переменную с такми-то именем", "прочитать значение из переменной с таким-то именем", "проверить, существует ли переменная с таким-то именем". А реализацию поначалу сделал бы простую (типа того, что у тебя уже было), потом при необходимости можно было бы усложнить

Цитата Сообщение от #pragma Посмотреть сообщение
То есть,когда потребуется выполнить
PureBasic
1
LET a = 1
То просто будет создаваться экземпляр класса переменных,а в конструктор констант будет передаваться строка,и вся ответственность за типизацию,инициализацию и прочее уже ляжет на реализацию класса
Что-то слабо понял, о чём ты говоришь. А какую строку передавать в случае "LET a=b+c"? Просто в большой программе всё должно быть функционально отделено. Создание константы - отдельно. Создание переменной, инициализированной константой - отдельно. Создавать переменную через строку, и типа внутри автоматически дёрнется создание константы - это идеологически неправильно, потому как при таком подходе ты свою программу оченб быстро превратишь в помойку, в которой сложно будет разобраться. Не даром я тебе приводил сравнение с кубиками. Когда у тебя есть много маленьких кубиков, ты из них можешь собрать всё что угодно, когда та сразу же начинаешь склеивать кубики в другие конструкции, то из них уже тяжело что-то собрать. И есть хорошее программерское наблюдение: чем более универсальным делается интерфейс, тем меньше остаётся мест, где его удаётся применить".

Цитата Сообщение от #pragma Посмотреть сообщение
Единственная возможная проблема мне видится с видимостью переменных,что данный объект не будет видно из функций,вызываемых далее,а если создавать какой-то глобальный экземпляр,то встаёт вопрос сколько их нужно...Может тут namespace как-то спасёт?
Опять-таки, я бы сразу не стал так далеко заглядывать. Просто по той причине, что ты ещё толком не имеешь понятия о том, как будет выглядеть весь интерпретатор. Я уже несколько раз говорил идею, что для начала бы надо сделать, чтобы хоть как-то заработал вариант с выражениями и PRINT'ами. Т.е на текущий момент ты имеешь такую сложность, что тебе надо реализовывать сразу три вещи: константы, переменные, синтаксический анализатор. При этом ты пока не имеешь чёткого представления о том, что будет, а поэтому у тебя возникает масса затруднений на предмет того, а как же конкретно всё реализовывать.

Программистов условно можно разделить на два типа. Первые как правило сначала всё долго и тщательно всё планируют, а потом реализовывают. Вторые сначала в голове имеют общую картину, сразу же начинают реализовывать наброски, по ходу дела постоянно что-то корректируя, и в процессе работы начинает вырисовываться чёткая картина. Программисты первого типа как правило страдают тем, что их код очень трудно поддаётся дальнейшей переделке, а времени на раздумья уходит слишком много, потому как в процессе работы появляется куча ньюансов, которые теоретически сложно предугадать. Программисты второго типа изначально пишут код с учётом дальнейших переделок, а потому код оказывается гибким. Я отношу себя ко второму типу. Если тебе ближе первый тип, то мне надо будет немного по другому вести "обучение", ибо я исхожу из того, что при необходимости мы всегда можем подточить и подпилить, а затем аккуратно переделать.

То есть я делаю тобой предложенный enum частью синтаксического анализатора(ну не в класс констант же его включать). Мне не нравится,что пришлось так неэстетично записать включение "const_class.h" прямо посередине header-а,как-то не смотрится,да и запись class ConstVar; тоже не к месту.Это всё потому,что enum Types используется в классе ConstVar,который и подключается с помощью "const_class.h".Как бы так сделать поэлегантнее,чтобы в то же время сохранить некий порядок и структуру разделения? Модульное программирование для меня пока не совсем ясно,вот такие ньюансы немного сбиваю с толку.
Опять, я не понял чётко постановку вопроса, но есть реально две разные вещи: TOKEN_CONST_INT, TOKEN_CONST_FLOAT - это один enum, относящийся к лексическому анализатору (парсеру). Есть другой enum: CONST_VAL_INT, CONST_VAL_FLOAT, относящийся к представлению констант. Это две совершенно разные вещи (поэтому я их и выделяю префиксами TOKEN_ и CONST_ чтобы не путать). Или вопрос в чём-то в другом? То что ты сразу же задаёшься вопросами правильного распределения по муодям - это хорошо, но по опыту знаю, что всё равно идеально не получится Правильное ощущение выработается со временем, а здесь опять та же проблема - ты пока ещё не понимаешь, как в и тоге всё получится В общем поэтому я и говорю, что не надо бояться эксприментировать, ошибаться и переделывать, ибо пока на своём опыте не увидишь, как делается "неправильно", то никогда на уровне ощущений не поймёшь, как делать "правильно"

Добавлено через 13 минут 16 секунд
Немного поглядел исходники - у тебя с терминологией что-то в кучу намешано
  • Value (сокращённо val) - это непосредственное числовое значение: 5, 10, 12.345
  • Constant (сокращённо const) - это некое абстрактное понятие, которое содержит в себе значение (Value), но при этом содержит дополнительные атрибуты, описывающие тип значения. В моём понятии Value я не выделяю в отдельный класс, я выделяю лишь класс Constant, который содержит поле value
  • Variable (сокращённо var) - это переменная, имеющая имя, чтобы по этому имени можно было обращаться. Перменная в каждый момент времени содержит в себе какое-то значение, т.е. переменная внутри себя содержит поле класса Constant

Т.е. что-то типа того

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
// ------------------ это интерфейс модуля констант
 
// Тип значения (константы) - этот enum строго относится только к модулю констант
enum ConstantType
{
  CONST_TYPE_NULL = 0,  // ввожу это поле, чтобы "полезные" значения были ненулевыми
  CONST_TYPE_INT,
  CONST_TYPE_FLOAT,
};
 
// Типы для хранения целой и плавающей константы
typedef long long const_Int_t;
typedef double const_Float_t;;
 
// Класс описывает значение, как абстрактную единицу. Над экземплярами класса
// можено осуществлять арифметические операции. Конкретное значение
// и его тип являются полями класса
class Constant
{
  private:
    // Эти два поля описывают значение (value) константы
    ConstantType type;
    union
    {
      const_Int_t ival;
      const_Float_t fval;
    } value;
 
  public:
    // С конструкторами я, возможно, тебе нагнал, ибо опять-таки плохо Си++ знаю
 
    // Конструктор для создания целой константы
    Constant (const_Int_t ival);
 
    // Конструктор для создания плавающей константы
    Constant (const_Float_t fval);
 
    // Конструктор для создания константы по строковому представлению
    // Внутри синтаксического анализатора ты будешь пользоваться именно этим конструктором
    Constant (string str, ConstantType type);
 
...
}
 
// ------------------ это интерфейс модуля переменных
 
// Класс, описывающий именованный объект (т.е. переменную), который
// ХРАНИТ значение. Т.е. в переменную можно только прочитать или записать
// значение. Операций над переменными мы НЕ делаем, операции делаются
// ТОЛЬКО НАД ЗНАЧЕНИЯМИ (константами)
//
// Таким образом для конструкции a=b+1 надор атомарных действий такой
// 1. Прочитать значение переменной b (т.е. получить константу, хрянащуюся в b)
// 2. Создать константу, значение которой в строковой форме представлено как "1"
// 3. Выполнить операцию "+" над константами из пунктов 1 и 2
// 4. Записать константу, полученную в пнкте 3 в качестве текущего значения
//    переменной a
class Variable
{
  private:
    string name;
    Constant value; // текущее значение переменной
...
}
Возможно опять что-то сумбурно, ты справшивай если что непонятно. Но старайся вопрос задать так, чтобы его можно было понять

Добавлено через 18 минут 27 секунд
По поводу твоего кода

C++
1
ConstVar::ConstVar(const std::string parser_CurToken, Types VarType)
не создавай параметр с именем parser_CurToken, ибо это какая-то обязаловка получается. Модуль у тебя независимый, парсер тут не при чём, поэтому пусть имя параметра будет независимым (str или что-то типа того)

Операция сложения должна выглядеть так (по отношению именно к твоему коду):

C
1
2
3
4
5
6
7
8
9
10
11
12
if (is_float && prev.IsFloat())
  // f + f
  constant.fval += prev.GetFVal();
else if (is_float && prev.IsInt())
  // f + i
  constant.fval += prev.GetIVal();
else if (!is_float && prev.IsFloat())
  // i + f
  constant.ival += prev.GetFVal();
else
  // i + i
  constant.ival += prev.GetIVal();
Т.е. при сложении значений разных типов тип результата совпадает с типом первого аргумента

Кстати, когда есть ситуация, которая кажется тебе ошибочной (ты отметил её "Types messing Error?"), сразу влепи туда вызов своей процедуры error, а то потом забудешь и долго будешь отлаживать, программу

Добавлено через 7 минут 4 секунды
Класс, который я назвал Constant можно назвать Value, чтобы тебе меньше было путанницы. Тогда у тебя остаётся только два понятия: Value и Variable, а понятия Constant как такового не будет

Добавлено через 2 минуты 50 секунд
syntax_parserPrimary написан правильно (в итоге он получается предельно примитивным)

Добавлено через 2 часа 2 минуты 40 секунд
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ConstVar syntax_parserPrimary()
...
            case TOKEN_IDENT: {
                // По имени переменной узнаём Variable. При этом понимаем,
                // что переменные у нас живут всё время работы интерпретатора и
                // как с константами на локальных переменных тут не получится
                Variable *variable = .....
 
                // Возвращаем значение, записанное в переменной
                return variable->getValue();
            }
...
            default: ;
                // Выводим синтаксическую ошибку. gcc пишет что-то типа "syntax error near <TokenStr>"
...
Добавлено через 2 часа 3 минуты 22 секунды
Да, по поводу видимости переменных. Попробую условно объяснить на пальцах, как это в компиляторах делается (чтобы ты имел представление о том, как тебе гибко написать код). Заводится некое понятие "таблица переменных", которая содержит в себе список переменных (или массив - не суть). Для глобальных объектов заводится одна таблица. Обрабатываем процедуру, заводим вторую таблицу и локалы процедуры затаскаваем в неё. Обрабатываем лексический блок (фигурные скобки), заводим третью таблицу и локалы лексического блока пишем уже туда. таким образом тыблицы у тебя образуют что-то типа стека. Ну и далее когда встречается использование переменной, то ищес в таблице, которая на вершине стека, если не нашли - то дальше и т.п.

Тебе пока предлагаю ограничиться лишь одними глобмальными переменными. При этом ты заводишь понятие таблицы переменных, но таблица у тебя будет одна. А потом в случае чего добавишь
1
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru