Парсер lisp на lisp

Узнай цену своей работы

Формулировка задачи:

Здравствуйте! Решил написать компилятор racket (диалект lisp) на racket, для того, чтобы легко можно было проверить его полноценность (компилирует сам себя - все хорошо, нет - нужно пилить дальше). До этого писал компилятор для маленького lisp на с++, так что (примерно) представляю, что нужно делать. Это первая большая программа на lisp, так что пока тяжело. Например: вот такую простую функцию:
Листинг программы
  1. function ast(tokens, from, to)
  2. {
  3. if(from == undefined)
  4. from = 0;
  5. if(to == undefined)
  6. to = tokens.length
  7. var ret = [];
  8. for(var i=from; i<to; i++)
  9. {
  10. if(tokens[i] == "(")
  11. {
  12. var level = 1;
  13. var start = i;
  14. while(level!=0)
  15. {
  16. i++;
  17. if(tokens[i] == "(")
  18. level++;
  19. if(tokens[i] == ")")
  20. level--;
  21. }
  22. ret.push(ast(tokens, start+1, i));
  23. }
  24. else
  25. ret.push(tokens[i])
  26. }
  27. return ret;
  28. }
Я попытался написать вот так (код страшный и нерабочий):
Листинг программы
  1. (define (parse tokens from to)
  2. (cond
  3. [(>= from to) '#()]
  4. [(not (and (vector-has tokens "(") (vector-has tokens ")"))) tokens]
  5. [else (let* [(fb (vector-index tokens "("))
  6. (lb (end tokens 1 (+ fb 1)))]
  7. (println (string-append "fb = " (number->string fb)))
  8. (println (string-append "lb = " (number->string lb)))
  9. (cond
  10. [(and (= fb 0) (= lb (- (vector-length tokens) 1))) (parse tokens (+ fb 1) (- lb 1))]
  11. [(= fb 0) (vector-append (parse tokens (+ fb 1) lb) (parse tokens (+ lb 1) (- (vector-length tokens) 1)))]
  12. [(= lb (- (vector-length tokens) 1)) (vector-append (parse tokens 0 (- fb 1)) (parse tokens (+ fb 1) (- (vector-length tokens) 1)))]
  13. [else (vector-append (parse tokens 0 (- fb 1)) (parse tokens (+ fb 1) (- lb 1)) (parse tokens (+ lb 1) (- (vector-length tokens) 1)))]
  14. )
  15. )]) )
Помогите, пожалуйста, переписать.

Решение задачи: «Парсер lisp на lisp»

textual
Листинг программы
  1. (define (delimiter? ch)
  2.   (or (equal? ch #\()
  3.       (equal? ch #\))
  4.       (char-whitespace? ch)))
  5.  
  6. (define (match-token src)
  7.   (let loop ((src src) (acc null))
  8.     (if (delimiter? (first src))
  9.         (values (list->string (reverse acc)) (rest src))
  10.         (loop (rest src) (cons (first src) acc)))))
  11.  
  12. (define (match-list src)
  13.   (cond ((and (list? src) (null? src)) src)
  14.         ((equal? (first src) #\()
  15.          (let ((src (rest src)))
  16.            (cond ((null? src) src)
  17.                  ((equal? (first src) #\)) null)
  18.                  (else (let-values (((token rest) (match-token src)))
  19.                          (cons token (match-list rest)))))))
  20.         ((equal? (first src) #\)) null)
  21.         (else (let-values (((token rest) (match-token src)))
  22.                          (cons token (match-list rest))))))
  23.  
  24. (match-list (string->list "(defun foo nil)"))
  25. '("defun" "foo" "nil")

Объяснение кода листинга программы

  1. delimiter? - это функция, которая проверяет, является ли символ ch разделителем. Она возвращает true, если символ является (, ) или пробелом, и false в противном случае.
  2. match-token - это функция, которая пытается сопоставить токен с помощью разделителя. Если следующий символ является разделителем, функция возвращает пару, состоящую из сопоставленного токена и оставшейся строки. Если это не так, функция вызывает себя рекурсивно для оставшейся строки и добавляет текущий символ к результату.
  3. match-list - это функция, которая пытается сопоставить список с помощью разделителя. Если входной список пуст, функция возвращает его. Если первый символ в списке является (, функция вызывает себя рекурсивно для оставшейся части списка и добавляет ( как первый элемент результата. Если первый символ является ), функция возвращает nil. В противном случае функция вызывает себя рекурсивно для оставшейся части списка и добавляет первый символ как первый элемент результата.
  4. (match-list (string->list(defun foo nil))) - это вызов функции match-list с входным списком, полученным из строки (defun foo nil). Функция возвращает список, содержащий defun, foo, nil.
  5. Результат вызова match-list (string->list(defun foo nil)) - это список, содержащий defun, foo, nil.

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

9   голосов , оценка 3.778 из 5

Нужна аналогичная работа?

Оформи быстрый заказ и узнай стоимость

Бесплатно
Оформите заказ и авторы начнут откликаться уже через 10 минут