Burcu Sultan Orhan
Burcu Sultan Orhan

Reputation: 13

Filling an array with inputs from a file in Common Lisp

I'm trying to get data from a file to an array char by char in lisp, but I'm very new to common lisp so I got lost on the way. Here's what I've tried so far and got lots of errors:

(defun gppinterpreter (filename)

  (defvar *count* 0)
  (setf my-array (make-array '(10)))
  (with-open-file (stream filename)
    (do ((char (read-char stream nil)
               (read-char stream nil)))
        ((null char))
      (setf (aref my-array *count*) char)
      (set *count* (+ *count* 1))))
  (print my-array)
)

Upvotes: 0

Views: 231

Answers (1)

Svante
Svante

Reputation: 51501

That's not a bad start. Let's take a look at the errors one by one.

When you do a defvar, it defines a global variable (to be more precise, with global lexical scope, dynamic extent). When you do that inside of a function body, this happens each time the function is run. This is not what you want. You want a variable that has only local lexical scope. Use let for that:

(defun gppinterpreter (filename)
  (let ((count 0))                        ; <-
    (setf my-array (make-array '(10)))
    (with-open-file (stream filename)
      (do ((char (read-char stream nil)
                 (read-char stream nil)))
          ((null char))
        (setf (aref my-array count) char)
        (set count (+ count 1))))
    (print my-array)))

When you setf a variable that doesn't exist, it gets created in the global lexical scope, but some of its behaviour is not specified. Don't do that. You want a local variable again. Use the let:

(defun gppinterpreter (filename)
  (let ((count 0)
        (my-array (make-array '(10))))     ; <-
    (with-open-file (stream filename)
      (do ((char (read-char stream nil)
                 (read-char stream nil)))
          ((null char))
        (setf (aref my-array count) char)
        (set count (+ count 1))))
    (print my-array)))

Set is not setf. I'll leave the specifics aside for now; set is almost never what you want. You could use setf there, but there is a convenient shorthand for incrementing a place, incf:

(defun gppinterpreter (filename)
  (let ((count 0)
        (my-array (make-array '(10))))
    (with-open-file (stream filename)
      (do ((char (read-char stream nil)
                 (read-char stream nil)))
          ((null char))
        (setf (aref my-array count) char)
        (incf count)))                     ; <-
    (print my-array)))

This version at least runs without errors and produces a char vector. You might replace the loop with a single call to read-sequence, and instead of printing, you most likely want to just return the new vector:

(defun gppinterpreter (filename)
  (let ((my-array (make-array '(10))))
    (with-open-file (stream filename)
      (read-sequence my-array stream))   ; <-
    my-array))                           ; <-

The next steps depend on what structure your file actually has. You might want to get a string instead of a general vector. You might want to read a line of text, with read-line.

Upvotes: 1

Related Questions