export.scm 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. ;;; nyacc/export.scm
  2. ;; Copyright (C) 2015,2017-2018 Matthew R. Wette
  3. ;;
  4. ;; This library is free software; you can redistribute it and/or
  5. ;; modify it under the terms of the GNU Lesser General Public
  6. ;; License as published by the Free Software Foundation; either
  7. ;; version 3 of the License, or (at your option) any later version.
  8. ;;
  9. ;; This library is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. ;; Lesser General Public License for more details.
  13. ;;
  14. ;; You should have received a copy of the licence with this software.
  15. ;; If not, see <http://www.gnu.org/licenses/>.
  16. ;;; Code:
  17. (define-module (nyacc export)
  18. #:export (lalr->bison
  19. lalr->guile
  20. c-char token->bison elt->bison
  21. )
  22. #:use-module ((nyacc lalr) #:select (find-terminal pp-rule lalr-start))
  23. #:use-module (nyacc lex)
  24. #:use-module (nyacc util)
  25. #:use-module ((srfi srfi-1) #:select (fold))
  26. #:use-module ((srfi srfi-43) #:select (vector-for-each))
  27. #:use-module (ice-9 regex)
  28. )
  29. ;; The code below, for exporting to guile and bison, should be moved to
  30. ;; an "export" module.
  31. ;; terminal:
  32. ;; ident-like-string -> caps
  33. ;; non-ident-like-string -> ChSeq_#_# ...
  34. ;; symbol -> if $, use _, otherwise ???
  35. ;; breakdown:
  36. ;; 1 terminal, or non-terminal:
  37. ;; 2 if non-terminal,
  38. ;; replace - with _, replace $ with _
  39. ;; 3 if terminal, (output of @code{find-terminal})
  40. ;; if symbol, use 2
  41. ;; replace char with (c-char .)
  42. ;; if length-1 string replace with (c-char .)
  43. ;; if like-c-ident string, replace with CAPS
  44. ;; otherwise use ChSeq
  45. (define re/g regexp-substitute/global)
  46. (define (chseq->name cs)
  47. (let* ((iseq (string-fold (lambda (c s) (cons* (char->integer c) s)) '() cs))
  48. (tail (string-join (map number->string iseq) "_"))
  49. (name (string-append "ChSeq_" tail)))
  50. name))
  51. ;; Convert char to string that works inside single quotes for C.
  52. (define (c-char ch)
  53. (case ch
  54. ((#\') "'\\''")
  55. ((#\\) "'\\\\'")
  56. ((#\newline) "'\\n'")
  57. ((#\tab) "'\\t'")
  58. ((#\return) "\\r")
  59. (else (string #\' ch #\'))))
  60. (define (token->bison tok)
  61. (cond
  62. ((eqv? tok '$error) "error")
  63. ((symbol? tok) (symbol->bison tok))
  64. ((char? tok) (c-char tok))
  65. ((string? tok)
  66. (cond
  67. ((like-c-ident? tok) (string-upcase tok))
  68. ((= 1 (string-length tok)) (c-char (string-ref tok 0)))
  69. (else (chseq->name tok))))
  70. (else (error "what?"))))
  71. (define (symbol->bison symb)
  72. (let* ((str0 (symbol->string symb))
  73. (str1 (re/g #f "-" str0 'pre "_" 'post))
  74. (str2 (re/g #f "\\$" str1 'pre "_" 'post)))
  75. str2))
  76. (define (elt->bison symb terms)
  77. (let ((term (find-terminal symb terms)))
  78. (if term
  79. (token->bison term)
  80. (symbol->bison symb))))
  81. ;; @deffn lalr->bison spec => to current output port
  82. ;; needs cleanup: tokens working better but p-rules need fix.
  83. (define (lalr->bison spec . rest)
  84. (define (setup-assc assc)
  85. (fold (lambda (al seed)
  86. (append (x-flip al) seed)) '() assc))
  87. (let* ((port (if (pair? rest) (car rest) (current-output-port)))
  88. (lhs-v (assq-ref spec 'lhs-v))
  89. (rhs-v (assq-ref spec 'rhs-v))
  90. (prp-v (assq-ref spec 'prp-v))
  91. (assc (setup-assc (assq-ref spec 'assc)))
  92. (nrule (vector-length lhs-v))
  93. (terms (assq-ref spec 'terminals)))
  94. ;; Generate copyright notice.
  95. (let* ((notice (assq-ref (assq-ref spec 'attr) 'notice))
  96. (lines (if notice (string-split notice #\newline) '())))
  97. (for-each (lambda (l) (fmt port "// ~A\n" l))
  98. lines))
  99. ;; Write out the tokens.
  100. (for-each
  101. (lambda (term)
  102. (unless (eqv? term '$error)
  103. (fmt port "%token ~A\n" (token->bison term))))
  104. terms)
  105. ;; Write the associativity and prececences.
  106. (let iter ((pl '()) (ppl (assq-ref spec 'prec)))
  107. (cond
  108. ((pair? pl)
  109. (fmt port "%~A" (or (assq-ref assc (caar pl)) "precedence"))
  110. (let iter2 ((pl (car pl)))
  111. (unless (null? pl)
  112. (fmt port " ~A" (elt->bison (car pl) terms))
  113. (iter2 (cdr pl))))
  114. (fmt port "\n")
  115. (iter (cdr pl) ppl))
  116. ((pair? ppl) (iter (car ppl) (cdr ppl)))))
  117. ;; Don't compact tables.
  118. (fmt port "%define lr.default-reduction accepting\n")
  119. ;; Provide start symbol.
  120. (fmt port "%start ~A\n%%\n" (elt->bison (lalr-start spec) terms))
  121. ;;
  122. (do ((i 1 (1+ i))) ((= i nrule))
  123. (let* ((lhs (vector-ref lhs-v i)) (rhs (vector-ref rhs-v i)))
  124. (fmt port "~A:" (elt->bison lhs terms))
  125. (vector-for-each
  126. (lambda (ix e) (fmt port " ~A" (elt->bison e terms)))
  127. rhs)
  128. (if (zero? (vector-length rhs)) (fmt port " %empty"))
  129. (and=> (vector-ref prp-v i)
  130. (lambda (tok) (fmt port " %prec ~A" (elt->bison tok terms))))
  131. (fmt port " ;\n")))
  132. (newline port)
  133. (values)))
  134. ;; @item pp-guile-input spec => to current output port
  135. ;; total hack right now
  136. (define (lalr->guile spec . rest)
  137. (let* ((port (if (pair? rest) (car rest) (current-output-port)))
  138. (lhs-v (assq-ref spec 'lhs-v))
  139. (rhs-v (assq-ref spec 'rhs-v))
  140. (act-v (assq-ref spec 'act-v))
  141. (nrule (vector-length lhs-v))
  142. (terms (assq-ref spec 'terminals))
  143. (lhsP #f))
  144. ;;
  145. (fmt port "(use-modules (system base lalr))\n")
  146. (fmt port "(define parser\n")
  147. (fmt port " (lalr-parser\n (")
  148. (for-each
  149. (lambda (s)
  150. (if (> (port-column port) 60) (fmt port "\n "))
  151. (cond
  152. ((equal? #\; s) (fmt port " C-semi"))
  153. ((symbol? s) (fmt port " ~A" s))
  154. (else (fmt port " C-~A" s))))
  155. terms)
  156. (fmt port ")\n")
  157. ;;
  158. (do ((i 1 (1+ i))) ((= i nrule))
  159. (let* ((lhs (vector-ref lhs-v i)) (rhs (vector-ref rhs-v i)))
  160. (if #f
  161. (pp-rule 0 i)
  162. (begin
  163. (if lhsP
  164. (if (not (eqv? lhs lhsP))
  165. (fmt port " )\n (~S\n" lhs))
  166. (fmt port " (~S\n" lhs))
  167. (fmt port " (")
  168. (do ((j 0 (1+ j) )) ((= j (vector-length rhs)))
  169. (let ((e (vector-ref rhs j)))
  170. (if (positive? j) (fmt port " "))
  171. (fmt
  172. port "~A"
  173. (cond
  174. ((equal? #\; e) (fmtstr "C-semi"))
  175. ((char? e) (fmtstr "C-~A" e))
  176. (else e)))
  177. ))
  178. (fmt port ") ")
  179. (fmt port ": ~S" `(begin ,@(vector-ref act-v i)))
  180. (fmt port "\n")
  181. (set! lhsP lhs)))))
  182. (fmt port " ))\n")
  183. (fmt port " )\n")
  184. (values)))
  185. ;;; --- last line ---