config-parser.lisp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. ;;;; config-parser.lisp
  2. #+quicklisp (ql:quickload :parse-number)
  3. (defpackage #:config-parser
  4. (:use :esrap
  5. :cl)
  6. (:import-from #:parse-number
  7. #:parse-number)
  8. (:export open-configuration-file
  9. write-configuration-file))
  10. (in-package #:config-parser)
  11. ;;; "config-parser" goes here. Hacks and glory await!
  12. (defrule space
  13. (+ (or #\Space #\Tab #\Newline))
  14. (:constant nil))
  15. (defrule identifier
  16. (* (or (alphanumericp character) "_" "-" "."))
  17. (:text t)
  18. (:lambda (identifier)
  19. (intern (string-upcase identifier) "KEYWORD")))
  20. (defun not-doublequote (character)
  21. (not (eql #\" character)))
  22. (defrule string-chars
  23. (or (not-doublequote character)
  24. (and #\\ #\")))
  25. (defrule string
  26. (and #\" (* string-chars) #\")
  27. (:destructure (sq string eq)
  28. (declare (ignore sq eq))
  29. (text string)))
  30. (defrule number
  31. (and (? (or "-" "+"))
  32. (+ (or "0" "1" "2" "3" "4" "5" "6" "7" "8" "9"))
  33. (? (and "."
  34. (+ (or "0" "1" "2" "3" "4" "5" "6" "7" "8" "9"))))
  35. (? (and (or "e" "E")
  36. (? "-")
  37. (+ (or "0" "1" "2" "3" "4" "5" "6" "7" "8" "9")))))
  38. (:text t)
  39. (:lambda (num-string)
  40. (parse-number num-string)))
  41. (defrule block-title
  42. (and (? #\Newline) "[" (? space) identifier (? space) "]" (? #\Newline))
  43. (:destructure (nl1 lb sp1 ident sp2 rb nl)
  44. (declare (ignore nl1 lb sp1 sp2 rb nl))
  45. ident))
  46. (defrule ident-path
  47. (and identifier (? space) "/" (? space) identifier)
  48. (:destructure (identa sp1 sep sp2 identb)
  49. (declare (ignore sp1 sep sp2))
  50. (list identa identb)))
  51. (defrule variable-expression
  52. (and identifier (? space) "=" (? space) (or string number ident-path) (? #\Newline))
  53. (:destructure (identifier sp1 eq sp2 value nl)
  54. (declare (ignore sp1 eq sp2 nl))
  55. (list identifier value)))
  56. (defrule block-contents
  57. (* variable-expression)
  58. (:lambda (expressions)
  59. (loop for expression in expressions
  60. append expression)))
  61. (defrule block
  62. (and block-title block-contents)
  63. (:destructure (title contents)
  64. (list title contents)))
  65. (defrule file
  66. (* block)
  67. (:lambda (blocks)
  68. (loop for block in blocks
  69. append block)))
  70. (defun open-configuration-file (filename)
  71. (parse 'file
  72. (concatenate 'string
  73. (with-open-file (input-file filename)
  74. (loop for char = (read-char input-file nil 'foo)
  75. until (eq char 'foo)
  76. collect char)))))
  77. (defun write-identifier (identifier alist stream)
  78. (format stream "~a" (getf alist identifier)))
  79. (defun write-string-out (string stream)
  80. (format stream "\"~a\"" string))
  81. (defun write-block-title (identifier alist stream)
  82. (format stream "~%[")
  83. (write-identifier identifier alist stream)
  84. (format stream "]~&"))
  85. (defun write-path (id1 id2 alist stream)
  86. (write-identifier id1 alist stream)
  87. (format stream "/")
  88. (write-identifier id2 alist stream))
  89. (defun write-expression (lhs rhs alist stream)
  90. (format stream "~&")
  91. (write-identifier lhs alist stream)
  92. (format stream " = ")
  93. (if (typep rhs 'string)
  94. (write-string-out rhs stream)
  95. (if (typep rhs 'list)
  96. (write-path (car rhs) (cadr rhs) alist stream)
  97. (format stream "~a" rhs)))
  98. (format stream "~&"))
  99. (defun write-correct (stream alist toplevel-p config-list)
  100. (if toplevel-p
  101. (if (listp (car config-list))
  102. (write-correct stream alist nil (cdr config-list))
  103. (write-block-title (car config) alist stream))
  104. (loop for (lhs rhs) in config-list
  105. do (write-expression lhs rhs alist config-list))))
  106. (defun write-configuration-file (filename config key-to-text-alist)
  107. (with-open-file (output-file filename :direction :output :if-exists :overwrite :if-does-not-exist :create)
  108. (write-correct output-file key-to-text-alist t config)))