cxeval.scm 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. ;;; nyacc/lang/c99/c99eval.scm - evaluate constant expressions
  2. ;; Copyright (C) 2018-2020 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 GNU Lesser General Public License
  15. ;; along with this library; if not, see <http://www.gnu.org/licenses/>.
  16. ;;; Code:
  17. (define-module (nyacc lang c99 cxeval)
  18. #:export (parse-c99-cx eval-c99-cx)
  19. #:use-module (nyacc lalr)
  20. #:use-module (nyacc parse)
  21. #:use-module (nyacc lex)
  22. #:use-module (nyacc util)
  23. #:use-module ((nyacc lang util) #:select (make-tl tl-append tl->list))
  24. #:use-module (nyacc lang sx-util)
  25. #:use-module (nyacc lang c99 cpp)
  26. #:use-module (nyacc lang c99 munge)
  27. #:use-module (rnrs arithmetic bitwise)
  28. #:use-module ((srfi srfi-43) #:select (vector-map vector-for-each))
  29. #:use-module (system foreign))
  30. (use-modules (ice-9 pretty-print))
  31. (define (sferr fmt . args) (apply simple-format (current-error-port) fmt args))
  32. (define (pperr exp)
  33. (pretty-print exp (current-error-port) #:per-line-prefix " "))
  34. (define ffi-type-map
  35. `(("void" . ,void) ("float" . ,float) ("double" . ,double) ("short" . ,short)
  36. ("short int" . ,short) ("signed short" . ,short)
  37. ("signed short int" . ,short) ("int" . ,int) ("signed" . ,int)
  38. ("signed int" . ,int) ("long" . ,long) ("long int" . ,long)
  39. ("signed long" . ,long) ("signed long int" . ,long)
  40. ("unsigned short int" . ,unsigned-short)
  41. ("unsigned short" . ,unsigned-short)
  42. ("unsigned int" . ,unsigned-int) ("unsigned" . ,unsigned-int)
  43. ("unsigned long int" . ,unsigned-long) ("unsigned long" . ,unsigned-long)
  44. ("char" . ,int8) ("signed char" . ,int8) ("unsigned char" . ,uint8)
  45. ("wchar_t" . ,int) ("char16_t" . ,int16) ("char32_t" . ,int32)
  46. ("long long" . ,long) ("long long int" . ,long)
  47. ("signed long long" . ,long) ("signed long long int" . ,long)
  48. ("unsigned long long" . ,unsigned-long)
  49. ("unsigned long long int" . ,unsigned-long) ("_Bool" . ,int8)
  50. ("size_t" . ,size_t)))
  51. (define (sizeof-type name)
  52. (or (and=> (assoc-ref ffi-type-map name) sizeof)
  53. (throw 'nyacc-error "bad type")))
  54. ;; (string "abc" "dev")
  55. (define (sizeof-string-const value)
  56. #f)
  57. (include-from-path "nyacc/lang/c99/mach.d/c99cx-act.scm")
  58. (include-from-path "nyacc/lang/c99/mach.d/c99cx-tab.scm")
  59. (define c99cx-raw-parser
  60. (make-lalr-parser
  61. (acons 'act-v c99cx-act-v c99cx-tables)))
  62. (define gen-c99cx-lexer
  63. (let* ((reader (make-comm-reader '(("/*" . "*/"))))
  64. (comm-skipper (lambda (ch) (reader ch #f))))
  65. (make-lexer-generator c99cx-mtab
  66. #:comm-skipper comm-skipper
  67. #:chlit-reader read-c-chlit
  68. #:num-reader read-c-num)))
  69. (define (parse-c99cx text)
  70. (with-throw-handler
  71. 'nyacc-error
  72. (lambda ()
  73. (with-input-from-string text
  74. (lambda () (c99cx-raw-parser (gen-c99cx-lexer)))))
  75. (lambda (key fmt . args)
  76. (apply throw 'cpp-error fmt args))))
  77. (define (expand-typename typename udict)
  78. (let* ((decl `(udecl (decl-spec-list
  79. (type-spec (typename ,typename)))
  80. (declr (ident "_"))))
  81. (xdecl (expand-typerefs decl udict))
  82. (xname (and xdecl (sx-ref* xdecl 1 1 1 1))))
  83. xname))
  84. ;; (sizeof type-name)
  85. ;; (type-name specificer-qualifier-list abstract-declarator)
  86. ;; (decl-spec-list
  87. ;; (abs-decl
  88. (define (eval-sizeof-type tree udict)
  89. (sx-match (sx-ref tree 1)
  90. ((type-name (decl-spec-list (type-spec (typename ,name))))
  91. (let* ((xname (expand-typename name udict))
  92. (ffi-type (assoc-ref ffi-type-map xname)))
  93. (unless ffi-type ;; work to go
  94. (throw 'c99-error "cxeval: failed to expand \"sizeof(~A)\"" name))
  95. (sizeof ffi-type)))
  96. ((type-name (decl-spec-list (type-spec (fixed-type ,name))))
  97. (let* ((ffi-type (assoc-ref ffi-type-map name)))
  98. (sizeof ffi-type)))
  99. ((type-name (decl-spec-list (type-spec (float-type ,name))))
  100. (let* ((ffi-type (assoc-ref ffi-type-map name)))
  101. (sizeof ffi-type)))
  102. ((type-name (decl-spec-list (type-spec . ,_1)) (abs-declr (pointer)))
  103. (sizeof '*))
  104. (else
  105. (throw 'c99-error "failed to expand sizeof type ~S" (sx-ref tree 1)))))
  106. ;; (sizeof unary-expr)
  107. ;; (primary-expression ; S 6.5.1
  108. ;; (identifier ($$ `(p-expr ,$1)))
  109. ;; (constant ($$ `(p-expr ,$1)))
  110. ;; (string-literal ($$ `(p-expr ,(tl->list $1))))
  111. ;; ("(" expression ")" ($$ $2))
  112. ;; ("(" "{" block-item-list "}" ")"
  113. ;; ($$ `(stmt-expr (@ (extension "GNUC")) ,$3)))
  114. ;; )
  115. (define (eval-sizeof-expr tree udict)
  116. (let* ((expr (sx-ref tree 1)))
  117. (sx-match expr
  118. ((p-expr (string . ,strl))
  119. (let loop ((l 0) (sl strl))
  120. (if (pair? sl) (loop (+ l (string-length (car sl))) (cdr sl)) l)))
  121. (else
  122. (throw 'c99-error "failed to expand sizeof expr ~S" expr)))))
  123. (define (eval-ident name udict ddict)
  124. (cond
  125. ((assoc-ref ddict name) =>
  126. (lambda (hit)
  127. ;; This should actually go through the cpp-expander first methinks.
  128. (and (string? hit)
  129. (let ((expr (parse-cpp-expr hit)))
  130. (eval-c99-cx expr udict ddict)))))
  131. (else
  132. ;;(error "missed" name)
  133. #f)))
  134. ;; @deffn {Procedure} eval-c99-cx tree [udict [ddict]]
  135. ;; Evaluate the constant expression or return #f
  136. ;; @end deffn
  137. (define* (eval-c99-cx tree #:optional udict ddict)
  138. (define (fail) #f)
  139. (letrec
  140. ((ev (lambda (ex ix) (eval-expr (sx-ref ex ix))))
  141. (ev1 (lambda (ex) (ev ex 1))) ; eval expr in arg 1
  142. (ev2 (lambda (ex) (ev ex 2))) ; eval expr in arg 2
  143. (ev3 (lambda (ex) (ev ex 3))) ; eval expr in arg 3
  144. (uop (lambda (op ex) (and op ex (op ex))))
  145. (bop (lambda (op lt rt) (and op lt rt (op lt rt))))
  146. (eval-expr
  147. (lambda (tree)
  148. (case (car tree)
  149. ((fixed) (string->number (cnumstr->scm (sx-ref tree 1))))
  150. ((float) (string->number (cnumstr->scm (sx-ref tree 1))))
  151. ((char) (char->integer (string-ref (sx-ref tree 1) 0)))
  152. ((string) (string-join (sx-tail tree 1) ""))
  153. ((pre-inc post-inc) (uop 1+ (ev1 tree)))
  154. ((pre-dec post-dec) (uop 1- (ev1 tree)))
  155. ((pos) (and tree (ev1 tree)))
  156. ((neg) (uop - (ev1 tree)))
  157. ((not) (and tree (if (equal? 0 (ev1 tree)) 1 0)))
  158. ((mul) (bop * (ev1 tree) (ev2 tree)))
  159. ((div) (bop / (ev1 tree) (ev2 tree)))
  160. ((mod) (bop modulo (ev1 tree) (ev2 tree)))
  161. ((add) (bop + (ev1 tree) (ev2 tree)))
  162. ((sub) (bop - (ev1 tree) (ev2 tree)))
  163. ((lshift) (bop bitwise-arithmetic-shift-left (ev1 tree) (ev2 tree)))
  164. ((rshift) (bop bitwise-arithmetic-shift-right (ev1 tree) (ev2 tree)))
  165. ((lt) (if (bop < (ev1 tree) (ev2 tree)) 1 0))
  166. ((le) (if (bop <= (ev1 tree) (ev2 tree)) 1 0))
  167. ((gt) (if (bop > (ev1 tree) (ev2 tree)) 1 0))
  168. ((ge) (if (bop >= (ev1 tree) (ev2 tree)) 1 0))
  169. ((eq) (if (bop = (ev1 tree) (ev2 tree)) 1 0))
  170. ((ne) (if (bop = (ev1 tree) (ev2 tree)) 0 1))
  171. ((bitwise-not) (uop lognot (ev1 tree)))
  172. ((bitwise-or) (bop logior (ev1 tree) (ev2 tree)))
  173. ((bitwise-xor) (bop logxor (ev1 tree) (ev2 tree)))
  174. ((bitwise-and) (bop logand (ev1 tree) (ev2 tree)))
  175. ;;
  176. ((or)
  177. (let ((e1 (ev1 tree)) (e2 (ev2 tree)))
  178. (if (and e1 e2) (if (and (zero? e1) (zero? e2)) 0 1) #f)))
  179. ((and)
  180. (let ((e1 (ev1 tree)) (e2 (ev2 tree)))
  181. (if (and e1 e2) (if (or (zero? e1) (zero? e2)) 0 1) #f)))
  182. ((cond-expr)
  183. (let ((e1 (ev1 tree)) (e2 (ev2 tree)) (e3 (ev3 tree)))
  184. (if (and e1 e2 e3) (if (zero? e1) e3 e2) #f)))
  185. ;;
  186. ((sizeof-type)
  187. (catch 'c99-error
  188. (lambda () (eval-sizeof-type tree udict))
  189. (lambda (key fmt . args)
  190. (sferr "eval-c99-cx: ") (apply sferr fmt args)
  191. (newline (current-error-port)) #f)))
  192. ((sizeof-expr)
  193. (catch 'c99-error
  194. (lambda () (eval-sizeof-expr tree udict))
  195. (lambda (key fmt . args)
  196. (sferr "eval-c99-cx: ") (apply sferr fmt args)
  197. (newline (current-error-port)) #f)))
  198. ((ident) (eval-ident (sx-ref tree 1) udict ddict))
  199. ((p-expr) (ev1 tree))
  200. ((cast) (ev2 tree))
  201. ((fctn-call) #f) ; assume not constant
  202. ;;
  203. ;; TODO
  204. ((comp-lit) (fail)) ; return a bytearray
  205. ((comma-expr) (fail))
  206. ((i-sel) (fail))
  207. ((d-sel) (fail))
  208. ((array-ref) (fail))
  209. ;;
  210. (else (fail))))))
  211. (eval-expr tree)))
  212. ;; --- last line ---