From: patzy
Subject: Need advices about state machine definition macro
Date: 
Message-ID: <1187098630.452313.206380@r34g2000hsd.googlegroups.com>
Hi, I'm playing with macros trying to create one for defining state
machines. Starting from Dave Robert's macro available here:
http://www.findinglisp.com/blog/2004/06/state-machines.html
http://www.findinglisp.com/blog/archives/2004_06_01_archive.html

I wrote my own macro like this:

(defmacro define-state-machine (name initial-state &rest states)
  (let ((current-state (gensym)))
    `(let ((,current-state ,initial-state))
       (defun ,name (&optional (action 'nil) (new-current-state 'nil))
	 (case action
	   ('get-initial-state ,initial-state)
	   ('get-current-state ,current-state)
	   ('set-current-state (setf ,current-state new-current-state))
	   (otherwise (case ,current-state
			,@(loop for (state-name . state-body) in states
				collecting
				(case (car state-body)
				  ('with-vars
				   ;;We got local state variables
				   (let ((state-vars (cadr state-body))
					 (state-transitions (cddr state-body)))
				     `(,state-name (let (,@state-vars)
						     (cond ,@(mapcar (lambda (a-transition)
									  (let ((transition-next (car a-transition))
										(transition-test (cadr a-transition))
										(transition-action (caddr a-transition)))
									    `((progn ,@transition-test)
									      (progn (setf ,current-state ,transition-next)
										     ,@transition-action))))
									state-transitions))))))

				  ('with-action
				   ;;We got state action
				   (let ((state-action (cadr state-body))
					 (state-transitions (cddr state-body)))
				     `(,state-name (progn ,@state-action
						     (cond ,@(mapcar (lambda (a-transition)
									  (let ((transition-next (car a-transition))
										(transition-test (cadr a-transition))
										(transition-action (caddr a-transition)))
									    `((progn ,@transition-test)
									      (progn (setf ,current-state ,transition-next)
										     ,@transition-action))))
									state-transitions))))))
				  (otherwise
				    ;;No state variables or body
				    (let ((state-transitions state-body))
				      `(,state-name
 					(cond ,@(mapcar (lambda (a-transition)
								      (let ((transition-next (car a-transition))
									    (transition-test (cadr a-transition))
									    (transition-action (caddr a-transition)))
									`((progn ,@transition-test)
									  (progn (setf ,current-state ,transition-next)
										 ,@transition-action))))
								    state-transitions))))))))))))))

This allow me to define state machines like this:

(define-state-machine test-fsm
  'state-1;initial state
  ;;All states
  ('state-1 ;the state
   ;;its local vars
   with-vars ((test (random 2)))
   ;;all its transitions
   ('state-2;transition next
    ((equal 0 test));transition test
    ((format t "Test: ~S~%" test)
     (format t "Entering state 2 from state 1~%")));transition action
   ('state-3;transition next
    ((equal 1 test));transition test
    ((format t "Test: ~S~%" test)
     (format t "Entering state 3 from state 1~%"))));transition action

  ('state-2 ;the state
   ;;state action
   with-action ((let ((some-var 'some-value))
		 (format t "In state 2 action:~S~%" some-var)))
   ;;all its transitions
   ('state-1;transition next
    ('t);transition test
    ((format t "Entering state 1 from state 2~%"))));transition action

  ('state-3 ;the state
   ;;all its transitions
   ('state-1;transition next
    ('t);transition test
    ((format t "Entering state 1 from state 3~%")))));transition
action

It works quite well, but I'm not satisfied with the macro definition,
there are redundant blocks of code and I'm sure about the
'keywords' (e.g. with-vars and with-action) handling.

Can you people tell me what you think about this, the code is
certainly not the best but I'm posting here to improve it and learn
more about macros.

PS: I tried some macrolet and stuff like this to avoid code redundancy
but I can get it to work...

From: Pascal Bourguignon
Subject: Re: Need advices about state machine definition macro
Date: 
Message-ID: <87fy2m8c0z.fsf@thalassa.informatimago.com>
patzy <·············@gmail.com> writes:

> Hi, I'm playing with macros trying to create one for defining state
> machines. Starting from Dave Robert's macro available here:
> http://www.findinglisp.com/blog/2004/06/state-machines.html
> http://www.findinglisp.com/blog/archives/2004_06_01_archive.html
>
> I wrote my own macro like this:
>
> (defmacro define-state-machine (name initial-state &rest states)
> [...more than a screenfull...]
> 								    state-transitions))))))))))))))
>
> This allow me to define state machines like this:
>
> (define-state-machine test-fsm
>   'state-1;initial state
>   ;;All states
>   ('state-1 ;the state

Can you write:

(let ((states '(initial middle final)))
  (define-state-machine test-fsm
      (pop states)
     ((pop states) ...)
     ((pop states) ...)))

If not, then you have too many quotes in your macro syntax...


> It works quite well, but I'm not satisfied with the macro definition,
> there are redundant blocks of code and I'm sure about the
> 'keywords' (e.g. with-vars and with-action) handling.
>
> Can you people tell me what you think about this, the code is
> certainly not the best but I'm posting here to improve it and learn
> more about macros.
>
> PS: I tried some macrolet and stuff like this to avoid code redundancy
> but I can get it to work...

Macros are functions like any other.  You have the right to define and
call your own functions from your macros.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.
From: patzy
Subject: Re: Need advices about state machine definition macro
Date: 
Message-ID: <1187103320.212562.153050@g4g2000hsf.googlegroups.com>
On Aug 14, 3:46 pm, Pascal Bourguignon <····@informatimago.com> wrote:
> patzy <·············@gmail.com> writes:
> > Hi, I'm playing with macros trying to create one for defining state
> > machines. Starting from Dave Robert's macro available here:
> >http://www.findinglisp.com/blog/2004/06/state-machines.html
> >http://www.findinglisp.com/blog/archives/2004_06_01_archive.html
>
> > I wrote my own macro like this:
>
> > (defmacro define-state-machine (name initial-state &rest states)
> > [...more than a screenfull...]
> >                                                                state-transitions))))))))))))))
>
> > This allow me to define state machines like this:
>
> > (define-state-machine test-fsm
> >   'state-1;initial state
> >   ;;All states
> >   ('state-1 ;the state
>
> Can you write:
>
> (let ((states '(initial middle final)))
>   (define-state-machine test-fsm
>       (pop states)
>      ((pop states) ...)
>      ((pop states) ...)))
>
> If not, then you have too many quotes in your macro syntax...
>
> > It works quite well, but I'm not satisfied with the macro definition,
> > there are redundant blocks of code and I'm sure about the
> > 'keywords' (e.g. with-vars and with-action) handling.
>
> > Can you people tell me what you think about this, the code is
> > certainly not the best but I'm posting here to improve it and learn
> > more about macros.
>
> > PS: I tried some macrolet and stuff like this to avoid code redundancy
> > but I can get it to work...
>
> Macros are functions like any other.  You have the right to define and
> call your own functions from your macros.
>
> --
> __Pascal Bourguignon__                    http://www.informatimago.com/
>
> NOTE: The most fundamental particles in this product are held
> together by a "gluing" force about which little is currently known
> and whose adhesive power can therefore not be permanently
> guaranteed.
Thanks for you remark, looks like it doesn't work with your "(pop
states)...", I just made some tests but I can't get it working.
When saying "too many quotes..." do you refer to all my nested
backquote stuff? Can you give me a simple example explaining why it
doesn't work?
From: Pascal Bourguignon
Subject: Re: Need advices about state machine definition macro
Date: 
Message-ID: <871we683hq.fsf@thalassa.informatimago.com>
patzy <·············@gmail.com> writes:

> On Aug 14, 3:46 pm, Pascal Bourguignon <····@informatimago.com> wrote:
>> patzy <·············@gmail.com> writes:
>> > (define-state-machine test-fsm
>> >   'state-1;initial state
>> >   ;;All states
>> >   ('state-1 ;the state
>>
>> Can you write:
>>
>> (let ((states '(initial middle final)))
>>   (define-state-machine test-fsm
>>       (pop states)
>>      ((pop states) ...)
>>      ((pop states) ...)))
>>
>> If not, then you have too many quotes in your macro syntax...
>
> Thanks for you remark, looks like it doesn't work with your "(pop
> states)...", I just made some tests but I can't get it working.
> When saying "too many quotes..." do you refer to all my nested
> backquote stuff? Can you give me a simple example explaining why it
> doesn't work?

I mean that the arguments to a macro are NOT evaluated therefore you
don't need to quote them.  In fact, you mustn't quote them.  Unless
your macro evaluates them correctly at run-time, which it doesn't
since (pop states) doesn't work.

So at the very least, you should be able to write:

(define-state-machine test-fsm
  state-1
  (state-1 
   with-vars ((test (random 2)))
   (state-2
    ((equal 0 test))
    ((format t "Test: ~S~%" test)
     (format t "Entering state 2 from state 1~%")))
   (state-3
    ((equal 1 test))
    ((format t "Test: ~S~%" test)
     (format t "Entering state 3 from state 1~%"))))
  (state-2 
   with-action ((let ((some-var some-value))
		 (format t "In state 2 action:~S~%" some-var)))
   (state-1
    (t)
    ((format t "Entering state 1 from state 2~%"))))
  (state-3 
   (state-1
    (t)
    ((format t "Entering state 1 from state 3~%")))))

But even better, follow Rainer's advice and use keywords.



C/USER[36]> (defmacro m (arg)
              (format t "At macro expansion time, ARG = ~S, of type ~S~%" arg (type-of arg))
              (let ((val (gensym)))
                `(let ((,val ,arg))
                   (format t "At run time, ~S --> ~S~%" ',arg ,val)
                   ,val)))
M
C/USER[37]> (let ((a 42))  (m 'a))
At macro expansion time, ARG = 'A, of type CONS
At run time, 'A --> A
A
C/USER[38]> (let ((a 42))  (m a))
At macro expansion time, ARG = A, of type SYMBOL
At run time, A --> 42
42
C/USER[39]> 



-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.
From: patzy
Subject: Re: Need advices about state machine definition macro
Date: 
Message-ID: <1187114661.137584.201410@q75g2000hsh.googlegroups.com>
On Aug 14, 6:50 pm, Pascal Bourguignon <····@informatimago.com> wrote:
> patzy <·············@gmail.com> writes:
> > On Aug 14, 3:46 pm, Pascal Bourguignon <····@informatimago.com> wrote:
> >> patzy <·············@gmail.com> writes:
> >> > (define-state-machine test-fsm
> >> >   'state-1;initial state
> >> >   ;;All states
> >> >   ('state-1 ;the state
>
> >> Can you write:
>
> >> (let ((states '(initial middle final)))
> >>   (define-state-machine test-fsm
> >>       (pop states)
> >>      ((pop states) ...)
> >>      ((pop states) ...)))
>
> >> If not, then you have too many quotes in your macro syntax...
>
> > Thanks for you remark, looks like it doesn't work with your "(pop
> > states)...", I just made some tests but I can't get it working.
> > When saying "too many quotes..." do you refer to all my nested
> > backquote stuff? Can you give me a simple example explaining why it
> > doesn't work?
>
> I mean that the arguments to a macro are NOT evaluated therefore you
> don't need to quote them.  In fact, you mustn't quote them.  Unless
> your macro evaluates them correctly at run-time, which it doesn't
> since (pop states) doesn't work.
>
> So at the very least, you should be able to write:
>
> (define-state-machine test-fsm
>   state-1
>   (state-1
>    with-vars ((test (random 2)))
>    (state-2
>     ((equal 0 test))
>     ((format t "Test: ~S~%" test)
>      (format t "Entering state 2 from state 1~%")))
>    (state-3
>     ((equal 1 test))
>     ((format t "Test: ~S~%" test)
>      (format t "Entering state 3 from state 1~%"))))
>   (state-2
>    with-action ((let ((some-var some-value))
>                  (format t "In state 2 action:~S~%" some-var)))
>    (state-1
>     (t)
>     ((format t "Entering state 1 from state 2~%"))))
>   (state-3
>    (state-1
>     (t)
>     ((format t "Entering state 1 from state 3~%")))))
>
> But even better, follow Rainer's advice and use keywords.
>
> C/USER[36]> (defmacro m (arg)
>               (format t "At macro expansion time, ARG = ~S, of type ~S~%" arg (type-of arg))
>               (let ((val (gensym)))
>                 `(let ((,val ,arg))
>                    (format t "At run time, ~S --> ~S~%" ',arg ,val)
>                    ,val)))
> M
> C/USER[37]> (let ((a 42))  (m 'a))
> At macro expansion time, ARG = 'A, of type CONS
> At run time, 'A --> A
> A
> C/USER[38]> (let ((a 42))  (m a))
> At macro expansion time, ARG = A, of type SYMBOL
> At run time, A --> 42
> 42
> C/USER[39]>
>
> --
> __Pascal Bourguignon__                    http://www.informatimago.com/
>
> NOTE: The most fundamental particles in this product are held
> together by a "gluing" force about which little is currently known
> and whose adhesive power can therefore not be permanently
> guaranteed.

I removed all the quotes in my state machine definition, now I'm
trying to make it work with the (pop states) stuff. But all I got is
an expansion containing "(pop states)" instead of the actual popped
value.
I have test but I think I found the problem: I need to evaluate the
state name outside of the case keys list, since in 'case'
documentation it says that keys is a list of key and is probably not
evaluated explaining why (pop states) still there...

As for the keywords, it looks like a better solution than the one I'm
using ATM, and it's probably clearer when defining a state machine.

Thanks for your remarks and example, I'll post more when I'll find a
solution to the (pop...) problem.
From: Pascal Bourguignon
Subject: Re: Need advices about state machine definition macro
Date: 
Message-ID: <87vebh6cyv.fsf@thalassa.informatimago.com>
patzy <·············@gmail.com> writes:

> On Aug 14, 6:50 pm, Pascal Bourguignon <····@informatimago.com> wrote:
>> patzy <·············@gmail.com> writes:
>> > On Aug 14, 3:46 pm, Pascal Bourguignon <····@informatimago.com> wrote:
>> >> patzy <·············@gmail.com> writes:
>> >> > (define-state-machine test-fsm
>> >> >   'state-1;initial state
>> >> >   ;;All states
>> >> >   ('state-1 ;the state
>>
>> >> Can you write:
>>
>> >> (let ((states '(initial middle final)))
>> >>   (define-state-machine test-fsm
>> >>       (pop states)
>> >>      ((pop states) ...)
>> >>      ((pop states) ...)))
>>
>> >> If not, then you have too many quotes in your macro syntax...
>>
>> > Thanks for you remark, looks like it doesn't work with your "(pop
>> > states)...", I just made some tests but I can't get it working.
>> > When saying "too many quotes..." do you refer to all my nested
>> > backquote stuff? Can you give me a simple example explaining why it
>> > doesn't work?
>>
>> I mean that the arguments to a macro are NOT evaluated therefore you
>> don't need to quote them.  In fact, you mustn't quote them.  Unless
>> your macro evaluates them correctly at run-time, which it doesn't
>> since (pop states) doesn't work.
>>
>> So at the very least, you should be able to write:
>>
>> (define-state-machine test-fsm
>>   state-1
>>   (state-1
>>    with-vars ((test (random 2)))
>>    (state-2
>>     ((equal 0 test))
>>     ((format t "Test: ~S~%" test)
>>      (format t "Entering state 2 from state 1~%")))
>>    (state-3
>>     ((equal 1 test))
>>     ((format t "Test: ~S~%" test)
>>      (format t "Entering state 3 from state 1~%"))))
>>   (state-2
>>    with-action ((let ((some-var some-value))
>>                  (format t "In state 2 action:~S~%" some-var)))
>>    (state-1
>>     (t)
>>     ((format t "Entering state 1 from state 2~%"))))
>>   (state-3
>>    (state-1
>>     (t)
>>     ((format t "Entering state 1 from state 3~%")))))
>>
>> But even better, follow Rainer's advice and use keywords.
>>
>> C/USER[36]> (defmacro m (arg)
>>               (format t "At macro expansion time, ARG = ~S, of type ~S~%" arg (type-of arg))
>>               (let ((val (gensym)))
>>                 `(let ((,val ,arg))
>>                    (format t "At run time, ~S --> ~S~%" ',arg ,val)
>>                    ,val)))
>> M
>> C/USER[37]> (let ((a 42))  (m 'a))
>> At macro expansion time, ARG = 'A, of type CONS
>> At run time, 'A --> A
>> A
>> C/USER[38]> (let ((a 42))  (m a))
>> At macro expansion time, ARG = A, of type SYMBOL
>> At run time, A --> 42
>> 42
>> C/USER[39]>
>>
>> --
>> __Pascal Bourguignon__                    http://www.informatimago.com/
>>
>> NOTE: The most fundamental particles in this product are held
>> together by a "gluing" force about which little is currently known
>> and whose adhesive power can therefore not be permanently
>> guaranteed.
>
> I removed all the quotes in my state machine definition, now I'm
> trying to make it work with the (pop states) stuff. But all I got is
> an expansion containing "(pop states)" instead of the actual popped
> value.
> I have test but I think I found the problem: I need to evaluate the
> state name outside of the case keys list, since in 'case'
> documentation it says that keys is a list of key and is probably not
> evaluated explaining why (pop states) still there...
>
> As for the keywords, it looks like a better solution than the one I'm
> using ATM, and it's probably clearer when defining a state machine.
>
> Thanks for your remarks and example, I'll post more when I'll find a
> solution to the (pop...) problem.

Read very closely the specifications for CASE.

Consider:

(case 'quote
  ((quote setq catch) 'special-operator)
  ((sin cos car cdr)  'function)
  ((dolist dotimes)   'macro)
  (otherwise          'unknown))


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.
From: patzy
Subject: Re: Need advices about state machine definition macro
Date: 
Message-ID: <1187178130.097902.16780@b79g2000hse.googlegroups.com>
On Aug 14, 11:08 pm, Pascal Bourguignon <····@informatimago.com>
wrote:
> patzy <·············@gmail.com> writes:
> > On Aug 14, 6:50 pm, Pascal Bourguignon <····@informatimago.com> wrote:
> >> patzy <·············@gmail.com> writes:
> >> > On Aug 14, 3:46 pm, Pascal Bourguignon <····@informatimago.com> wrote:
> >> >> patzy <·············@gmail.com> writes:
> >> >> > (define-state-machine test-fsm
> >> >> >   'state-1;initial state
> >> >> >   ;;All states
> >> >> >   ('state-1 ;the state
>
> >> >> Can you write:
>
> >> >> (let ((states '(initial middle final)))
> >> >>   (define-state-machine test-fsm
> >> >>       (pop states)
> >> >>      ((pop states) ...)
> >> >>      ((pop states) ...)))
>
> >> >> If not, then you have too many quotes in your macro syntax...
>
> >> > Thanks for you remark, looks like it doesn't work with your "(pop
> >> > states)...", I just made some tests but I can't get it working.
> >> > When saying "too many quotes..." do you refer to all my nested
> >> > backquote stuff? Can you give me a simple example explaining why it
> >> > doesn't work?
>
> >> I mean that the arguments to a macro are NOT evaluated therefore you
> >> don't need to quote them.  In fact, you mustn't quote them.  Unless
> >> your macro evaluates them correctly at run-time, which it doesn't
> >> since (pop states) doesn't work.
>
> >> So at the very least, you should be able to write:
>
> >> (define-state-machine test-fsm
> >>   state-1
> >>   (state-1
> >>    with-vars ((test (random 2)))
> >>    (state-2
> >>     ((equal 0 test))
> >>     ((format t "Test: ~S~%" test)
> >>      (format t "Entering state 2 from state 1~%")))
> >>    (state-3
> >>     ((equal 1 test))
> >>     ((format t "Test: ~S~%" test)
> >>      (format t "Entering state 3 from state 1~%"))))
> >>   (state-2
> >>    with-action ((let ((some-var some-value))
> >>                  (format t "In state 2 action:~S~%" some-var)))
> >>    (state-1
> >>     (t)
> >>     ((format t "Entering state 1 from state 2~%"))))
> >>   (state-3
> >>    (state-1
> >>     (t)
> >>     ((format t "Entering state 1 from state 3~%")))))
>
> >> But even better, follow Rainer's advice and use keywords.
>
> >> C/USER[36]> (defmacro m (arg)
> >>               (format t "At macro expansion time, ARG = ~S, of type ~S~%" arg (type-of arg))
> >>               (let ((val (gensym)))
> >>                 `(let ((,val ,arg))
> >>                    (format t "At run time, ~S --> ~S~%" ',arg ,val)
> >>                    ,val)))
> >> M
> >> C/USER[37]> (let ((a 42))  (m 'a))
> >> At macro expansion time, ARG = 'A, of type CONS
> >> At run time, 'A --> A
> >> A
> >> C/USER[38]> (let ((a 42))  (m a))
> >> At macro expansion time, ARG = A, of type SYMBOL
> >> At run time, A --> 42
> >> 42
> >> C/USER[39]>
>
> >> --
> >> __Pascal Bourguignon__                    http://www.informatimago.com/
>
> >> NOTE: The most fundamental particles in this product are held
> >> together by a "gluing" force about which little is currently known
> >> and whose adhesive power can therefore not be permanently
> >> guaranteed.
>
> > I removed all the quotes in my state machine definition, now I'm
> > trying to make it work with the (pop states) stuff. But all I got is
> > an expansion containing "(pop states)" instead of the actual popped
> > value.
> > I have test but I think I found the problem: I need to evaluate the
> > state name outside of the case keys list, since in 'case'
> > documentation it says that keys is a list of key and is probably not
> > evaluated explaining why (pop states) still there...
>
> > As for the keywords, it looks like a better solution than the one I'm
> > using ATM, and it's probably clearer when defining a state machine.
>
> > Thanks for your remarks and example, I'll post more when I'll find a
> > solution to the (pop...) problem.
>
> Read very closely the specifications for CASE.
>
> Consider:
>
> (case 'quote
>   ((quote setq catch) 'special-operator)
>   ((sin cos car cdr)  'function)
>   ((dolist dotimes)   'macro)
>   (otherwise          'unknown))
>
> --
> __Pascal Bourguignon__                    http://www.informatimago.com/
>
> NOTE: The most fundamental particles in this product are held
> together by a "gluing" force about which little is currently known
> and whose adhesive power can therefore not be permanently
> guaranteed.

Reading the case specifications and some macros example/tutorials, I
modified my macro. Now it works with "(pop states)" (well, only for
the state name, not for transitions but I think I finally understood
why it was wrong).

Here is the new macro:


(defmacro define-state-machine ((name init-state) &rest states)
  (let ((current-state (gensym))
	(initial-state (gensym))
	(state-names (loop repeat (length states) collect (gensym))))
    (format t "Init state: ~S~%" initial-state)
    (format t "Current state: ~S~%" current-state)
    (format t "State names: ~S~%" state-names)
    `(let* ((,current-state ,init-state)
	    (,initial-state ,current-state)
	    ,@(loop for n in state-names for s in states
		    collect `(,n ,(car s))))
       (defun ,name (&optional (action 'nil) (new-current-state 'nil))
	 (case action
	  (get-initial-state ,initial-state)
	  (get-current-state ,current-state)
	  (set-current-state (setf ,current-state new-current-state))
	  (otherwise (cond
		       ,@(loop for (nil . state-body) in states
			       for state-name in state-names
			       collecting
			       (case (car state-body)
				 (with-vars
				      ;;We got local state variables
				  (let ((state-vars (cadr state-body))
					(state-transitions (cddr state-body)))
				    `((equal ,state-name ,current-state)
				      (let (,@state-vars)
					(cond ,@(mapcar (lambda (a-transition)
							  (let ((transition-next (car a-transition))
								(transition-test (cadr a-transition))
								(transition-action (caddr a-transition)))
							    `((progn ,@transition-test)
							      (progn (setf ,current-state (quote ,transition-next))
								     ,@transition-action))))
							state-transitions))))))

				 (with-action
				  ;;We got state action
				  (let ((state-action (cadr state-body))
					(state-transitions (cddr state-body)))
				    `((equal ,state-name ,current-state)
				      (progn ,@state-action
					     (cond ,@(mapcar (lambda (a-transition)
							       (let ((transition-next (car a-transition))
								     (transition-test (cadr a-transition))
								     (transition-action (caddr a-transition)))
								 `((progn ,@transition-test)
								   (progn (setf ,current-state (quote ,transition-next))
									  ,@transition-action))))
							     state-transitions))))))
				 (otherwise
				  ;;No state variables or body
				  (let ((state-transitions state-body))
				    `((equal ,state-name ,current-state)
				      (cond ,@(mapcar (lambda (a-transition)
							(let ((transition-next (car a-transition))
							      (transition-test (cadr a-transition))
							      (transition-action (caddr a-transition)))
							  `((progn ,@transition-test)
							    (progn (setf ,current-state (quote ,transition-next))
								   ,@transition-action))))
						      state-transitions)))))))
		       (t (error (format nil "FSM in an unknown state: ~S" ,current-
state))))))))))


Now, state names are evaluated at the beginning of the macro and I'm
using a list of gensyms (after reading about the once-only macro). I
also replaced case with a cond so the matching test is evaluated at
runtime and I can test the value of the current-state gensym with the
state names gensyms. I am now able to write stuff like this:


(let* ((state-list '(initial  middle final)))
  (format t "Expansion:~S~%" (macroexpand-1 '(define-state-machine
(test-fsm2 (pop state-list))
					       ((pop state-list)
						('t)
						((format t "Initial~%")))
					       ((pop state-list)
						('t)
						((format t "Middle~%")))
					       ((pop state-list)
						('t)
						((format t "Final~%"))))))
  (define-state-machine (test-fsm2 'initial)
    ((pop state-list)
     with-action ((format t "Initial state action~%"))
     (middle
      ('t)
      ((format t "Initial~%"))))
    ((pop state-list)
     with-action ((format t "Middle state action~%"))
     (final
      ('t)
      ((format t "Middle~%"))))
    ((pop state-list)
     with-action ((format t "Final state action~%"))
     (initial
      ('t)
      ((format t "Final~%"))))))
(format t "~S~%" (test-fsm2 'get-initial-state))
(format t "FSM: ~S~%" #'test-fsm2)
(test-fsm2)
(test-fsm2)
(test-fsm2)
(test-fsm2)
(test-fsm2)

Now, I'll try to move some of the code to some helper function to
improve readability and then try too understand how keywords works.

Thanks for your remarks and examples.
From: Pascal Bourguignon
Subject: Re: Need advices about state machine definition macro
Date: 
Message-ID: <87tzr04wrr.fsf@thalassa.informatimago.com>
patzy <·············@gmail.com> writes:
>> Read very closely the specifications for CASE.
>>
>> Consider:
>>
>> (case 'quote
>>   ((quote setq catch) 'special-operator)
>>   ((sin cos car cdr)  'function)
>>   ((dolist dotimes)   'macro)
>>   (otherwise          'unknown))

Have you tried this form?  
What did you get?  
Why?

> Reading the case specifications and some macros example/tutorials, I
> modified my macro. Now it works with "(pop states)" (well, only for
> the state name, not for transitions but I think I finally understood
> why it was wrong).
>
> Here is the new macro:
>
> (defmacro define-state-machine ((name init-state) &rest states)
>   (let ((current-state (gensym))
> 	(initial-state (gensym))
> 	(state-names (loop repeat (length states) collect (gensym))))
>     (format t "Init state: ~S~%" initial-state)
>     (format t "Current state: ~S~%" current-state)
>     (format t "State names: ~S~%" state-names)
>     `(let* ((,current-state ,init-state)
> 	    (,initial-state ,current-state)
> 	    ,@(loop for n in state-names for s in states
> 		    collect `(,n ,(car s))))
>        (defun ,name (&optional (action 'nil) (new-current-state 'nil))
> 	 (case action
> 	  (get-initial-state ,initial-state)

Looks wrong.

This CASE will test if (EQ ACTION 'GET-INITIAL-STATE), and if so, will
execute the one form obtained from INITIAL-STATE.



The point is that CASE clauses take as first element a "designator for
a list of objects".  When we want a designator for a list, and we have
an atom, we assume we have a list containing only this atom.

(case state
  (get-initial-state ,initial-state)
  ...)

is understood as:

(case state
  ((get-initial-state) ,initial-state)
  ...)



The keys (the objects in the list designated) are not evaluated.  When
you write:

(case state
  ('initial  (print 'beginning))
  ...)

It is of course:

(case state
  ((quote initial)  (print 'beginning))
  ...)

and it tests whether action is QUOTE or INITIAL.  Seems to work, but
if one of the state is QUOTE, you probably won't get the right action.



Of course, since the keys are not evaluated, you cannot use an
expression like (POP STATES) as key in a CASE.  When you have
expressions, you must use something else, like a COND.  You must also
be careful with side effects.


Note that I wasn't saying that you should accept expressions for the
list of states.  I was saying that since you took expressions such as
'INITIAL, then it ought to work with any expression, but it didn't,
which shows that it shouldn't take expressions.

Taking an expression for the list of states at run-time means that the
state machine is not known at macroexpansion time, therefore you don't
need a macro, you can just write a function to execute the state
machine at run-time.

When you know your state machines at macroexpansion time (compilation
time, in the source), then you can write a macro to compile it into
lisp at macroexpansion time.  But then the data of the state machine
is literal, you don't need to quote it because it hasn't to be
evaluated.





-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.
From: patzy
Subject: Re: Need advices about state machine definition macro
Date: 
Message-ID: <1187248279.479779.9460@r34g2000hsd.googlegroups.com>
On Aug 15, 5:56 pm, Pascal Bourguignon <····@informatimago.com> wrote:

> Looks wrong.
>
> This CASE will test if (EQ ACTION 'GET-INITIAL-STATE), and if so, will
> execute the one form obtained from INITIAL-STATE.
>
> The point is that CASE clauses take as first element a "designator for
> a list of objects".  When we want a designator for a list, and we have
> an atom, we assume we have a list containing only this atom.
>
> (case state
>   (get-initial-state ,initial-state)
>   ...)
>
> is understood as:
>
> (case state
>   ((get-initial-state) ,initial-state)
>   ...)
>
> The keys (the objects in the list designated) are not evaluated.  When
> you write:
>
> (case state
>   ('initial  (print 'beginning))
>   ...)
>
> It is of course:
>
> (case state
>   ((quote initial)  (print 'beginning))
>   ...)
>
> and it tests whether action is QUOTE or INITIAL.  Seems to work, but
> if one of the state is QUOTE, you probably won't get the right action.
>
> Of course, since the keys are not evaluated, you cannot use an
> expression like (POP STATES) as key in a CASE.  When you have
> expressions, you must use something else, like a COND.  You must also
> be careful with side effects.
>
> Note that I wasn't saying that you should accept expressions for the
> list of states.  I was saying that since you took expressions such as
> 'INITIAL, then it ought to work with any expression, but it didn't,
> which shows that it shouldn't take expressions.
>
> Taking an expression for the list of states at run-time means that the
> state machine is not known at macroexpansion time, therefore you don't
> need a macro, you can just write a function to execute the state
> machine at run-time.
>
> When you know your state machines at macroexpansion time (compilation
> time, in the source), then you can write a macro to compile it into
> lisp at macroexpansion time.  But then the data of the state machine
> is literal, you don't need to quote it because it hasn't to be
> evaluated.
>
> --
> __Pascal Bourguignon__                    http://www.informatimago.com/
>
> NOTE: The most fundamental particles in this product are held
> together by a "gluing" force about which little is currently known
> and whose adhesive power can therefore not be permanently
> guaranteed.

Thank you, for this precise explanation, I just understood the list
designator idea in case.
As you pointed out, if the state machine is only known at runtime then
I don't need a macro to express it and just have to write some
function to run it from some representation. The idea here was to
understand why it didn't work with expressions and how to change this
(Then I guess I was too focused on this problem to think about
anything else...).

My main problem is too see the differences between macroexpansion-time
and runtime, I'm still reading about this and macros...

I think I got a similar problem, mixing macroexpansion time with
runtime in my head while writing for example:

(defmacro test-m (&key a-key)
  (if (listp a-key)
    (format t "This is a list~%")
    (format t "This is not a list~%"))
  `(format t "~S~%" ,a-key))

Testing with :

(test-m :a-key 'tst)

prints "This is a list" cause inside the macro a-key is seen as (quote
tst).

Anyway thanks again for your time and advices and I'm going to read
about this and write some tests to try to understand how it works. But
I guess the idea is just that only source code is known at macro
expansion time...

PS: Sorry for the previous double post, just some refresh with mozilla
that send my message a second time.
From: Pascal Bourguignon
Subject: Re: Need advices about state machine definition macro
Date: 
Message-ID: <87ir7f3478.fsf@thalassa.informatimago.com>
patzy <·············@gmail.com> writes:
> My main problem is too see the differences between macroexpansion-time
> and runtime, I'm still reading about this and macros...

--------(file.lisp)-------------
(eval-when (:compile-toplevel)
  (format t "Compilation time~%"))
(eval-when (:load-toplevel)
  (format t "Load time~%"))
(eval-when (:execute)
  (format t "Run time (top-level)~%"))

(defmacro m ()
  (format t "Macroexpansion time~%")
  '(format t "Run time (macro)~%"))

(defun f ()
  (m))
---------------------------------

Try this file in various implementations.  In clisp we get:


C/USER[128]> (load "/tmp/file.lisp")
;; Loading file /tmp/file.lisp ...
Run time (top-level)
Macroexpansion time
;; Loaded file /tmp/file.lisp
T
C/USER[129]> (f)
Run time (macro)
NIL
C/USER[130]> (compile-file "/tmp/file.lisp")
;; Compiling file /tmp/file.lisp ...
Compilation time
Macroexpansion time
;; Wrote file /tmp/file.fas
0 errors, 0 warnings
#P"/tmp/file.fas" ;
NIL ;
NIL
C/USER[131]> (load "/tmp/file.fas")
;; Loading file /tmp/file.fas ...
Load time
;; Loaded file /tmp/file.fas
T
C/USER[132]> (f)
Run time (macro)
NIL
C/USER[133]> (defun g ()  (m))
Macroexpansion time
G
C/USER[134]> (g)
Run time (macro)
NIL


> I think I got a similar problem, mixing macroexpansion time with
> runtime in my head while writing for example:
>
> (defmacro test-m (&key a-key)
>   (if (listp a-key)
>     (format t "This is a list~%")
>     (format t "This is not a list~%"))
>   `(format t "~S~%" ,a-key))
>
> Testing with :
>
> (test-m :a-key 'tst)
>
> prints "This is a list" cause inside the macro a-key is seen as (quote
> tst).

You must remember that the arguments to a macro are not evaluated.


C/USER[150]> (defmacro m (a)
               (format t "A  = ~S~%" a) ; macroexpansion time    
               `(format t ",A = ~S~%" ,a)) ; run time
M
C/USER[151]> (defun f (x)
               (m 1)
               (m x)
               (m (sin 42))
               (m '(sin 42)))
A  = 1
A  = X
A  = (SIN 42)
A  = '(SIN 42)
F
C/USER[152]> (f 3)
,A = 1
,A = 3
,A = -0.91652155
,A = (SIN 42)
NIL
C/USER[153]> 


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.
From: patzy
Subject: Re: Need advices about state machine definition macro
Date: 
Message-ID: <1187280766.687760.207330@r34g2000hsd.googlegroups.com>
On Aug 16, 5:10 pm, Pascal Bourguignon <····@informatimago.com> wrote:
> patzy <·············@gmail.com> writes:
> > My main problem is too see the differences between macroexpansion-time
> > and runtime, I'm still reading about this and macros...
>
> --------(file.lisp)-------------
> (eval-when (:compile-toplevel)
>   (format t "Compilation time~%"))
> (eval-when (:load-toplevel)
>   (format t "Load time~%"))
> (eval-when (:execute)
>   (format t "Run time (top-level)~%"))
>
> (defmacro m ()
>   (format t "Macroexpansion time~%")
>   '(format t "Run time (macro)~%"))
>
> (defun f ()
>   (m))
> ---------------------------------
>
> Try this file in various implementations.  In clisp we get:
>
> C/USER[128]> (load "/tmp/file.lisp")
> ;; Loading file /tmp/file.lisp ...
> Run time (top-level)
> Macroexpansion time
> ;; Loaded file /tmp/file.lisp
> T
> C/USER[129]> (f)
> Run time (macro)
> NIL
> C/USER[130]> (compile-file "/tmp/file.lisp")
> ;; Compiling file /tmp/file.lisp ...
> Compilation time
> Macroexpansion time
> ;; Wrote file /tmp/file.fas
> 0 errors, 0 warnings
> #P"/tmp/file.fas" ;
> NIL ;
> NIL
> C/USER[131]> (load "/tmp/file.fas")
> ;; Loading file /tmp/file.fas ...
> Load time
> ;; Loaded file /tmp/file.fas
> T
> C/USER[132]> (f)
> Run time (macro)
> NIL
> C/USER[133]> (defun g ()  (m))
> Macroexpansion time
> G
> C/USER[134]> (g)
> Run time (macro)
> NIL
>
> > I think I got a similar problem, mixing macroexpansion time with
> > runtime in my head while writing for example:
>
> > (defmacro test-m (&key a-key)
> >   (if (listp a-key)
> >     (format t "This is a list~%")
> >     (format t "This is not a list~%"))
> >   `(format t "~S~%" ,a-key))
>
> > Testing with :
>
> > (test-m :a-key 'tst)
>
> > prints "This is a list" cause inside the macro a-key is seen as (quote
> > tst).
>
> You must remember that the arguments to a macro are not evaluated.
>
> C/USER[150]> (defmacro m (a)
>                (format t "A  = ~S~%" a) ; macroexpansion time
>                `(format t ",A = ~S~%" ,a)) ; run time
> M
> C/USER[151]> (defun f (x)
>                (m 1)
>                (m x)
>                (m (sin 42))
>                (m '(sin 42)))
> A  = 1
> A  = X
> A  = (SIN 42)
> A  = '(SIN 42)
> F
> C/USER[152]> (f 3)
> ,A = 1
> ,A = 3
> ,A = -0.91652155
> ,A = (SIN 42)
> NIL
> C/USER[153]>
>
> --
> __Pascal Bourguignon__                    http://www.informatimago.com/
>
> NOTE: The most fundamental particles in this product are held
> together by a "gluing" force about which little is currently known
> and whose adhesive power can therefore not be permanently
> guaranteed.

Your file.lisp example makes the difference between macro expansion
and runtime as well as load time clear.

I probably need more practice with macros and to put this into my
head: Macro parameters are not evaluated !!! I think I was confused by
the ' syntax in my previous example believing a quoted symbol is
itself which is true but only when evaluated (and it doesn't happen
with macro parameters).

Thanks again for you time, and clarifications.
From: Rainer Joswig
Subject: Re: Need advices about state machine definition macro
Date: 
Message-ID: <joswig-20FDAA.18294616082007@news-europe.giganews.com>
In article <························@r34g2000hsd.googlegroups.com>,
 patzy <·············@gmail.com> wrote:

> I probably need more practice with macros and to put this into my
> head: Macro parameters are not evaluated !!!

That depends entirely on the expansion.

(defun list-me (a b) (list a b))

(defmacro eval-or-not? (x y)
  (list 'list-me x (list 'quote y)))

or similar with backquote

(defmacro eval-or-not? (x y)
  `(list-me ,x ',y))


? (macroexpand '(eval-or-not? (sin 0.5) (sin 0.5)))

(LIST-ME (SIN 0.5) '(SIN 0.5))

So, if you write

(let ((a 1.5) (b 2.3)) 
  (eval-or-not? a b))

The macro will be expanded and the code looks like:

(let ((a 1.5) (b 2.3)) 
  (list-me a 'b))

Note that a is evaluated and b not.


> I think I was confused by
> the ' syntax in my previous example believing a quoted symbol is
> itself which is true but only when evaluated (and it doesn't happen
> with macro parameters).

Use keywords. Keyword symbols evaluate to themselve and
they don't pollute the current package with a possibly
new symbol.

> 
> Thanks again for you time, and clarifications.

-- 
http://lispm.dyndns.org
From: Pascal Bourguignon
Subject: Re: Need advices about state machine definition macro
Date: 
Message-ID: <87zm0r1lqg.fsf@thalassa.informatimago.com>
Rainer Joswig <······@lisp.de> writes:

> In article <························@r34g2000hsd.googlegroups.com>,
>  patzy <·············@gmail.com> wrote:
>
>> I probably need more practice with macros and to put this into my
>> head: Macro parameters are not evaluated !!!
>
> That depends entirely on the expansion.

Which means that it's the macro _result_ that gets evaluated.  

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.
From: patzy
Subject: Re: Need advices about state machine definition macro
Date: 
Message-ID: <1187180284.581545.237070@r29g2000hsg.googlegroups.com>
On Aug 14, 11:08 pm, Pascal Bourguignon <····@informatimago.com>
wrote:
> patzy <·············@gmail.com> writes:
> > On Aug 14, 6:50 pm, Pascal Bourguignon <····@informatimago.com> wrote:
> >> patzy <·············@gmail.com> writes:
> >> > On Aug 14, 3:46 pm, Pascal Bourguignon <····@informatimago.com> wrote:
> >> >> patzy <·············@gmail.com> writes:
> >> >> > (define-state-machine test-fsm
> >> >> >   'state-1;initial state
> >> >> >   ;;All states
> >> >> >   ('state-1 ;the state
>
> >> >> Can you write:
>
> >> >> (let ((states '(initial middle final)))
> >> >>   (define-state-machine test-fsm
> >> >>       (pop states)
> >> >>      ((pop states) ...)
> >> >>      ((pop states) ...)))
>
> >> >> If not, then you have too many quotes in your macro syntax...
>
> >> > Thanks for you remark, looks like it doesn't work with your "(pop
> >> > states)...", I just made some tests but I can't get it working.
> >> > When saying "too many quotes..." do you refer to all my nested
> >> > backquote stuff? Can you give me a simple example explaining why it
> >> > doesn't work?
>
> >> I mean that the arguments to a macro are NOT evaluated therefore you
> >> don't need to quote them.  In fact, you mustn't quote them.  Unless
> >> your macro evaluates them correctly at run-time, which it doesn't
> >> since (pop states) doesn't work.
>
> >> So at the very least, you should be able to write:
>
> >> (define-state-machine test-fsm
> >>   state-1
> >>   (state-1
> >>    with-vars ((test (random 2)))
> >>    (state-2
> >>     ((equal 0 test))
> >>     ((format t "Test: ~S~%" test)
> >>      (format t "Entering state 2 from state 1~%")))
> >>    (state-3
> >>     ((equal 1 test))
> >>     ((format t "Test: ~S~%" test)
> >>      (format t "Entering state 3 from state 1~%"))))
> >>   (state-2
> >>    with-action ((let ((some-var some-value))
> >>                  (format t "In state 2 action:~S~%" some-var)))
> >>    (state-1
> >>     (t)
> >>     ((format t "Entering state 1 from state 2~%"))))
> >>   (state-3
> >>    (state-1
> >>     (t)
> >>     ((format t "Entering state 1 from state 3~%")))))
>
> >> But even better, follow Rainer's advice and use keywords.
>
> >> C/USER[36]> (defmacro m (arg)
> >>               (format t "At macro expansion time, ARG = ~S, of type ~S~%" arg (type-of arg))
> >>               (let ((val (gensym)))
> >>                 `(let ((,val ,arg))
> >>                    (format t "At run time, ~S --> ~S~%" ',arg ,val)
> >>                    ,val)))
> >> M
> >> C/USER[37]> (let ((a 42))  (m 'a))
> >> At macro expansion time, ARG = 'A, of type CONS
> >> At run time, 'A --> A
> >> A
> >> C/USER[38]> (let ((a 42))  (m a))
> >> At macro expansion time, ARG = A, of type SYMBOL
> >> At run time, A --> 42
> >> 42
> >> C/USER[39]>
>
> >> --
> >> __Pascal Bourguignon__                    http://www.informatimago.com/
>
> >> NOTE: The most fundamental particles in this product are held
> >> together by a "gluing" force about which little is currently known
> >> and whose adhesive power can therefore not be permanently
> >> guaranteed.
>
> > I removed all the quotes in my state machine definition, now I'm
> > trying to make it work with the (pop states) stuff. But all I got is
> > an expansion containing "(pop states)" instead of the actual popped
> > value.
> > I have test but I think I found the problem: I need to evaluate the
> > state name outside of the case keys list, since in 'case'
> > documentation it says that keys is a list of key and is probably not
> > evaluated explaining why (pop states) still there...
>
> > As for the keywords, it looks like a better solution than the one I'm
> > using ATM, and it's probably clearer when defining a state machine.
>
> > Thanks for your remarks and example, I'll post more when I'll find a
> > solution to the (pop...) problem.
>
> Read very closely the specifications for CASE.
>
> Consider:
>
> (case 'quote
>   ((quote setq catch) 'special-operator)
>   ((sin cos car cdr)  'function)
>   ((dolist dotimes)   'macro)
>   (otherwise          'unknown))
>
> --
> __Pascal Bourguignon__                    http://www.informatimago.com/
>
> NOTE: The most fundamental particles in this product are held
> together by a "gluing" force about which little is currently known
> and whose adhesive power can therefore not be permanently
> guaranteed.

Reading the case specifications and some macros example/tutorials, I
modified my macro. Now it works with "(pop states)" (well, only for
the state name, not for transitions but I think I finally understood
why it was wrong).

Here is the new macro:


(defmacro define-state-machine ((name init-state) &rest states)
  (let ((current-state (gensym))
	(initial-state (gensym))
	(state-names (loop repeat (length states) collect (gensym))))
    (format t "Init state: ~S~%" initial-state)
    (format t "Current state: ~S~%" current-state)
    (format t "State names: ~S~%" state-names)
    `(let* ((,current-state ,init-state)
	    (,initial-state ,current-state)
	    ,@(loop for n in state-names for s in states
		    collect `(,n ,(car s))))
       (defun ,name (&optional (action 'nil) (new-current-state 'nil))
	 (case action
	  (get-initial-state ,initial-state)
	  (get-current-state ,current-state)
	  (set-current-state (setf ,current-state new-current-state))
	  (otherwise (cond
		       ,@(loop for (nil . state-body) in states
			       for state-name in state-names
			       collecting
			       (case (car state-body)
				 (with-vars
				      ;;We got local state variables
				  (let ((state-vars (cadr state-body))
					(state-transitions (cddr state-body)))
				    `((equal ,state-name ,current-state)
				      (let (,@state-vars)
					(cond ,@(mapcar (lambda (a-transition)
							  (let ((transition-next (car a-transition))
								(transition-test (cadr a-transition))
								(transition-action (caddr a-transition)))
							    `((progn ,@transition-test)
							      (progn (setf ,current-state (quote ,transition-next))
								     ,@transition-action))))
							state-transitions))))))

				 (with-action
				  ;;We got state action
				  (let ((state-action (cadr state-body))
					(state-transitions (cddr state-body)))
				    `((equal ,state-name ,current-state)
				      (progn ,@state-action
					     (cond ,@(mapcar (lambda (a-transition)
							       (let ((transition-next (car a-transition))
								     (transition-test (cadr a-transition))
								     (transition-action (caddr a-transition)))
								 `((progn ,@transition-test)
								   (progn (setf ,current-state (quote ,transition-next))
									  ,@transition-action))))
							     state-transitions))))))
				 (otherwise
				  ;;No state variables or body
				  (let ((state-transitions state-body))
				    `((equal ,state-name ,current-state)
				      (cond ,@(mapcar (lambda (a-transition)
							(let ((transition-next (car a-transition))
							      (transition-test (cadr a-transition))
							      (transition-action (caddr a-transition)))
							  `((progn ,@transition-test)
							    (progn (setf ,current-state (quote ,transition-next))
								   ,@transition-action))))
						      state-transitions)))))))
		       (t (error (format nil "FSM in an unknown state: ~S" ,current-
state))))))))))


Now, state names are evaluated at the beginning of the macro and I'm
using a list of gensyms (after reading about the once-only macro). I
also replaced case with a cond so the matching test is evaluated at
runtime and I can test the value of the current-state gensym with the
state names gensyms. I am now able to write stuff like this:


(let* ((state-list '(initial  middle final)))
  (format t "Expansion:~S~%" (macroexpand-1 '(define-state-machine
(test-fsm2 (pop state-list))
					       ((pop state-list)
						('t)
						((format t "Initial~%")))
					       ((pop state-list)
						('t)
						((format t "Middle~%")))
					       ((pop state-list)
						('t)
						((format t "Final~%"))))))
  (define-state-machine (test-fsm2 'initial)
    ((pop state-list)
     with-action ((format t "Initial state action~%"))
     (middle
      ('t)
      ((format t "Initial~%"))))
    ((pop state-list)
     with-action ((format t "Middle state action~%"))
     (final
      ('t)
      ((format t "Middle~%"))))
    ((pop state-list)
     with-action ((format t "Final state action~%"))
     (initial
      ('t)
      ((format t "Final~%"))))))
(format t "~S~%" (test-fsm2 'get-initial-state))
(format t "FSM: ~S~%" #'test-fsm2)
(test-fsm2)
(test-fsm2)
(test-fsm2)
(test-fsm2)
(test-fsm2)

Now, I'll try to move some of the code to some helper function to
improve readability and then try too understand how keywords works.

Thanks for your remarks and examples.
From: Rainer Joswig
Subject: Re: Need advices about state machine definition macro
Date: 
Message-ID: <joswig-072366.16045214082007@news-europe.giganews.com>
In article <························@r34g2000hsd.googlegroups.com>,
 patzy <·············@gmail.com> wrote:

Use functions to generate the code.

> This allow me to define state machines like this:
> 
> (define-state-machine test-fsm
>   'state-1;initial state
>   ;;All states
>   ('state-1 ;the state
>    ;;its local vars
>    with-vars ((test (random 2)))
>    ;;all its transitions
>    ('state-2;transition next
>     ((equal 0 test));transition test
>     ((format t "Test: ~S~%" test)
>      (format t "Entering state 2 from state 1~%")));transition action
>    ('state-3;transition next
>     ((equal 1 test));transition test
>     ((format t "Test: ~S~%" test)
>      (format t "Entering state 3 from state 1~%"))));transition action
> 
>   ('state-2 ;the state
>    ;;state action
>    with-action ((let ((some-var 'some-value))
> 		 (format t "In state 2 action:~S~%" some-var)))
>    ;;all its transitions
>    ('state-1;transition next
>     ('t);transition test
>     ((format t "Entering state 1 from state 2~%"))));transition action
> 
>   ('state-3 ;the state
>    ;;all its transitions
>    ('state-1;transition next
>     ('t);transition test
>     ((format t "Entering state 1 from state 3~%")))));transition
> action


Get rid of all the comments and make the code self-documenting:

(define-state-machine (test-fsm :initial-state state-1)
 (:state state-1
  :vars ((test (random 2)))
  :transitions ((:next-state state-2
                 :test (equal 0 test)
                 :do ((format t "Test: ~S~%" test)
                      (format t "Entering state 2 from state 1~%")))
                (:next-state state-3
                 :test (equal 1 test)
                 :do ((format t "Test: ~S~%" test)
                      (format t "Entering state 3 from state 1~%")))))

 (:state state-2
  :action ((let ((some-var 'some-value))
             (format t "In state 2 action:~S~%" some-var)))
  :transitions ((:next-state state-1
                 :test t
                 :do ((format t "Entering state 1 from state 2~%")))))
 (:state state-3
  :transitions ((:next-state state-1
                 :test t
                 :do ((format t "Entering state 1 from state 3~%"))))))
From: patzy
Subject: Re: Need advices about state machine definition macro
Date: 
Message-ID: <1187103446.602439.30240@k79g2000hse.googlegroups.com>
On Aug 14, 4:04 pm, Rainer Joswig <······@lisp.de> wrote:
> In article <························@r34g2000hsd.googlegroups.com>,
>
>  patzy <·············@gmail.com> wrote:
>
> Use functions to generate the code.
>
>
>
> > This allow me to define state machines like this:
>
> > (define-state-machine test-fsm
> >   'state-1;initial state
> >   ;;All states
> >   ('state-1 ;the state
> >    ;;its local vars
> >    with-vars ((test (random 2)))
> >    ;;all its transitions
> >    ('state-2;transition next
> >     ((equal 0 test));transition test
> >     ((format t "Test: ~S~%" test)
> >      (format t "Entering state 2 from state 1~%")));transition action
> >    ('state-3;transition next
> >     ((equal 1 test));transition test
> >     ((format t "Test: ~S~%" test)
> >      (format t "Entering state 3 from state 1~%"))));transition action
>
> >   ('state-2 ;the state
> >    ;;state action
> >    with-action ((let ((some-var 'some-value))
> >             (format t "In state 2 action:~S~%" some-var)))
> >    ;;all its transitions
> >    ('state-1;transition next
> >     ('t);transition test
> >     ((format t "Entering state 1 from state 2~%"))));transition action
>
> >   ('state-3 ;the state
> >    ;;all its transitions
> >    ('state-1;transition next
> >     ('t);transition test
> >     ((format t "Entering state 1 from state 3~%")))));transition
> > action
>
> Get rid of all the comments and make the code self-documenting:
>
> (define-state-machine (test-fsm :initial-state state-1)
>  (:state state-1
>   :vars ((test (random 2)))
>   :transitions ((:next-state state-2
>                  :test (equal 0 test)
>                  :do ((format t "Test: ~S~%" test)
>                       (format t "Entering state 2 from state 1~%")))
>                 (:next-state state-3
>                  :test (equal 1 test)
>                  :do ((format t "Test: ~S~%" test)
>                       (format t "Entering state 3 from state 1~%")))))
>
>  (:state state-2
>   :action ((let ((some-var 'some-value))
>              (format t "In state 2 action:~S~%" some-var)))
>   :transitions ((:next-state state-1
>                  :test t
>                  :do ((format t "Entering state 1 from state 2~%")))))
>  (:state state-3
>   :transitions ((:next-state state-1
>                  :test t
>                  :do ((format t "Entering state 1 from state 3~%"))))))

Thanks, seems to be a good idea and it could make my keywords (with-
action etc...) management easier. Anyway is there any good examples of
macros defining keywords like the one I used (as in the loop macro
which is a bit too complicated for me ATM)?