Сделал примерно следующее:
Ну и есть "итераторы":
Примерно вот в таком ключе:
https://bitbucket.org/lulinalex/mindstream/commits/51387b73dd34d9359bb8dc86f86fd2d01e198a00
Как-то так...
Практические примеры - позже.
Зачем нужно? Чтобы грузить "данные" превращать их в "код" и по этому коду грузить НОВЫЕ данные.
Вот есть мета-мета-модель UML. При помощи неё грузим мета-модель UML.
А при помощи мета-модели грузим модель UML.
А из модели UML получаем код на целевом языке.
Как-то так...
Да. Дерево разбора это байт-код стековой машины. Который вообще говоря умеет исполняться в соответствии с той грамматикой, которая его построила.
Парсинг и выполнение кода выглядит так:
Ну и есть "ручки сбоку" для залезания в "кишки кода" - MembersIterator и CodeIterator (см. выше).
При этом код знает про грамматику, которая его породила.
Если написать так:
То будут последовательно применены N грамматик.
Базовая грамматика выглядит примерно так:
А она в свою очередь выводится из аксиоматики стековой машины - Ни о чём. Обновление аксиоматики.
Тесты вида - Только код. Примеры "высокоуровневых" тестов - оттуда же выводятся.
Весь вопрос только в словарях и грамматиках.
+Виктор Морозов
+Михаил Костицын
Примеры того же, но из "прошлой жизни", без грамматик:
Коммит:
https://bitbucket.org/lulinalex/mindstream/commits/251e79385cd307a87fad5ad851104c5814080f35
Вот тут - 'W:\shared\models\NewSchool\MDProcess.root.script' - данные.
Вот тут - 'W:\shared\models\NewSchool\Templates\MDALike.tpl.script' - грамматика.
Грамматики "без грамматик".
for %S%Attrs OUT - итератор по атрибутам.
%S - self - сам элемент.
%P или %S%P - родитель.
%P%P или %S%P%P - родитель родителя.
Жаль, что многое в "закорючках", но это наследие прошлого.
Я работаю над этим.
Что такое "грамматика" - это описание "скобочных структур" в терминах других "скобочных" структур.
Ну как DTD и XML + XSLT.
Скажем так:
DTD - описание мета-модели.
XML - модель.
XSLT - способ преобразования одной модели в другую.
Только у меня ещё можно позвать так:
%S %Meta %f method - вызов метода мета-класса.
И даже так:
%S %Meta %Meta %f method - вызов метода мета-мета-класса.
И даже так:
%S %Meta %Meta %Meta %f method - вызов метода мета-мета-мета-класса.
Т.е. определяем не только "грамматику" (в терминах "скобочек"), но и способы работы с ней.
Например:
%S %Meta %f IsClass - узнаём, что %S - является классом (в терминах UML).
%S %Meta %f IsCategory - узнаём, что %S - является категорией (в терминах UML).
или:
%S %Meta %Meta %f IsGrammar UML - узнаём, что %S - относится к грамматике UML.
%S %Meta %Meta %f IsGrammar Test - узнаём, что %S - относится к грамматике тестов.
%S %Meta %Meta %f IsGrammar FORTH - узнаём, что %S - относится к грамматике FORTH-машины.
или:
%S %f GeneratesTo C++ - узнаём, что %S - генерируется в C++.
%S %f GeneratesTo Delphi - узнаём, что %S - генерируется в Delphi.
И т.д. и т.п.
А можно пристегнуть "способы работы" - "сбоку". Обрабатывая итераторы MembersIterator и CodeIterator.
Т.е. хотим - парсим данные и получаем "предопределённый разработчиками код" и выполняем его. А хотим - парсим данные и получаем "код", а потом обрабатываем его итераторами.
Возможно вызывая методы мета и мета-мета классов.
Это всё дерево деревьев деревьев разбора. Где каждое предыдущее дерево описывает последующее и имеет с ним двунаправленные связи. И "данные" и "код".
Начинаем от мета-UML и приходим к Delphi. Это к примеру.
Вдогонку:
"есть базовая FORTH аксиоматика
из неё выводим FORTH1
потом FORTH2
потом GUI-Тесты
или RTF-парсер
или генератор в Delphi
это понятно?
FORTH -> FORTH1 -> FORTH2 -> RTF
примерно так
грамматику на каждом этапе подтачиваем под следующий
грамматика мимикрирует"
"ну суть там банальна - сначала парсим текстовый поток - так - потом так - а потом эдак - а потом разэдак
и после каждого парсинга получаем дерево разбора
с данными и методами
которые применяются на последующей итерации"
Ну и напоследок.
Я надеюсь, что товарищ не обидится на цитату:
""И наконец термин «псевдовектор» обычно объясняется студентам так: «Посмотрите, ведь мы показали, что омега — скалярная величина. А вектор мы вводим для того, чтобы выписать формулу Эйлера».""
Но как-то - да.
Мне всегда нравилась "линейная алгебра" и "векторные пространства".
Особенно - евклидово и метрики со скалярным произведением.
FILE VAR File1 FILE VAR File2 ... FILE VAR FileN // - входные файлы Grammar VAR G // - грамматика G := nil // - начальная грамматика FORTH-машины OBJECT VAR ParseTree // - дерево разбора ParseTree := ( File1 ParseWith G ) // - получаем дерево разбора По файлу File1 и грамматике G G := ( ParseTree As Grammar ) // - получаем из дерева разбора новую грамматику ParseTree := ( File2 ParseWith G ) // - получаем дерево разбора По файлу File2 и грамматике G G := ( ParseTree As Grammar ) // - получаем из дерева разбора новую грамматику ... ParseTree := ( FileN ParseWith G ) // - получаем дерево разбора По файлу FileN и грамматике G G := ( ParseTree As Grammar ) // - получаем из дерева разбора новую грамматику
Ну и есть "итераторы":
ParseTree MembersIterator ==> ( OBJECT IN aMember ... ) ParseTree CodeIterator ==> ( OBJECT IN aCodeItem ... )
Примерно вот в таком ключе:
FORWARD DumpElement INTEGER VAR Indent [EXECUTE] ( Indent := 0 ) VOID WORDWORKER Out STRING VAR aValue aValue := ( WordToWork DO ) [ Indent ' ' char:Dupe aValue ] strings:Cat . ; // Out VOID WORDWORKER OutEx STRING VAR aValue aValue := ( WordToWork DO ) if ( aValue <> '' ) then Out aValue ; // OutEx VOID WORDWORKER OutA ARRAY VAR l_Value l_Value := ( WordToWork DO ) OutEx ( l_Value strings:Cat ) ; // OutA STRING FUNCTION Check STRING IN aName if ( '??? Unexisting word ???' aName StartsStr ) then ( Result := '' ) else ( Result := aName ) ; // Check STRING FUNCTION CodeName OBJECT IN aCode STRING VAR l_Name aCode pop:Word:Name Check >>> l_Name if ( l_Name <> '' ) then ( Result := l_Name ) else ( if ( aCode Is class::TkwString ) then ( Result := ( [ '''' aCode DO '''' ] strings:Cat ) ) else if ( aCode Is class::TkwInteger ) then ( Result := ( aCode DO IntToStr ) ) else ( Result := '' ) ) ; // CodeName FORWARD DumpCodeCall PROCEDURE DumpMembers OBJECT IN aCode aCode MembersIterator ==> ( OBJECT IN aCode if ( aCode Is class::TkwForwardDeclaration ) then OutA [ 'FORWARD ' aCode CodeName ] ) aCode MembersIterator ==> ( OBJECT IN aCode aCode DumpElement ) ; // DumpMembers PROCEDURE DumpElementPrim BOOLEAN IN aNeedStereo OBJECT IN aCode STRING VAR l_Name aCode CodeName >>> l_Name if aNeedStereo then ( if ( l_Name = 'WordToWork' ) then EXIT if ( l_Name = 'Result' ) then EXIT ) STRING VAR l_Stereo STRING VAR l_Directives aCode pop:Word:Producer pop:Word:Name Check >>> l_Stereo aCode pop:Word:Directives >>> l_Directives if aNeedStereo then ( if ( l_Stereo <> '' ) then ( [ l_Stereo ' ' l_Name ] strings:Cat >>> l_Name ) if ( ( l_Directives <> '' ) AND ( l_Directives <> ' ' ) ) then ( [ l_Directives l_Name ] strings:Cat >>> l_Name ) ) if ( l_Name <> '' ) then ( OutEx l_Name Inc Indent ) TRY aCode DumpMembers aCode CodeIterator ==> ( OBJECT IN aCode aCode DumpCodeCall ) FINALLY if ( l_Name <> '' ) then ( Dec Indent ) END if ( l_Name <> '' ) then if aNeedStereo then ( STRING VAR l_Bracket l_Bracket := ( aCode pop:Word:Producer pop:Word:EndBracket ) if ( l_Bracket <> '' ) then ( OutA [ l_Bracket ' // ' l_Name ] Out '' ) ) ; // DumpElementPrim PROCEDURE OutBracket OBJECT IN aCode if ( aCode CodeName = 'TRY' ) then ( EXIT ) STRING VAR l_Bracket l_Bracket := ( aCode pop:Word:Producer pop:Word:EndBracket ) //l_Bracket := ( aCode pop:Word:EndBracket ) if ( l_Bracket <> '' ) then OutEx l_Bracket ; // OutBracket PROCEDURE DumpCodeCall OBJECT IN aCode if ( aCode Is class::TkwCompiledInitParam ) then ( EXIT ) STRING VAR l_Name BOOLEAN VAR l_NeedBracket l_NeedBracket := false aCode CodeName >>> l_Name INTEGER VAR l_LeftWordRefsCount l_LeftWordRefsCount := ( aCode pop:Word:LeftWordRefValuesCount ) while ( l_LeftWordRefsCount > 0 ) ( Dec l_LeftWordRefsCount OBJECT VAR l_Param l_Param := ( l_LeftWordRefsCount aCode pop:Word:GetLeftWordRefValue ) if NOT ( l_Param pop:object:IsNil ) then ( [ l_Param CodeName ' ' l_Param CodeIterator ==> ( OBJECT IN aCode aCode CodeName ) l_Name ] strings:Cat >>> l_Name ) ) OutEx l_Name //Inc Indent TRY RULES ( aCode Is class::TkwCompiledWordContainer ) ( aCode CodeIterator ==> ( OBJECT IN aCode false aCode DumpElementPrim aCode OutBracket ) ) ( aCode Is class::TkwBeginLikeCompiledCode ) ( l_NeedBracket := true Inc Indent aCode DumpMembers aCode CodeIterator ==> ( OBJECT IN aCode aCode DumpCodeCall ) Dec Indent ) ( aCode Is class::TkwCompiledWordWorkerWordRunner ) ( aCode CodeIterator ==> ( OBJECT IN aCode aCode DumpCodeCall ) ) ( ( aCode Is class::TkwCompiledVarWorker ) // OR // ( aCode Is class::TkwVarModifier ) ) ( Inc Indent aCode CodeIterator ==> ( OBJECT IN aCode aCode DumpCodeCall ) Dec Indent ) ( aCode Is class::TkwCompiledWordWorker ) ( aCode CodeIterator ==> DumpCodeCall ) ( aCode Is class::TkwForwardDeclarationHolder ) ( aCode CodeIterator ==> DumpCodeCall ) ( aCode Is class::TkwCompiledRules OR ( aCode Is class::TkwCompiledCase ) ) ( l_NeedBracket := true BOOLEAN VAR l_Shift l_Shift := false Inc Indent aCode CodeIterator ==> ( OBJECT IN aCode l_Shift ? Inc Indent aCode DumpCodeCall l_Shift ? Dec Indent l_Shift := NOT l_Shift ) Dec Indent ) ; // RULES FINALLY //Dec Indent END if l_NeedBracket then ( aCode OutBracket ) ; // DumpCodeCall PROCEDURE DumpElement OBJECT IN aCode true aCode DumpElementPrim ; // DumpElement PROCEDURE DumpCode STRING IN aFileName aFileName script:CompileAndProcess DumpElement '' . ;
https://bitbucket.org/lulinalex/mindstream/commits/51387b73dd34d9359bb8dc86f86fd2d01e198a00
Как-то так...
Практические примеры - позже.
Зачем нужно? Чтобы грузить "данные" превращать их в "код" и по этому коду грузить НОВЫЕ данные.
Вот есть мета-мета-модель UML. При помощи неё грузим мета-модель UML.
А при помощи мета-модели грузим модель UML.
А из модели UML получаем код на целевом языке.
Как-то так...
Да. Дерево разбора это байт-код стековой машины. Который вообще говоря умеет исполняться в соответствии с той грамматикой, которая его построила.
Парсинг и выполнение кода выглядит так:
ParseTree := ( File1 ParseWith G ) ParseTree DO
Ну и есть "ручки сбоку" для залезания в "кишки кода" - MembersIterator и CodeIterator (см. выше).
При этом код знает про грамматику, которая его породила.
Если написать так:
ParseTree := ( File1 ParseWith [ G1 G2 .. GN ] )
То будут последовательно применены N грамматик.
Базовая грамматика выглядит примерно так:
// Тут описываем слова, необходимые для построения дерева разбора модели MDA вылитой в формат скрипта StereotypeStereotypeProducer @MDAClass ; // - базовый стереотип, через который всё выводится <<@MDAClass>> MDAClass ; <<@MDAClass>> MDACategory ; // - заглушки для начальной раскрутки <<MDACategory>> Project ; // - проект <<@MDAClass>> MDAAbstractClass ; <<@MDAClass>> MDADependency ; <<@MDAClass>> MDAAttribute ; //StereotypeProducer MDAStateMachine //StereotypeProducer MDAState //StereotypeProducer MDATransition //StereotypeProducer MDATransitionAttribute //StereotypeProducer MDAStateAction // - а эти парни вообще выводятся на модели из первых двух <<@MDAClass>> MDAOperation ; // - стереотип для создания типов операций <<MDACategory>> MDATemplates ; <<MDACategory>> MDALibrary ; // - MDA-библиотека <<MDACategory>> MDALayer ; <<MDAClass>> MDAUtilityPack ; // - набор утилитных функций MDA <<MDAClass>> MDAGenerator ; StereotypeProducer mdalink <<mdalink>> group ; <<mdalink>> include ; <<mdalink>> main_hierarchy ; <<MDAOperation>> generator ; // - генератор элементов модели <<MDAOperation>> transformator ; // - трансформатор (аналог CASE в mda-генераторе) <<MDAOperation>> Operation ; // - операция (любая, что MDA, что нет - любая операция без стереотипа) <<@MDAClass>> MDAParameter ; // - стереотип параметра //WordAlias <<param>> <<MDAParameter>> //<<MDAParameter>> param ; StereotypeProducer param <<param>> in ; // - входной параметра (изменяться не может) StereotypeProducer up // - стереотип для типов пользовательских свойств <<up>> bool ; // - булево значение UP <<up>> string ; // - строковое значение UP <<up>> list ; // - значение UP из заранее заданного списка значений <<up>> color ; <<up>> tribool ; // - трёхпозиционное значение UP undefined/false/true <<up>> text ; <<MDAClass>> MDAReport ; <<MDAOperation>> report ;
А она в свою очередь выводится из аксиоматики стековой машины - Ни о чём. Обновление аксиоматики.
Тесты вида - Только код. Примеры "высокоуровневых" тестов - оттуда же выводятся.
Весь вопрос только в словарях и грамматиках.
+Виктор Морозов
+Михаил Костицын
Примеры того же, но из "прошлой жизни", без грамматик:
USES 'W:\shared\models\NewSchool\MDProcess.root.script' ; USES 'W:\shared\models\NewSchool\Templates\MDALike.tpl.script' ; : Gen //help WordAliasByRef X_MDAClass :: UIDS_LIST 46E1540F00AB ; WordAliasByRef X_MDALibrary :: UIDS_LIST 46E155F80242 ; //help PROCEDURE OUT IN %S //%S |N . %SN . //%S |S . %SS . %S %ST %ST |N . %S %ST %ST %ST |N . %S %ST %ST %ST %ST |N . //%S |U . %SU . ; PROCEDURE X IN %S %S OUT //%S %P OUT %S%P OUT //%S %P %P OUT %S%P%P OUT //%S %P %P %P OUT %S%P%P%P OUT //%S %P %P %P %P OUT %S%P%P%P%P OUT //%S %P %P %P %P %P OUT %S%P%P%P%P%P OUT ; @ <<MDAClass>> %R IT X @ <<MDALibrary>> %R IT X @ X_MDAClass %R IT X @ X_MDALibrary %R IT X @ <<MDAClass>> %G IT X @ <<MDALibrary>> %G IT X '' . ARRAY VAR A @ X_MDAClass %R >>> A //[ :: X_MDAClass %R ; ] >>> A @ X A ITERATE '' . @ X_MDALibrary %R >>> A //[ :: X_MDALibrary %R ; ] >>> A @ X A ITERATE //ARRAY VAR A //[ <<MDAClass>> %G ] >>> A ; Gen ... USES 'W:\shared\models\NewSchool\MDProcess.root.script' ; USES 'W:\shared\models\NewSchool\Templates\MDALike.tpl.script' ; : Gen : OUT IN %S %SN . %SS . ; @ MDProcess$Templates |S . @ MDProcess$Templates MembersIterator ==> OUT @ MDProcess$ForDelphi |S . @ MDProcess$ForDelphi MembersIterator ==> OUT @ MDProcess$ForF1 |S . @ MDProcess$ForF1 MembersIterator ==> OUT ; Gen ... USES 'W:\shared\models\NewSchool\Templates\MDALike.tpl.script' ; PROCEDURE OUTPRIM IN %S %S NotValid ? EXIT %SN . %SS . %S %ST %ST |N . ; FORWARD OUTSAFE PROCEDURE OUTSAFE IN %S %S NotValid ? EXIT %S OUTPRIM for %S%G ( IN %S %S OUTPRIM if ( %S NotValid ! ) then ( for %S%G OUTSAFE ) ) ; FORWARD OUT PROCEDURE OUT IN %S %S NotValid ? EXIT %S OUTPRIM for %S%G ( IN %S %S OUTPRIM ) for %S%Attrs OUT for %S%Ops OUT for %S%C OUT %S%T OUTSAFE ; USES 'W:\shared\models\NewSchool\SharedDelphi.root.script' ; /*{USES 'W:\shared\models\NewSchool\SharedDelphiOperations.root.script' ; USES 'W:\shared\models\NewSchool\Shared Delphi Scripting\Shared Delphi Scripting.model.script' ; USES 'W:\shared\models\NewSchool\SharedDelphiTests.root.script' ;}*/ Test Gen @ "Shared Delphi" OUT // @ "Shared Delphi Scripting" OUT // @ "Shared Delphi Operations" OUT // @ "Shared Delphi Tests" OUT ; Gen
Коммит:
https://bitbucket.org/lulinalex/mindstream/commits/251e79385cd307a87fad5ad851104c5814080f35
Вот тут - 'W:\shared\models\NewSchool\MDProcess.root.script' - данные.
Вот тут - 'W:\shared\models\NewSchool\Templates\MDALike.tpl.script' - грамматика.
Грамматики "без грамматик".
for %S%Attrs OUT - итератор по атрибутам.
%S - self - сам элемент.
%P или %S%P - родитель.
%P%P или %S%P%P - родитель родителя.
Жаль, что многое в "закорючках", но это наследие прошлого.
Я работаю над этим.
Что такое "грамматика" - это описание "скобочных структур" в терминах других "скобочных" структур.
Ну как DTD и XML + XSLT.
Скажем так:
DTD - описание мета-модели.
XML - модель.
XSLT - способ преобразования одной модели в другую.
Только у меня ещё можно позвать так:
%S %Meta %f method - вызов метода мета-класса.
И даже так:
%S %Meta %Meta %f method - вызов метода мета-мета-класса.
И даже так:
%S %Meta %Meta %Meta %f method - вызов метода мета-мета-мета-класса.
Т.е. определяем не только "грамматику" (в терминах "скобочек"), но и способы работы с ней.
Например:
%S %Meta %f IsClass - узнаём, что %S - является классом (в терминах UML).
%S %Meta %f IsCategory - узнаём, что %S - является категорией (в терминах UML).
или:
%S %Meta %Meta %f IsGrammar UML - узнаём, что %S - относится к грамматике UML.
%S %Meta %Meta %f IsGrammar Test - узнаём, что %S - относится к грамматике тестов.
%S %Meta %Meta %f IsGrammar FORTH - узнаём, что %S - относится к грамматике FORTH-машины.
или:
%S %f GeneratesTo C++ - узнаём, что %S - генерируется в C++.
%S %f GeneratesTo Delphi - узнаём, что %S - генерируется в Delphi.
И т.д. и т.п.
А можно пристегнуть "способы работы" - "сбоку". Обрабатывая итераторы MembersIterator и CodeIterator.
Т.е. хотим - парсим данные и получаем "предопределённый разработчиками код" и выполняем его. А хотим - парсим данные и получаем "код", а потом обрабатываем его итераторами.
Возможно вызывая методы мета и мета-мета классов.
Это всё дерево деревьев деревьев разбора. Где каждое предыдущее дерево описывает последующее и имеет с ним двунаправленные связи. И "данные" и "код".
Начинаем от мета-UML и приходим к Delphi. Это к примеру.
Вдогонку:
"есть базовая FORTH аксиоматика
из неё выводим FORTH1
потом FORTH2
потом GUI-Тесты
или RTF-парсер
или генератор в Delphi
это понятно?
FORTH -> FORTH1 -> FORTH2 -> RTF
примерно так
грамматику на каждом этапе подтачиваем под следующий
грамматика мимикрирует"
"ну суть там банальна - сначала парсим текстовый поток - так - потом так - а потом эдак - а потом разэдак
и после каждого парсинга получаем дерево разбора
с данными и методами
которые применяются на последующей итерации"
Ну и напоследок.
Я надеюсь, что товарищ не обидится на цитату:
""И наконец термин «псевдовектор» обычно объясняется студентам так: «Посмотрите, ведь мы показали, что омега — скалярная величина. А вектор мы вводим для того, чтобы выписать формулу Эйлера».""
Но как-то - да.
Мне всегда нравилась "линейная алгебра" и "векторные пространства".
Особенно - евклидово и метрики со скалярным произведением.
Комментариев нет:
Отправить комментарий