bison.scm 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. ;;; nyacc/bison.scm - export bison
  2. ;; Copyright (C) 2016,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 bison)
  18. #:export (make-lalr-machine/bison)
  19. #:use-module (sxml simple)
  20. #:use-module (sxml match)
  21. #:use-module (sxml xpath)
  22. #:use-module (ice-9 pretty-print)
  23. #:use-module ((srfi srfi-1) #:select (fold))
  24. #:use-module ((srfi srfi-43) #:select (vector-for-each vector-map))
  25. #:use-module (nyacc export)
  26. #:use-module (nyacc lalr) ; gen-match-table
  27. )
  28. ;; @deffn chew-on-grammar tree lhs-v rhs-v terms => a-list
  29. ;; Generate a-list that maps bison rule index to NYACC rule index.
  30. (define (chew-on-grammar tree lhs-v rhs-v terms) ;; bison-rule => nyacc-rule map
  31. ;; match rule index, if no match return @code{-1}
  32. ;; could be improved by starting with last rule number and wrapping
  33. (define (match-rule lhs rhs)
  34. (let iter ((ix 0))
  35. (if (eqv? ix (vector-length lhs-v)) -1
  36. (if (and (equal? lhs (elt->bison (vector-ref lhs-v ix) terms))
  37. (equal? rhs (vector->list
  38. (vector-map
  39. (lambda (ix val) (elt->bison val terms))
  40. (vector-ref rhs-v ix)))))
  41. ix
  42. (iter (1+ ix))))))
  43. ;; this is a fold
  44. (define (rule->index-al tree seed)
  45. (sxml-match tree
  46. ;; Skip first bison rule: always $accept.
  47. ((rule (@ (number "0")) (lhs "$accept") . ,rest)
  48. (acons 0 0 seed))
  49. ;; This matches all others.
  50. ((rule (@ (number ,n)) (lhs ,lhs) (rhs (symbol ,rhs) ...))
  51. (acons (string->number n) (match-rule lhs rhs) seed))
  52. (,otherwise seed)))
  53. (fold rule->index-al '() ((sxpath '(// rule)) tree)))
  54. ;; @deffn chew-on-automaton tree gx-al bs->ns => a-list
  55. ;; This digests the automaton and generated the @code{pat-v} and @code{kis-v}
  56. ;; vectors for the NYACC automaton.
  57. (define (chew-on-automaton tree gx-al bs->ns)
  58. (define st-numb
  59. (let ((xsnum (sxpath '(@ number *text*))))
  60. (lambda (state)
  61. (string->number (car (xsnum state))))))
  62. (define (do-state state)
  63. (let* ((b-items ((sxpath '(// item)) state))
  64. (n-items (fold
  65. (lambda (tree seed)
  66. (sxml-match tree
  67. ((item (@ (rule-number ,rns) (point ,pts)) . ,rest)
  68. (let ((rn (string->number rns))
  69. (pt (string->number pts)))
  70. (if (and (positive? rn) (zero? pt)) seed
  71. (acons (assq-ref gx-al rn) pt seed))))
  72. (,otherwise (error "broken item")))) '() b-items))
  73. (b-trans ((sxpath '(// transition)) state))
  74. (n-trans (map
  75. (lambda (tree)
  76. (sxml-match tree
  77. ((transition (@ (symbol ,symb) (state ,dest)))
  78. (cons* (bs->ns symb) 'shift (string->number dest)))
  79. (,otherwise (error "broken tran")))) b-trans))
  80. (b-redxs ((sxpath '(// reduction)) state))
  81. (n-redxs (map
  82. (lambda (tree)
  83. (sxml-match tree
  84. ((reduction (@ (symbol ,symb) (rule "accept")))
  85. (cons* (bs->ns symb) 'accept 0))
  86. ((reduction (@ (symbol ,symb) (rule ,rule)))
  87. (cons* (bs->ns symb) 'reduce
  88. (assq-ref gx-al (string->number rule))))
  89. (,otherwise (error "broken redx" tree)))) b-redxs))
  90. )
  91. (list
  92. (st-numb state)
  93. (cons 'kis n-items)
  94. (cons 'pat (append n-trans n-redxs)))))
  95. (let ((xsf (sxpath '(itemset item (@ (rule-number (equal? "0"))
  96. (point (equal? "2")))))))
  97. (let iter ((data '()) (xtra #f) (states (cdr tree)))
  98. (cond
  99. ((null? states) (cons xtra data))
  100. ((pair? (xsf (car states)))
  101. (iter data (st-numb (car states)) (cdr states)))
  102. (else
  103. (iter (cons (do-state (car states)) data) xtra (cdr states)))))))
  104. ;; @deffn atomize symbol => string
  105. ;; This is copied from the module @code{(nyacc lalr)}.
  106. (define (atomize terminal) ; from lalr.scm
  107. (if (string? terminal)
  108. (string->symbol (string-append "$:" terminal))
  109. terminal))
  110. ;; @deffn make-bison->nyacc-symbol-mapper terminals non-terminals => proc
  111. ;; This generates a procedure to map bison symbol names, generated by the
  112. ;; NYACC @code{lalr->bison} procedure, (back) to nyacc symbols names.
  113. (define (make-bison->nyacc-symbol-mapper terms non-ts)
  114. (let ((bs->ns-al
  115. (cons*
  116. '("$default" . $default)
  117. '("$end" . $end)
  118. (map (lambda (symb) (cons (elt->bison symb terms) symb))
  119. (append (map atomize terms) non-ts)))))
  120. (lambda (name) (assoc-ref bs->ns-al name))))
  121. ;; fix-pa
  122. ;; fix parse action
  123. (define (fix-pa pa xs)
  124. (cond
  125. ((and (eqv? 'shift (cadr pa))
  126. (> (cddr pa) xs))
  127. (cons* (car pa) (cadr pa) (1- (cddr pa))))
  128. ((and (eqv? 'shift (cadr pa))
  129. (= (cddr pa) xs))
  130. (cons* (car pa) 'accept 0))
  131. (else pa)))
  132. ;; @deffn fix-is is xs rhs-v
  133. ;; Convert xxx
  134. (define (fix-is is xs rhs-v)
  135. (let* ((gx (car is))
  136. (rx (cdr is))
  137. (gl (vector-length (vector-ref rhs-v gx))))
  138. (if (= rx gl) (cons gx -1) is)))
  139. ;; @deffn spec->mac-sxml spec
  140. ;; Write bison-converted @var{spec} to file, run bison on it, and load
  141. ;; the bison-generated automaton as a SXML tree using the @code{-x} option.
  142. (define (spec->mach-sxml spec)
  143. (let* ((basename (tmpnam))
  144. (bisname (string-append basename ".y"))
  145. (xmlname (string-append basename ".xml"))
  146. (tabname (string-append basename ".tab.c")))
  147. (with-output-to-file bisname
  148. (lambda () (lalr->bison spec)))
  149. (system (string-append "bison" " --xml=" xmlname " --output=" tabname
  150. " " bisname))
  151. (let ((sx (call-with-input-file xmlname
  152. (lambda (p) (xml->sxml p #:trim-whitespace? #t)))))
  153. (delete-file bisname)
  154. (delete-file xmlname)
  155. (delete-file tabname)
  156. sx)))
  157. ;; @deffn make-lalr-machine/bison spec => mach
  158. ;; Make a LALR automaton, consistent with that from @code{make-lalr-machine}
  159. ;; using external @code{bison} program.
  160. (define (make-lalr-machine/bison spec)
  161. (let* ((terminals (assq-ref spec 'terminals))
  162. (non-terms (assq-ref spec 'non-terms))
  163. (lhs-v (assq-ref spec 'lhs-v))
  164. (rhs-v (assq-ref spec 'rhs-v))
  165. (s0 (spec->mach-sxml spec))
  166. (sG ((sxpath '(bison-xml-report grammar)) s0))
  167. (sG (if (pair? sG) (car sG) sG))
  168. (sA ((sxpath '(bison-xml-report automaton)) s0))
  169. (sA (if (pair? sA) (car sA) sA))
  170. (pG (chew-on-grammar sG lhs-v rhs-v terminals))
  171. (bsym->nsym (make-bison->nyacc-symbol-mapper terminals non-terms))
  172. (pA (chew-on-automaton sA pG bsym->nsym))
  173. (xs (car pA))
  174. (ns (caadr pA))
  175. (pat-v (make-vector ns #f))
  176. (kis-v (make-vector ns #f))
  177. )
  178. ;;(pretty-print sA)
  179. (for-each
  180. (lambda (state)
  181. (let* ((sx (car state))
  182. (sx (if (>= sx xs) (1- sx) sx))
  183. (pat (assq-ref (cdr state) 'pat))
  184. (pat (map (lambda (pa) (fix-pa pa xs)) pat))
  185. (kis (assq-ref (cdr state) 'kis))
  186. (kis (map (lambda (is) (fix-is is xs rhs-v)) kis)))
  187. (vector-set! pat-v sx pat)
  188. (vector-set! kis-v sx kis)))
  189. (cdr pA))
  190. (gen-match-table
  191. (cons*
  192. (cons 'pat-v pat-v)
  193. (cons 'kis-v kis-v)
  194. (cons 'len-v (vector-map (lambda (i v) (vector-length v)) rhs-v))
  195. (cons 'rto-v (vector-copy lhs-v))
  196. spec))))
  197. ;; --- last line ---