Re: [Nemerle DSL] Описание конечного автомата
От: CodingUnit Россия  
Дата: 04.02.10 10:52
Оценка:
Здравствуйте, VladD2, Вы писали:



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


VD>Если бы я решал подобную задачу, то скорее всего я выбрал бы следующий подход:

VD>1. Каждый автомат я описывал бы как отдельный класс.
VD>2. Список состояний я описывал бы в метаатрибуте которым помечал бы этот класс.
VD>3. Синтаксис сделал бы похожим на описание локальных функций.
VD>4. Реакции на переходы описывал бы как методы внутри этого класса.

VD>Вот как мог бы выглядеть приведенный выше автомат:

VD>
VD>


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

CU>>
CU>>[statemachine]
CU>>class TestFSM
CU>>{

CU>>  [state]
CU>>  class Top // самое верхнее состояние
CU>>  {
    
CU>>    [state]
CU>>    class Start // подсостояние Top
CU>>    {
       
CU>>      [state]
CU>>      class Sub1 // подсостояние Start
CU>>      {
            [state]  
            class Sub2 // подсостояние Sub1
            {

            }
CU>>      } 
CU>>    }
    
CU>>    [state]
CU>>    class Next // подсостояние Top
CU>>    {

CU>>    }
CU>>  }
CU>>}
CU>>


графически они выглядят примерно так



В принципе с метаатрибутом описать весь автомат можно, лишь бы это не сложно было сделать, тогда описание будет выглядеть примерно так:
 [FsmDef(
 {
 state Top
  {
        state Start
        {
        | Event1 => Next // переход по событию Event1

           // подостояние 1
           state Sub1
           {
           | entry => {
                      Action1 // действие при входе
                      }
           | exit => Action2 // действие при выходе

            // подсостояние 2            
             state Sub2
             {
             
             }
           }
        } 
       
        state Next
        {
        | Event2 => Start
        }
  }
})]
class MyFsm
{
  // обарботчик события перехода 
  EnterIn_IdleInGear_State(previosState : MyFsmState) : void
  {
    ... код обработки 
  }


сложно ли такую структуру считать в макросе? Там видимо понадобится дополнительный рекурсивный разбор каждого вложенного состояния и создание иерархии, при этом надо как то выделить части | name, и вложенные state. Hадо еще чтобы какой то класс хранил состояние структуру, то есть создавался однократно и использовался как синглтон в дальнейшем. Сложность пока только в том чтобы распознать конструкции | и state на одном уровне, остальное дело техники, не могли бы вы Владислав описать примерно как такое можно сделать, и что такое ..$ в цитате, в прошлом посте оно позволило развернуть лист выражений в цитате? В этих конструкциях match с чем конкретно он сравнивает, после switch такая конструкция выглядит странно, как я понимаю там списки из Expression, то есть он сравнивает списки экземпляров Expression?

VD>

VD> ...
VD>}
VD
VD>Выше я описал возможный вариант.
VD>Для реализации данного подхода нужно описать и реализовать два макроса:
VD>1. FsmDef — метаатрибут. В нем должна производиться основная работа по построению конечного автомата.
VD>2. state — макрос уровня выражения. Нужен только для того, чтобы немерле мог воспринимать синтаксис описания состояния — "state имяСостояния список состояний".

VD>Вот как могут выглядеть заглушки (т.е. без реализации) этих макросов:

VD>
VD>  [Nemerle.MacroUsage(Nemerle.MacroPhase.BeforeTypedMembers, Nemerle.MacroTargets.Class)]
VD>  macro FsmDef(type_builder : TypeBuilder, body)
VD>  {
VD>  }

VD>  macro State(stateName, body)
VD>  syntax("state", stateName, body)
VD>  {
VD>    <[ () ]> // В этом макросе нам ничего делать не надо. Он нужет только чтобы немерле "пропустил" наш синтаксис.
VD>  }
VD>


VD>Понимаю, что без опыта создания макросов распознать столь не тривиальную структуру будет не просто. По этому я потратил час, чтобы набросать примерную реализацию макросов. Вот что у меня получилось...

VD>Сами макросы:
VD>
VD>using Nemerle;
VD>using Nemerle.Compiler;
VD>using Nemerle.Compiler.Parsetree;
VD>using System.Diagnostics;

VD>namespace MacroLibrary2
VD>{
VD>  [Nemerle.MacroUsage(Nemerle.MacroPhase.BeforeTypedMembers, Nemerle.MacroTargets.Class)]
VD>  macro FsmDef(type_builder : TypeBuilder, body)
VD>  {
VD>    Helper.MakeFsm(type_builder, body);
VD>  }

VD>  macro State(stateName, body)
VD>  syntax("state", stateName, body)
VD>  {
VD>    _ = stateName; // говорим компилятору, что мы намеренно не желаем использовать параметр
VD>    _ = body;      // тоже самое
VD>    <[ () ]> // В этом макросе нам ничего делать не надо. Он нужен только чтобы немерле "пропустил" наш синтаксис.
VD>  }
  
VD>  module Helper
VD>  {
VD>    public MakeFsm(ty : TypeBuilder, body : PExpr) : void
VD>    {
VD>      def makeTransition(transitionDef : MatchCase) : void
VD>      {
VD>          Message.Hint(transitionDef.Location, $"  Events=$(transitionDef.patterns) Transition=$(transitionDef.body)")
VD>      }
    
VD>      def makeSate(stateDef : PExpr) : void
VD>      {   // ncc заворачивает обращение к макросу в конструкцию PExpr.MacroCall...
VD>        | PExpr.MacroCall(name, _, parms) when name.Id == "state" =>
          
VD>          match (parms)
VD>          { // параметры (код передаваемый в них) макроса заворачиваются в SyntaxElement.Expression.
VD>            // Пользователь должен передать два параметра...
            
VD>              // имя и пустую группу...
VD>            | [Expression(<[ $stateName ]>), Expression(<[ { } ]>)] => 
VD>              Message.Hint(stateName.Location, $"Распознано описание состояния '$stateName' (без переходов!)");

VD>              // или имя и список вхождений оператора match который компилятор превращает в полноценный оператор match...              
VD>            | [Expression(<[ $stateName ]>), Expression(<[ match ($_) { ..$transitions } ]>)] =>
VD>              Message.Hint(stateName.Location, $"Распознано описание состояния '$stateName'. Переходы:");
            
VD>              foreach (transitionDef in transitions)
VD>                makeTransition(transitionDef);
                
VD>            | [Expression(<[ $_ ]>), Expression(<[ { $x } ]>)] =>
VD>              Message.Error(x.Location, "Ожидается описание переходов в формате: { | Event => State | Event => State ... }");
              
VD>            | _ => 
VD>              Message.Error(stateDef.Location, 
VD>                "Ожидается описание состояния в формате: state StateName { transitions }"); 
VD>          }
        
VD>        | _ =>
VD>          Message.Error(stateDef.Location, 
VD>            "Ожидается описание состояния в формате: state StateName { transitions }"); 
VD>      }
      
VD>      match (body)
VD>      {
VD>         // описания состояний заключены в группу (фигурные скобки)
VD>        | <[ { ..$states } ]> => // матчим список выражений описывающих состояния
VD>          foreach (state in states) 
VD>            makeSate(state);
            
VD>        | _ => 
VD>          Message.Error(body.Location, 
VD>            "Ожидается список состоянии в формате { state1 state2 ... }"); 
VD>      }
VD>    }
VD>  }
VD>}
VD>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.