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

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