Форум программистов, компьютерный форум 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
17415 / 5653 / 355
Регистрация: 30.03.2009
Сообщений: 15,478
Записей в блоге: 26
14.08.2009, 09:53     Пишем свой интерпретатор языка BASIC
Насколько я понял, вызов функции ты хочешь инерпретировать прямо из файла. Но при таком варианте задолбаешься с этим работать и вскоре интерпретатор превратится в болото. Полезно было бы это попробовать, дабы поиметь негативный опыт, но тут слишком много времени уйдёт в пустую, а последствия разгребать будет сложно

Тут надо работать через промежуточное представление. Хотя всё равно будет возникать вопрос о заведении переменной - в глобальной части или в локальной. Вообще, об этом я уже писал (пост 37, предпоследний абзац). Если перевести на текущее положение дел, то фактически тебе надо будет иметь две таблицы переменных (два вектора, или как у тебя называется). Локалы записываешь в локальную таблицу,глобалы в глобальную. При поиске переменной по имени сначала проверяешь в локальной таблице (если ты внутри процедуры), а потом в глобальной. При завершении работы процедуры локальная таблица удаляется

Если делать промежуточное представление, тот это место немного меняется. У тебя появляются три вещи. Таблицы переменных непосредственно, которые будут жить на протяжении времени жизни всей программы. А из промежуточного представления будут торчать обращения в одну из таблиц переменных. Второе - таблица символьных имён (о ней чуть ниже). И третье - таблица текущих значений: у тебя же процедура может рекурсивно саму себя вызывать, а у каждой активации процедуры своё значение переменных (об этом тоже ниже)

В итоге будем иметь что-то типа того в качестве промежуточного представления. Я пишу в своих упрощённых терминах, а дальше ты корячься со своими Си++'ными векторами и т.п.

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
// Описание переменной
struct Variable
{
  // Условно провязываю в список все переменные текущего контекста.
  // Т.е. глобальные переменные будут в одном списке, локальные переменные
  // процедуры - в другом (в каждой процедуре будет свой список)
  variable *next;
 
  // Имя переменной. Для исполнения промежуточного представление не нужно.
  // Нужно только для отладки и, вероятно, для выдачи ошибок
  char *name;
 
  // Дальше тип, может что-то ещё нужно
 
  // Текущее значение переменной (об этом ниже)
  Value *value;
}
 
// Описание процедуры
struct Procedure
{
  // Процедуры тоже условно провязываем в список
  Procedure *next;
 
  // Аналогично, для исполнения представления имя уже неважно, только
  // для отладки и выдачи ошибок
  char *name;
 
  // Информация о типе процедуры, ещё какая-то информация
 
  // Список параметров процедуры
  Variable *params;
 
  // Список локальных переменных процедуры
  Variable *locals;
 
  // Список операторов
  Statement *statement;
}
 
// Описание всей программы
struct Program
{
  // Список глобальных переменных
  Variable *globals;
 
  // Список процедур
  Procedure *procedures;
 
  // Список операторов
  Stetement *statement;
 
  // Может быть, что-то ещё
}
По поводу таблицы имён. На первом проходе парсера ты читаешь исходник и строишь промежуточное представление. При этом в процессе работы ты будешь строить конструкции Variable промежуточного представления. И будет возникать вопрос, как одно сдругим связывать по имени. Для этого нужно будет иметь таблицу имён, которая есть по сути набор пар { символьное имя, ссылка struct Variable* }. При этом пока ты работаешь в глобальной части, ты работаешь только с глобальной таблицей (т.е. таблица, в которой прописаны соотвествия для глобальных имён), а когда начинаешь парсить внутренности процедуры, то заводишь вторую дополнительную таблицу для имён локалов процедуры (включая параметры). Когда встречаешь имя - сначала проверяешь в таблице локалов, если там нет - в таблице глобалов. После того, как по имени нашёл соотвествующую struct Variable*, ссылку на эту переменную втыкаешь в представление. После того, как закончил парсить процедуру, таблицу локалов очищаешь. Понятно, что при таком раскладе процедура внутри процедуры не будет строиться. Да и большинство современных языков такое не позволяют, а потому думаю, что такое ограничение будет нормальным

Теперь таблица значений. В чём-то смысл похож на таблицу имён, только таблица о сути хранит набор всех значений (struct Value) для переменных текущего контекста. Одна таблица будет хранить набор значений для глобалов и будет жить всегда. В глобальной переменной будет торчать ссылка на struct Value, которая за всё время работы не поменяется (имею ввиду, что из переменной всегда будет торчать ссылка на одну и ту же запись Value). При входе в процедуру в момент ИНТЕРПРЕТАЦИИ (не парсенья) заводится новая таблица значений (каждое значение прописывается как Неинициализированное), а в представлении обходятся все локалы процедуры и поля value замыкаются на соответсвующую запись в твблице значений. При выходе из процедуры таблица значений удаляется (а ссылки на Value внутри локальных переменных на всякий случай устанваливается в NULL). Таким образом мы сможем рекурсивно вызывать процедуру? при каждой активации будет заводиться новая таблица значений (которая по большому счёту выполняет роль окна в стеке, как если бы это был код из-под компилятора). Тут есть тонкий момент: при рекурсивном возврате нам нужно уметь восстанавливать правильные связки "переменная-значение". Т.е. в момент интерпретации операции CALL нужно каким-то образом сохранить эти привязки переменной к значению, а после возврата - восстановить.Смысл этого понятен - в представлении (как и в тексте программы), локальная переменная присуствует в количестве одной штуки, но в момент исполнения их может быть несколько (из-за того, что может быть несколько активаций процедуры)

После всего написанного - ты ещё горишь желанием связываться с процедурами (и локальными объектами в них)? Потому как есть простые версии бейсика, где процедур как таковых нет. Формально они есть - за счёт оператора GOSUB (уход на подпрограмму), но при этом нет понятия локльной переменной, а потому работа ведётся через глобальные. Для использования это неудобно, т.к. не является полноценной процедурой, но очень и очень сильно упрощает интерпретатор. Именно поэтому я тебе изначально предлагал не связываться с процедурами. Не потому что это трудно по своей сути, а потому что для начинающего слишком большой объём работ, который тяжело выполнить аккуратно
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru