1
votes

I have an assignment where I need to write a script using lisp. I am having issues with passing variables

Here is the code. Issues to follow:

(defmacro while (test &rest bodies)
   `(do ()
        ((not ,test))
        ,@ bodies)
) 
(defmacro += (var inc)
    `(print (eval var))
    ;(setf (eval var) (+ (eval var) inc))
)

(defmacro iterate (i begin end inc &rest others)
    (setf i begin)
    
    (while (<= i (eval end))
        ;(dolist (item others)
        ;    (eval item)
        ;)
       
        (print (list 'two i (eval end)))
        (+= (eval end) 1)
        (setf i (+ i inc))
    )
)

(setf n 5)
(iterate i 1 n 1
    (print (list 'one i))
    (+= n 1)
)

The first issue lies in passing the statements to the iterate macro. When I try to run the commented out dolist, the print statement will throw an error when it comes to the variable i. For some reason I can not get it to print using the macro variable i which has a value, but it seems to want to default to the global variable i which has not been set. I get the error:

- EVAL: variable I has no value

The second issue is when I call the "+=" macro. The value of end in the iterate macro is 5 as passed to the macro by use of the variable N which it is set to 5, however, when I pass it to the "+=" macro using the line "(+= (eval end) 1)" I can not get it to pass the value. I tried removing the eval in the line "(+= (eval end) 1)" and when I try printing it with "(print (eval var))" in the "+=" macro, I get the error - EVAL: variable END has no value

How would I solve these issues?

1
your ITERATE macro is wrong. It should generate code, but it doesn't. Then there will also be no reason to use EVAL. - Rainer Joswig
A good rule of thumb is: 'if you are using eval you are making a mistake'. There are cases where eval is justified, but they are not common, at all. - user5920214

1 Answers

2
votes

Your first macro is basically correct. It generates code.

(defmacro while (test &body body)
  `(do ()
       ((not ,test))
     ,@body))

One can check it with an example. We expand the macro using example code. The function MACROEXPAND-1 expands the top-level macro exactly once. You need to pass code to the function MACROEXPAND-1:

CL-USER 1 > (macroexpand-1 '(while (< i 10)
                              (print i)
                              (incf i)))
(DO NIL               ; NIL is the same as ()
    ((NOT (< I 10)))
  (PRINT I)
  (INCF I))
T
 

The generated code is a DO loop. Just like intended.

Thus we can use your macro:

CL-USER 2 > (let ((i 5))
              (while (< i 10)
                (print i)
                (incf i)))

5 
6 
7 
8 
9 
NIL

Your other macros should be like that

  • they should generate code
  • macro expansion of examples should show the right generated code
  • the generated code should work

Your macros should NOT

  • be using EVAL
  • try to compute results other than code