Существует ли Awk- или Lisp-подобный язык программирования, который может обрабатывать поток s-выражений?

Это часто не приводит к правильному пути к местоположению. Важно понимать, что путь начинается с текущего пакета, в котором находится код, а не от корня проекта. До тех пор, пока вы получите правильный относительный путь, вы должны быть в состоянии избежать этой ошибки в этом случае.

5
задан Caleb Reister 17 January 2019 в 06:38
поделиться

2 ответа

Простой скрипт

Вот пример в Common Lisp, предполагая, что ваш ввод находится в файле "/tmp/ex.cad" (его также можно получить, прочитав поток вывода процесса).

Основной цикл обработки состоит в открытии файла для получения входного потока in (который автоматически закрывается в конце with-open-file), циклического перебора всех форм в файле, их обработки и, возможно, вывода их на стандартный вывод. Вы можете усложнить процесс сколько угодно, но достаточно хорошо следующее:

(with-open-file (in #"/tmp/ex.cad")
  (let ((*read-eval* nil))
     (ignore-errors
       (loop (process-form (read in))))))

Предположим, вы хотите увеличить ширину fp_line записей, игнорировать fp_text и в противном случае распечатать форму без изменений. Вы можете определить process-form следующим образом:

(defun process-form (form)
  (destructuring-bind (header . args) form
    (print
     (case header
       (fp_line (let ((width (assoc 'width args)))
                  (when width (incf (second width) 3)))
                form)
       (fp_text (return-from process-form))
       (t form)))))

Выполнение предыдущего цикла выдаст:

(FP_LINE (START -27.04996 -3.986) (END -27.24996 -3.786) (LAYER F.FAB) (WIDTH 3.1)) 
(PAD "" NP_THRU_HOLE CIRCLE (AT 35.56 0) (SIZE 3.175 3.175) (DRILL 3.175) (LAYERS *.CU *.MASK) (CLEARANCE 1.5875)) 
(PAD 96 SMD RECT (AT 1.25 3.08473) (SIZE 0.29972 1.45034) (LAYERS F.CU F.PASTE F.MASK) (CLEARANCE 0.09906)) 

Больше безопасности

Оттуда вы можете построить более сложные конвейеры, с помощью сопоставления с образцом или макросов, если хотите. Вы должны принять во внимание некоторые меры безопасности, такие как привязка *read-eval* к nil, использование with-standard-io-syntax и привязка *print-circte* к T, как предложено в tfb , запрещение полностью определенных символов (имея #\: сигнализировать об ошибке) и т. д. В конечном счете, как и в случае однострочных сценариев оболочки Shell, количество мер предосторожности, которые вы добавляете, зависит от того, насколько вы доверяете своим данным:

;; Load libraries
(ql:quickload '(:alexandria :optima))

;; Import symbols in current package
(use-package :optima)
(use-package :alexandria)

;; Transform source into a stream
(defgeneric ensure-stream (source)
  (:method ((source pathname)) (open source))
  (:method ((source string)) (make-string-input-stream source))
  (:method ((source stream)) source))

;; make reader stop on illegal characters    
(defun abort-reader (&rest values)
  (error "Aborting reader: ~s" values))

Специальный пакет для символов KiCad (экспорт необязателен). ):

(defpackage :kicad
  (:use)
  (:export #:fp_text
           #:fp_line
           #:pad
           #:size))

Циклические формы:

(defmacro do-forms ((form source &optional result) &body body)
  "Loop over forms from source, eventually return result"
  (with-gensyms (in form%)
    `(with-open-stream (,in (ensure-stream ,source))
       (with-standard-io-syntax
         (let ((*read-eval* nil)
               (*print-circle* t)
               (*package* (find-package :kicad))
               (*readtable* (copy-readtable)))
           (set-macro-character #\: #'abort-reader nil)
           (loop
              :for ,form% := (read ,in nil ,in)
              :until (eq ,form% ,in)
              :do (let ((,form ,form%)) ,@body)
              :finally (return ,result)))))))

Пример:

;; Print lines at which there is a size parameter, and its value
(let ((line 0))
  (labels ((size (alist) (second (assoc 'kicad:size alist)))
           (emit (size) (when size (print `(:line ,line :size ,size))))
           (process (options) (emit (size options))))
    (do-forms (form #P"/tmp/ex.cad")
      (match form
        ((list* 'kicad:fp_text _ _ options) (process options))
        ((list* 'kicad:fp_line options) (process options))
        ((list* 'kicad:pad _ _ _ options) (process options)))
      (incf line))))

Выход

(:LINE 2 :SIZE 3.175) 
(:LINE 3 :SIZE 0.29972)
0
ответ дан coredump 17 January 2019 в 06:38
поделиться

Просто напишите простой скрипт на Лиспе или Схеме, который зацикливается на чтении и рекурсивно обрабатывает ваш s-expr по мере необходимости. В Linux я бы рекомендовал использовать Guile (хороший интерпретатор Scheme) или, возможно, Clisp (простая реализация Common Lisp) или даже SBCL (очень мощный Common Lisp ).

(Вы можете рассмотреть DSSSL , но в вашем случае это излишне)

Обратите внимание, что ваш пример ввода не S-выражение [ 117], потому что (layer F.Fab) не одно (поскольку после точки у вас должно быть другое s-выражение, а не атом, как Fab). Я думаю, что это опечатка и должно быть (layer "F.Fab"); или, может быть, ваше программное обеспечение KiCad не обрабатывает S-выражения, но какой-то другой язык ввода (который должен быть указан, вероятно, в нотации EBNF ) вдохновлен S-выражениями.

Также обратите внимание, что KiCad является свободным программным обеспечением и имеет сообщество с форумами и списком рассылки. Возможно, вам стоит спросить о вашей настоящей проблеме?

PS. Мы не знаем, какую трансформацию вы имеете в виду, но Scheme и Common Lisp действительно подходят для таких задач. В большинстве случаев они чрезвычайно просты для кодирования (возможно, всего несколько строк).

0
ответ дан Basile Starynkevitch 17 January 2019 в 06:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: