answer where a written type ends in one place
An arglist entry, an array's bound and its element type ask one question, and disagreed: `(unsigned int)' was a name plus a type, a trailing typedef a bound, a subscript the type's second word.
This commit is contained in:
74
types.scm
74
types.scm
@@ -237,3 +237,77 @@
|
||||
(map (lambda (value) (fn value type))
|
||||
(caddr info))))
|
||||
(else #f)))))
|
||||
|
||||
;;; The shape of a written type
|
||||
;;;
|
||||
;;; Three places have to tell a type from something that merely
|
||||
;;; contains one: an arglist entry is either `(name type)' or a bare
|
||||
;;; type, and an array's last element is either a bound or the last
|
||||
;;; word of its element type. They used to answer it separately, and
|
||||
;;; disagreed.
|
||||
|
||||
;;; A qualifier can never end a type, which is what tells `(¤ const t)'
|
||||
;;; -- an unsized array of `t' -- from `(¤ int 4)'.
|
||||
(define +c-qualifiers+ '(const volatile restrict _Atomic))
|
||||
|
||||
(define +c-specifiers+
|
||||
'(void char short int long float double signed unsigned
|
||||
bool _Bool complex _Complex))
|
||||
|
||||
;;; Does this list start a type rather than name one? `(const char)'
|
||||
;;; and `(unsigned int)' are types; `(f1 float)' is a named parameter.
|
||||
(define (type-head? form)
|
||||
(and (pair? form)
|
||||
(symbol? (car form))
|
||||
(or (memq (car form) '(* ¤ struct union enum))
|
||||
(memq (car form) +c-qualifiers+)
|
||||
(memq (car form) +c-specifiers+))))
|
||||
|
||||
;;; Does the parameter name itself?
|
||||
;;; (f1 float) does
|
||||
;;; (float), (const char), (unsigned int) and (¤ float 4) do not
|
||||
(define (named-arg? arg)
|
||||
(and (pair? arg)
|
||||
(pair? (cdr arg)) ; 1 element args are always type
|
||||
(not (type-head? arg))))
|
||||
|
||||
;;; Is NAME a typedef, as opposed to a `define'd constant? Both live in
|
||||
;;; the same table, and only the first is part of a type.
|
||||
(define (typedef-name? name)
|
||||
(let ((info (and (symbol? name) (get-type-info name))))
|
||||
(and info (memq (car info) '(typedef struct union enum)) #t)))
|
||||
|
||||
;;; `(¤ int N)' is N of int
|
||||
;;; `(¤ unsigned int)' is an unsized array of unsigned int
|
||||
;;;
|
||||
;;; The last element is a bound only if what precedes it is already a
|
||||
;;; complete type, so `(¤ const mytype)' and `(¤ * size-t)' end in the
|
||||
;;; last word of their element type and not in a bound. A type is
|
||||
;;; complete when it ends in a specifier, in a tag following its
|
||||
;;; keyword, or in a typedef we have seen declared.
|
||||
;;;
|
||||
;;; TYPE is the whole `(¤ ...)' form.
|
||||
(define (array-bound? type)
|
||||
(and (> (length type) 2)
|
||||
(let ((bound (last type))
|
||||
(preceding (last (drop-right type 1))))
|
||||
(cond
|
||||
((not (symbol? bound)) #t)
|
||||
((or (memq bound +c-specifiers+) (memq bound +c-qualifiers+)) #f)
|
||||
((memq preceding +c-specifiers+) #t)
|
||||
;; a tag always follows its keyword, so `(¤ * struct tt)' ends
|
||||
;; in a name belonging to the type
|
||||
((memq preceding '(struct union enum)) #f)
|
||||
(else (typedef-name? preceding))))))
|
||||
|
||||
;;; What one element of a written array type is:
|
||||
;;; (¤ struct point 2) -> (struct point), (¤ * const char 2) -> (* const char)
|
||||
(define (array-element-type type)
|
||||
(and (pair? type)
|
||||
(eq? '¤ (car type))
|
||||
(pair? (cdr type))
|
||||
(let ((words (if (array-bound? type)
|
||||
(drop-right (cdr type) 1)
|
||||
(cdr type))))
|
||||
(and (pair? words)
|
||||
(if (null? (cdr words)) (car words) words)))))
|
||||
|
||||
Reference in New Issue
Block a user