Ремесло программиста

Объявление

форум на движке phpBB доступен для тестирования
www.strategia.space
www.strategia.space/forum/
по предложению Лиса - канал на Matrix - #remdev:matrix.org

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Ремесло программиста » Валентина » Аспекты внутреннего устройства


Аспекты внутреннего устройства

Сообщений 1 страница 19 из 19

1

В этой теме я хотел бы  выкладывать некоторые задумки и реальные механизмы, которые используются в языке и в его реализации.
Итак, небольшая схемка, общий принцип работы:
http://s6.uploads.ru/t/905Mp.jpg
Исходный текст программы будет переводится во внутреннее представление виртуальной машины. Имеется возможность оттуда сохранить состояние машины (чисто теоретически вообще любое, не только во время старта) и загрузить данные в форме P-кода. По сути это такая же программа, но язык которой сильно бедней в плане синтаксиса (соответственно требуется меньше проверок во время загрузки/старта).
Ну и соответственно виртуальная машина проводит вычисления в рамках модели систем.

Вопрос по организации передачи параметров в функцию.
Итак, возьмем абстрактный вызов (поскольку синтаксис стандарта еще не определен, весь пример условный):

х=какая_то_функция(параметр1[тип<>''], параметр2[параметр2>0], параметр3)[тип='список']

Что тут происходит? Переменной (которая тоже система между прочим) передается результат работы функции какая_то_функция. На функцию наложены ограничения предусловий (для входящих параметров) и постусловие (для результата) с помощью спецификаторов. Функция получает 3 параметра:
- параметр1 (у которого при передачи тип должен отличаться от пустой строки);
- параметр2 (который должен восприниматься как простая система с текстовым значением, воспринимаем как число больше нуля);
- параметр3 (на который не наложено никаких ограничений и он может быть любой системой - простой, функцией, определенной пользователем и т.д.).
При этом параметры копируются и соответственно на сами системы, которые переданы в функцию, она повлиять не в состоянии. Все что ей позволено это результат и побочные эффекты. При этом функция получит локальные копии параметров, над которыми может делать все что пожелает.
Затем синтаксис вызова определяет, что функция должна вернуть значение, имеющее тип список.
Теперь возникает вопрос по реализации параметров внутри функции. Пока идея следующая, создать подсистему, которая по умолчанию будет существовать у функций, как служебная подсистема, хранящая локальные копии параметров.
Ну вот как-то так:
http://s6.uploads.ru/t/ocaDG.png
Согласно данной модели, здесь пока что условно, после проверки контракта (всех условий для входящих параметров), в функции создается подсистема #, в которую будут копироваться входящие параметры (под именами, определенными в сигнатуре функции при ее описании в коде программы). А в качестве результата будет генерироваться подсистема с таким же именем, что и имя функции. После выхода из функции, будет произведена проверка постусловия (что тип результата должен быть "список") и затем скопирован в переменную х. Как вариант результат функции тоже можно размещать #, однако существует вероятность вложенного вызова самой себя в качестве одного из параметров, поэтому я думал о размещения входных параметров и результата в разных подсистемах.
Как идея? Предлагайте варианты, пишите замечания.
Вообще, чисто теоретически, после отладки функции смысл в передачи кучи параметров отпадает сам собой, так как у программиста существует возможность запихнуть все системы-параметры в одну и передавать ее функцию (сейчас вопрос производительности не стоит, понятно, что практически это медленно, но еще неизвестно что медленней - передавать параметры по одному (и проверять корректность при входе в функцию каждого параметра) или передать все сразу в виде большой системы). Это свойство возникает из-за такого явления как алгебраические типы данных (АТД, не путать с абстрактными типами данных!!!!), суммирование типов в Валентине есть "из коробки" - их представляет теория систем и базовые операции для работы с подсистемами. Вопрос по произведению типов пока в стадии продумывания...
И еще размышления - сейчас продумывая возврат результатов функций я прихожу к мысли, что вселенная это больше чем система с именем '1'... Вполне вероятно, что данная система будет иметь несколько подсистем (например, список внешних модулей), вероятно вселенная внутри будет иметь еще подсистемы, которые будут недоступны напрямую программисту, но будут необходимы для поддержания функциональности модели.

2

Что-то типа спецификации метаязыка, описывающего синтаксис конструкций языка Валентина:

Набор конструкций представляет собой файл из набора секций
   Каждая следующая секция переключает на ввод параметров для нового значения

   1. Секция General - описание настроек набора
   В секции General описываются следующие параметры набора конструкций:
     Name - имя набора
     Remark - описание набора
     OpenQoute - открывающая кавычка (используется для описания текстовых констант)
     CloseQuote - закрывающая кавычка (используется для описания текстовых констант)
     OpenBracket - открывающая скобка
     CloseBracket - закрывающая скобка
     Divider - разделитель при перечислении параметров
     Token - лексема, которая в сплошном тексте должна рассматриваться как отдельный элемент
             Например: х-->х+1, лексему --> следует рассматривать отдельно. Тогда имеем: х, -->, х+1
                       Это не влияет на содержимое текстовых констант
             В Token через пробел возможно использование нескольких токенов в одной команде
   

  2. В секции Constr описывается одна отдельная конструкция языка
     Remark - Описание конструкции
     Id - Семнатический идентификатор конструкции
     Word1, word2...word8 - Слова-шаблоны для распознавания
 

  3. В секции Funct описывается одна отдельная функция языка
     Name - Имя функции
     Id - идентификатор функции
     Remark - Описание функции
     Params - Количество параметров функции
   Первоначально считается, что открыта секция General
   Секции заполненные не полностью будут проигнорированы

   ПРИМЕЧАНИЕ:
   1. Конструкции с идентификатором 0 являются незначащими лексемами
   и будут откидываться из начала строки

   2. Конструкции с идентификатором 1 являются однострочными комментариями
   и все что после них будет откидываться
   Вид данного комментария:  1 лексемы_комментария 2
                             1 - текст программы
                             2 - комментарий

   Если в слове конструкции указан номер параметра, то он считается единственно возможным вариантом


Как и в первой Валентине, такое описание можно преобразовать к форме близкой к БНФ  автоматом. Плюс сменяемый синтаксис предполагает возможность включения исходников на разных диалектах (это возможно, но реализацию надо продумывать).

3

Пример описания синтаксиса:

Имя теста
Name=Тест
Remark=Просто пробный файл для демонстрации

Описание оператора цикла
Всего слов можно использовать 8 - Word1-Word8
Constr
Remark=Оператор цикла
Id=5
Word1=Повторять Повторить Повтор Повторяем
Word2=Пока
Word3=1

Constr
Remark=Оператор цикла
Id=5
Word1=Цикл
Word2=с
Word3=условием
Word4=:
Word5=1

Constr
Remark=Незначащая лексема
Id=0
Word1=Затем Далее Следовательно
Word2=,

Constr
Remark=Комментарий
Id=1
Word1=1
Word2=// #
Word3=2

Constr
Remark=Комментарий
Id=1
Word1=// #
Word2=1

Constr
Remark=Выражение
Id=3
Word1=1
Word2=-->
Word3=2

FUNCT
Name=Синус
Remark=Вычисление синуса, один параметр в радианах
Params=1

Здесь описываются лексемы которые должны быть выделены в тексте
general
token=--> : + * / -


Все что не распознано будет просто пропущено, поэтому в тексте такого описания можно свободно писать комментарии.
Система поддерживает идею множественности конструкций (из первой Валентины), например, здесь описаны циклы:
Повторять пока
Повторить пока
Повтор пока
Повторяем пока

Также из первой Валентины унаследована идея незначащих лексем. В примере можно писать и так:
Затем повторять пока
Далее повторить пока
и т.д.

Так можно решать проблемы склонений (в разумных пределах разумеется), хотя и первоначально идеи были не совсем про склонения. Из опыта прошлой Валентины 8 слов для описания синтаксиса хватает за глаза. Можно писать очень сложные витиеватые операторы.
Как уже писалось ранее в других темах - Валентина не имеет собственного закрепленного синтаксиса (предполагается поставка двух вариантов по умолчанию - простой для быстрой записи текстов программ и подробный, на подобие как у Кобола, для чтения программ), конструкции привязываются к семантики языка с помощью Id. ID пока не проработаны, в дальнейшем идентификаторы сменить будет нельзя (для целей совместимости).

4

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

i3
1>
2>
3>
4>

Здесь символ i признак начала новой инструкции
3 - идентификатор инструкции (команда ID в метаязыке, указывающая на семантику)
1>...4> список входящих параметров конструкции (конструкция языка может содержать 8 слов и 4 параметра).
Как видно из схемы первого поста, если добиться правильного описания инструкций, имеется теоретическая возможность сохранения состояния виртуальной машины в любой момент времени (например, приостановили программу, перенесли программу на другую систему, запустили).

В целом это немного смахивает на платформу .Net

Сама программа условно делится на две части:
1. Инициализация начального состояния виртуальной машины (в исходном тексте программы это раздел описания системы)
2. Подпрограммы для исполнения виртуальной машины (в исходном тексте программы это раздел с описанием функций)

5

utkin
Помимо арифметических и логических команд есть ещё команды управления, а также есть ещё данные описания функций и описания структур данных.

6

Ну так вводите эти данные в чем проблема? В примере есть цикл, это что, не оператор управления?

7

utkin
Помимо П-кода есть ещё Д-код. Он у вас не описан никак. Хотелось бы увидеть, такое описание. Либо обоснование почему его не следует его включать.

utkin написал(а):

Ну так вводите эти данные в чем проблема?

Как бы язык ваш вам и карты в руки. Я пока у себя ещё не делал. Ну не дошел я до объектов с их таблица виртуальных методов. Более того на свете ещё существуют такие таблицы где помимо самих функций ещё и вспомогательные данные для них хранятся. Да и взять простой record оказывается там общепринято переставлять элементы так что-бы оптимизировать расход памяти -  но в тоде время и с дырками!
Как только вы захотите сделать обмен с другими или вызывать WinAPI у вас могут появиться трудности с переносом.

utkin написал(а):

В примере есть цикл, это что, не оператор управления?

Допустим что оператор. Я про другое.  Это достаточно своеобразная кухная операторов. Может их стоит выделить из п-кода в отдельную группу?

Кухня

Тут тебе и метки, и особый сорт меток как имена функций
К ним по разному передаётся управление jmp есть call.
И в правильных ассемблера вместо call используют макрос invoke
В паскале есть continue, break, exit. exit - выход из функции
Есть ещё исключения, try-except-finaly и их

В паскаль-ABC и С# есть оператор yeold. Его одним П-кодом не опишите, так как там ещё нужно хранить состояние, а это уже Д-код.

или взять стековые макросы фасема, форта. Или лябды как в Си++.

А ведь ещё есть колбеки, они к примеру в WinAPI требуют атрибут STDCALL.
Если безымянные функции, анонимные и виртуальные функции,

Или вспомнить COM или OLE, им ведь пришлось создать специальное соглашение о вызове и ввести понятия клиент и сервер. А не просто функция и вызывающий.
Так как автоматика может породить объект и подставить его под интерфейс. А может использовать существующий объект, а может и вовсе пробросить вызов через сеть.

И так далее и тому подобное.

8

Не знаю никакого Д-кода :).

Как бы язык ваш вам и карты в руки. Я пока у себя ещё не делал.

Парсеру вообще пофиг он просто распознает конструкцию и возвращает ИД с параметрами. А как распознают ИД в виртуальной машине уже другой вопрос. Поэтому сейчас можно создавать любую конструкцию - хоть оператор, хоть заголовок функции, хоть объявление переменных.

Более того на свете ещё существуют такие таблицы где помимо самих функций ещё и вспомогательные данные для них хранятся.

Ну это зависит от того нужно Вам это или нет. Компилятору наверно надо хранить такие данные, чтобы помнить все. А интерпретатору нет смысла откладывать решения в какие-то таблицы. Большинство литературы она про компиляторы поэтому и разночтения получаются.

Да и взять простой record оказывается там общепринято переставлять элементы так что-бы оптимизировать расход памяти -  но в тоде время и с дырками!

Да, это называется экономия на спичках. Большинство менеджеров памяти выделяют место странично кратно 4 (иногда 2). То есть если Вам надо 7 байт, Вам дадут 8, как бы Вы не мешали данные в record'ах. Перемешивание данных имеет смысл для границ страницы (то есть расположить так чтобы каждое поле по возможности располагалось в одной странице предоставляемой памяти иначе компилятор просто перенесет поле на новую страницу самостоятельно). Опять же это про компиляторы. Просто так упорядочивать (типа сначала Integer, потом Byte) бесполезно. И я уже молчу об операционках, они выделяют память программам блочно. И пофиг как Вы будете выравнивать свои структуры - надо Вам 25 Кб памяти, операционка Вам даст 32 Кб. Хоть выравнивать record, хоть нет. Смысл в такого рода экономии весьма и весьма сомнителен.
И дополнительно - то что я должен в ручную распихивать порядок в record'ах это вообще говоря косяк компилятора. Он что сам не может автоматически правильно распихать? Может, вся информация у него для этого есть. Почему я должен это делать ручками? Ладно интерпретатору надо торопиться исполнять инструкции, компилятору-то вообще без проблем оптимизировать порядок полей в record. Отсутствие такой возможности просто признак неоптимальности работы компилятора и только. Это прямая вина разработчика конкретной реализации. А язык и тем более программист не должны вообще обращать внимания на эту проблему.

Как только вы захотите сделать обмен с другими или вызывать WinAPI у вас могут появиться трудности с переносом.

Никаких ВинАпи, Вы что кроссплатформенность же. Менеджер для работы с библиотеками приводит данные в правильный вид, а все безобразие должно твориться в динамических библиотеках. Вычислительная модель оторвана от платформы.

Может их стоит выделить из п-кода в отдельную группу?

Может быть да. Я поэтому и пишу это здесь, чтобы избежать грубых ошибок проектирования.
Тут тебе и метки, и особый сорт меток как имена функций

К ним по разному передаётся управление jmp есть call.
И в правильных ассемблера вместо call используют макрос invoke
В паскале есть continue, break, exit. exit - выход из функции
Есть ещё исключения, try-except-finaly и их

С точки зрения парсера нет никакой разницы между break и continue - будет возвращен ИД и параметры (ну в данном случае без параметров). А семантика уже рассматривается дальше.

В паскаль-ABC и С# есть оператор yeold. Его одним П-кодом не опишите, так как там ещё нужно хранить состояние, а это уже Д-код.

Состояние хранится в виртуальной машине. Нет проблем. Рассматривайте вычислительный процесс как дерево, в результате вызов функций и состояния накапливаются рекурсивно. Противоречий не возникает, парсеру нет смысла помнить состояние, для данного оператора также возможен возврат идентификатора конструкции.
Вы смотрите на более крупный блок управления. Я в данный момент описываю трансляцию с описанного программистом синтаксиса в более узкий синтаксис виртуальной машины. Хранить там состояния нет смысла.

или взять стековые макросы фасема, форта.

Внутри языка этого нету, проблема решена бритвой Оккама :).

Или лябды как в Си++.

Лямбды противоречат концепции языка - все является системами, все системы обязаны иметь адресацию для возможности доступа к ним и реализации основных функций, таких как копирование, удаление, определения природы системы и т.д. на этапе исполнения программы. Потому что если система имеет десять безымянных функций, как определить какую из этих десяти требуется скопировать в другую систему? Или передать в качестве параметра в другую функцию. Я понимаю да, что лямбды прямо в вызове описываются. А если я хочу одну и ту же функцию в десять других распихать? И зачем мне этот геморрой десять раз безымянно описывать? Не, не, не. Я понимаю для статики можно мапом пробежаться, но система-то динамическая, я не знаю что нужно передать в мап-функцию, чтобы она смогла туда передать лямбду. Я не знаю какую лямбду будет требоваться передавать - это может стать известно во время выполнения программы. В данной модели вычислений претензий к лямбдам просто вагон и маленькая тележка.

А ведь ещё есть колбеки, они к примеру в WinAPI требуют атрибут STDCALL.

Это не требуется для реализации алгоритмов. Это просто жертвоприношения компьютерам и не больше. Разве, например, в алгоритме калькулятора нужен атрибут STDCall? Нет, там нужно получить два числа и произвести над ними операцию. Вывести на экран в конце-концов. Никакой STDCall там не требуется.

Если безымянные функции, анонимные и виртуальные функции,

Это костыли для решения проблем созданных ранее. Виртуальные функции имеют ограниченный функционал. Системы можно переименовывать, а функции это системы. Я могу любую функцию переименовать в ту, какую нужно, скопировать функцию в систему, построить систему методом прямого копирования. Виртуальная функция в таких условиях вообще теряет смысл. Безымянные и анонимные функции суть те же лямбды в различных ипостасях. А значит не нужны (в данной языке разумеется, в иных случаях это полезная фишка). Безымянная функция в Дельфи это костыль, решающий проблемы жесткой системы типов. Также как и Variant. Сначала создадим бастионы, а потом наделаем там потайных ходов. Ну им это нормально, так как они тянут за собой совместимость со старьем. Мне-то зачем? Я ничем не связан и сразу могу делать как хочется. И плюс у меня есть возможность анализировать их ошибки (у них такой возможности не было) и свои ошибки первой Валентины.

Так как автоматика может породить объект и подставить его под интерфейс. А может использовать существующий объект, а может и вовсе пробросить вызов через сеть.

Вот именно это язык и делает, только с объектами внутри, а не в межпроцессорных взаимодействиях. В случае необходимости будет написана оболочка для согласования различных моделей между собой.

9

utkin

utkin написал(а):

Парсеру вообще пофиг

Мы вообще-то внутреннюю структуру обсуждаем. Причём тут парсер!

utkin написал(а):

Большинство литературы она про компиляторы поэтому и разночтения получаются

Мамая - моя женщина! Интерператор если перевести дословно исполнение через внутреннее представление!
А вы всё через-парсер хотите гонят, через внешнее представление.

utkin написал(а):

Состояние хранится в виртуальной машине. Нет проблем. Рассматривайте вычислительный процесс как дерево, в результате вызов функций и состояния накапливаются рекурсивно.

То бишь изврат по Чёрчу. Вместо того чтобы обратиться к нужному элементу структуры по смещению или сохранить состояние в объект я вынужден описывать десяток функций!

utkin написал(а):

Состояние хранится в виртуальной машине. Нет проблем...........синтаксис виртуальной машины. Хранить там состояния нет смысла.

Ну вот вы сами себе противоречите. Пойми помимо кода есть ещё и данные. И по моему с этим никто не спорит и все согласились. Любая машина состоит из кода и данных - в том числе и виртуальная.  И хранит она не только код, но и данные в некотором формате. Если для кода есть П-код, то для данных есть Д-код. Пусть он будет самый простой и примитивный. Но я считаю что он должен быть.

Ну вот зачем вы всё это суда написали про все эти непотребства? Я знаю что оно всё сделано через одно место.  Я задал один конкретный вопрос. Будете отделять или нет?

utkin написал(а):

Вот именно это язык и делает, только с объектами внутри, а не в межпроцессорных взаимодействиях. В случае необходимости будет написана оболочка для согласования различных моделей между собой.

У вас есть 10 негретят, которые будут писать оболочки за вас? Суть в том что есть стандарты и их проще использовать чем изобретать, по новой  и писать для них поддержку.
Создатель Дизел-паскаля так и не написал своего компилятора, так как погряз вот в таких вот оболочках.

utkin написал(а):

Это не требуется для реализации алгоритмов.

Для алгоритмов может и нет. А вот для систем из нескольких компонентов которые сложнее чем калькулятор нужны. Сложность существующих систем перевалило за 100 человеко лет. Поэтому части разных систем пишут разные люди и общаются между собой на общем языке. В частности шаблоны проектирования и ООП.
Так что это нужные вещи. Вопрос в том вы будете их вводить сейчас или через 10 лет? На вашем месте я бы отложил на 10 лет.

10

Павиа написал(а):

Создатель Дизел-паскаля так и не написал своего компилятора

А разве ставилась такая цель? Зачем ему компилятор? Он же занимается прикладным ПО.

11

Мы вообще-то внутреннюю структуру обсуждаем. Причём тут парсер!

Ну парсер относится к внутренней структуре. А так да недопонимание вышло. Но там ведь описание синтаксиса для парсера.

Мамая - моя женщина! Интерператор если перевести дословно исполнение через внутреннее представление!
А вы всё через-парсер хотите гонят, через внешнее представление.

И между тем отступая от лирики - интерпретатору таблицы состояний не нужны. Я пробовал уже :). Рекурсия рулит.

Вместо того чтобы обратиться к нужному элементу структуры по смещению или сохранить состояние в объект я вынужден описывать десяток функций!

Ну нет, есть же инкапсуляция и абстрагирование. Десять функций можно запихнуть в одну универсальную. Вам дадут одну универсальную вместо десяти.

Ну вот вы сами себе противоречите. Пойми помимо кода есть ещё и данные.

Данные это система, функция это система, программа это система. Э-э-э, есть код, нет кода сложно сказать наверняка.
Внутри есть виртуальная машина которая реализует модель вычислений. Она хранит все состояния и все. Она поддерживает целостность модели и представлений. Внутри нее представляются системы большая часть из которых есть одна универсальная структура.

Если для кода есть П-код, то для данных есть Д-код. Пусть он будет самый простой и примитивный. Но я считаю что он должен быть.

Слабо представляю о чем Вы. Дайте пример.

Ну вот зачем вы всё это суда написали про все эти непотребства? Я знаю что оно всё сделано через одно место.  Я задал один конкретный вопрос. Будете отделять или нет?

Без Вашего пример разницы между П и Д кодами не могу ответить четко на этот вопрос. А то опять выйдет недопонимание :).

У вас есть 10 негретят, которые будут писать оболочки за вас? Суть в том что есть стандарты и их проще использовать чем изобретать, по новой  и писать для них поддержку.

А я попробую. Опять же часть стандартов снова направлено на жертвоприношения - как подносить дары, в каком порядке и как часто это делать. На каждый пункт свой стандарт. Если программисту не требуется обслуживать компьютер, то и эти стандарты становятся не нужны.  Да и про 10 негритят разве не они пишут сложные системы? Хотите или нет, но есть задачи которые в нынешних условиях требует определенных ресурсов. Я сомневаюсь что винду пишет Билл Гейтс по вечерам. Все те же 10 негритят. Я читал интервью от создателя Objective C - его расширения пишут 10 негритят. Он работал в IBM и в его отделе работали десять негритят. Он обслуживал банки Морган Стенли и там было десять негритят. Это одна из причин рождения Objective C. Не десять негритят, а десять негритят пишущих на десяти различных языках программирования.

Для алгоритмов может и нет. А вот для систем из нескольких компонентов которые сложнее чем калькулятор нужны.

Потому что они низкоуровневые.

12

Пример описания синтаксиса перегружен. Зачем нужны эти "Word1="?
Ничего не даёт ни для разбора ни для понимания.

Params=1

Тоже не очевидно. Если уж цель - простота, то надо "число параметров: 1". Или как там по-английски.
Если нужна одновременно и простота разбора - то можно значения на отдельных строках.

Число параметров:
1

13

Пример описания синтаксиса перегружен. Зачем нужны эти "Word1="?

Это порядок следования слов в конструкции. Word1 это значит что это слово в конструкции стоит на первом месте.

Constr
Remark=Оператор цикла
Id=5
Word1=Повторять Повторить Повтор Повторяем
Word2=Пока
Word3=1

Здесь лексемма Повторять идет первой в конструкции. Лексемма Пока во второй.
Так интерпретатор знает, что Повторить пока х>10 это правильно, а Пока повторить х>10 неправильно.

Тоже не очевидно. Если уж цель - простота, то надо "число параметров: 1". Или как там по-английски.

Это можно исправить, дадите вариант, я попробую запихнуть.

Если нужна одновременно и простота разбора - то можно значения на отдельных строках.

Пустые строки и нераспознанные строки игнорируются. Это предоставляет Вам широкие возможности для комментариев и форматирования. Вы можете вставлять комментарии просто русским текстом перед каждой строкой. Можно написать оболочку для редактирования таких файлов (в первой Валентине примитивная система была).

14

utkin написал(а):

Это порядок следования слов в конструкции. Word1 это значит что это слово в конструкции стоит на первом месте.

Они и так уже упорядочены по строкам:

Id=5
Повторять Повторить Повтор Повторяем
Пока
1

Да, 5 и 1 - неочевидные числа. Видимо, ссылки.

Это предоставляет Вам широкие возможности для комментариев и форматирования.

Для комментариев тоже можно отдельный заголовок вроде "Замечание:" и далее до пустой строки.

Пустые строки и нераспознанные строки игнорируются.

Пустые строки более одной подряд  бессмысленны. Не распознанные - очень плохо, т.к. предполагают сразу полное знание наизусть всех распознаваемых.
Т.е. вообще не пригодно ни для одного новичка.

utkin написал(а):

Можно написать оболочку для редактирования таких файлов (в первой Валентине примитивная система была).

Неудобство в том, что значения, которые правятся, не выровнены и слишком сливаются с заголовками.
Это легко решается, построчно чередуя названия и значения, или CSV, но там знак ";" зарезервирован как разделитель. Х.з., м.б. последнее как-то обходится.

15

Они и так уже упорядочены по строкам:

Так Вы не обязаны это делать. А если допустите ошибку? Нет я не против, просто это делалось так по этой причине. И потом как определить что это действительно лексема, а пояснение в тексте метаязыка?

Да, 5 и 1 - неочевидные числа. Видимо, ссылки.

Это просто примеры. Смотрите ID это обозначение семантики. Эти ИД должен обрабатывать интерпретатор. Он "знает" что 5 это цикл (например), а 6 к примеру оператор условия if. То есть ID это информация о том, как должен себя вести интерпретатор, когда ему встретится эта конструкция. Внутри себя он это число преобразует в функцию, которая выполнит нужное действие в виртуальной машине.
Число 1 жестко привязано к ID. Это порядок следования параметров. Вот смотрите как:

Constr
Remark=Оператор цикла
Id=5
Word1=Повторять Повторить Повтор Повторяем
Word2=Пока
Word3=1

В данном случае будет корректна операция Повторяем пока х>10
То есть в первом случае рассматривается шаблон Повторяем пока <параметр1>
Если перед нами:

Constr
Remark=Оператор цикла
Id=5
Word1=Повторять Повторить Повтор Повторяем
Word2=1
Word3=Пока

То корректной будет операция
Повторить x>10 пока
Во втором случае рассматривается шаблон: Повторить <параметр1> пока
Число 1 означает первый параметр конструкции (в данном примере это x>10). Есть конструкции в которых может быть несколько таких параметров.
Например короткая форма условия
Если <параметр1>, тогда <параметр2>

Constr
Remark=Условие
Id=5
Word1=Если
Word2=1
Word3=,
Word4=Тогда
Word5=2

И тогда допускается 2 использовать раньше, например:

Constr
Remark=Условие
Id=5
Word1=Выполнить
Word2=2
Word3=,
Word4=Если
Word5=1

И тогда отслеживается конструкция вида Выполнить <параметр2>, если <параметр1>
Оба условия делают абсолютно одно и тоже и суть синтаксический сахар. Но для описания синтаксиса это дает определенную свободу. И второе можно насостовлять таких конструкций, что запись будет приближена к человеческой (правда там свои проблемы уже есть).
Если Вы сторонник краткости, можно добавить конструкцию вида:

Constr
Remark=Условие
Id=5
Word1=Если
Word2=1
Word3=то
Word4=2

Шаблон вида Если <параметр1> то <параметр2> (то есть без запятой после условия)
И все эти условия можно использовать одновременно в одном диалекте. Читабельность текста возрастает в разы (вместе с неоднозначностью восприятия разумеется).

Это легко решается, построчно чередуя названия и значения, или CSV, но там знак ";" зарезервирован как разделитель.

Впервые слышу. CSV разделитель может быть любым.

Пустые строки более одной подряд  бессмысленны.

Да почему это? Отлично можно красиво разделять секции.

Неудобство в том, что значения, которые правятся, не выровнены и слишком сливаются с заголовками.

Если У Вас будет программа, будет все равно.
Пока это стандартный файл конфигурации состоит из секций и наборов пар ключ=значение. Никаких проблем, раньше было стандартом (только секции брали в квадратные скобки).

16

На данный момент СуперВселенная 1 обзавелась двумя ветвями:
- 0 - описание систем
- 1 - ветвь исполнения программы
В 0 извлекаются все системы из внешних модулей, затем запускаемая система будет копироваться в 1, выполняться конструктор, а затем старт системы по точке входа.
Любые упоминания систем из внешних модулей в функциях будут копировать описания систем из 0 в соответствующую ветвь исполнения. Гибкость такого подхода в том, что в разных модулях можно многократно ссылаться на одни и те же внешние модули - их можно скопировать только один раз при первом упоминании :). Работа ведется в соответствии с моделью - один исходник - много систем (обсуждалось ранее). Таким образом, допускаются разные системы с одинаковыми именами в разных модулях. Обращение к описаниям систем (например для копирования) из внешних модулей требует обязательного упоминания имени модуля.
http://se.uploads.ru/t/6Dgmj.png
Здесь main(.vlt) имя файла с исходником.

17

Добавлены разбор стартовой точки и конструктора. Сейчас работы идут над самым интересным - рекурсивным подключением внешних модулей. Увы, времени маловато :).
http://sa.uploads.ru/t/bG3Av.png

18

Где и как искать подключаемые внешние модули?
Пока предлагается такая стратегия:
1. Ищем в каталоге с программой. Если там найдем, то его и грузим.
2. Ищем в специальном каталоге с интерпретатором (там по идее должна храниться библиотека модулей, реализующих базовые возможности, чтобы не писать их каждый раз ручками)

Приоритет расширений. Тут такая вещь, предполагается, что модуль указывается без расширения, а интерпретатор настолько умный, что сам его подставляет. Но я же либерал и демократ, а потому предлагается их несколько на выбор. Итак, что грузим сначала в порядке убывания:
1. Расширение *.влн (типа сокращения от Валентина)
2. Расширение *.влт (аналогично)
3. Расширение *.vln (Valentina)
4. Расширение *vlt (аналогично)
5. Просто файл, без расширения

Тут конечно волею хаоса может быть в каталоге два файла с одним именем и разными расширениями. Ну что поделаешь, не судьба :(, кто-то должен грузиться первым.
Если возражений нет и не предвидится, то так и станет в ближайшие пару дней. Я предупредил :)

19

Итак, получилось.
http://s9.uploads.ru/t/ijkJb.png
Текст первого модуля (main.vlt):

Система : Новая_система

Нужно:  spisok
Создание: стартовая_функция

Пуск: функция_конструктор

Псевдонимы:
система= system
нужно = dependencies

fhdsjkfhsjdkhfkjdh


Текст второго модуля (spisok.vlt):

Система: СПИСОК

Создание: стартовая_функция

Пуск: функция_конструктор

Псевдонимы:
система= system
нужно = dependencies

fhdsjkfhsjdkhfkjdh

На картинке видим, что в модуле main (это сама центральная программа у нас получается) идет описание системы Новая_система
В модуле spisok вгружена система СПИСОК, потому что она нужна Новой_системе.
При этом в команде Нужно: указывается имя модуля, его расширение гадается на кофейной гуще в соответствии с алгоритмом приведенным постом ранее :).
Собственно говоря первая секция описания систем закончена и знаменуется теперь тем, что все остальные секции по мере добавления будут рекурсивно разбираться и для внешних модулей.
Итак, подводя итоги, интерпретатор теперь умеет разбирать первую секцию, то есть описания вида:

Система: Тип_системы
Нужно: Список_имен_внешних_систем_через_запятую
Пуск: Имя_функции_для_запуска_системы_как_самостоятельной_программы
Создание: Имя_функции_ответственной_за_подготовку_системы_к_работе
Псевдонимы:
Идентификатор_на_национальном_языке=Идентификатор_на_английском


Теперь приступаем к разбору второй секции:

Структура
Открытая часть
    Список_и/или_описания_систем
    Список_функций
    Значение
Закрытая часть
    Список_и/или_описания_систем
    Список_функций
    Значение

Учитывая накопленный опыт и более простую структуру секции, работы должны идти намного быстрей.


Вы здесь » Ремесло программиста » Валентина » Аспекты внутреннего устройства