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

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

Войти
Регистрация
Восстановить пароль
Другие темы раздела
C++ Меню и список http://www.cyberforum.ru/cpp-beginners/thread41194.html
Здравствуйте форумчане. Помоги пожалуйста в следующем вопросе: У меня есть 2связный список, написано меню. Но в моменте когда написано make a list и delete custom необходимо чтобы выводились: Введите элемент и номер. вот сам код: #ifndef __list_h #define __list_h #include <iostream>
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!!! Вот текст программы, которая выводит на экран набор треугольников и квадратов, которые произвольно двигаются и меняют размер только квадратов. Проблема в том, что необходимо исправить код, чтоб фигуры не исчезали за экран (т.е. 640х460) и были компактным набором, т.е. двигались неменяя своего положения относительно друг друга и стукаясь об стенку экрана меняли свое...
C++ Округление дробного числа до целого в большую сторону. http://www.cyberforum.ru/cpp-beginners/thread41139.html
Доброго дня. Я новичок в программирование на Visual C++. Проблема такая программа должна считать кол-во месяцев, если числа целые то программа шла дальше, если дробное то (например 3.33333) программа не округляет это число (в большую сторону) до 4. Перелопатил тонны литературы, но пропустил или не нашёл этого, большая просьба написать функцию которая могла бы это делать, или способ какой.
C++ Код из Delphi в C++ Нужно написать курсовую на C++. Сам я в программировании плохо шарю (не программист). Попросил у народу помощи, помогли. Но решение на Delphi: {$APPTYPE CONSOLE} type byteset=set of byte; var d:array of longint; procedure c; var a,b,i:longint; подробнее

Показать сообщение отдельно
Evg
Эксперт CАвтор FAQ
17469 / 5707 / 362
Регистрация: 30.03.2009
Сообщений: 15,669
Записей в блоге: 26
10.07.2009, 14:28     Пишем свой интерпретатор языка BASIC
Цитата Сообщение от #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 секунды
Да, по поводу видимости переменных. Попробую условно объяснить на пальцах, как это в компиляторах делается (чтобы ты имел представление о том, как тебе гибко написать код). Заводится некое понятие "таблица переменных", которая содержит в себе список переменных (или массив - не суть). Для глобальных объектов заводится одна таблица. Обрабатываем процедуру, заводим вторую таблицу и локалы процедуры затаскаваем в неё. Обрабатываем лексический блок (фигурные скобки), заводим третью таблицу и локалы лексического блока пишем уже туда. таким образом тыблицы у тебя образуют что-то типа стека. Ну и далее когда встречается использование переменной, то ищес в таблице, которая на вершине стека, если не нашли - то дальше и т.п.

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