Clozure / ccl

Clozure Common Lisp
http://ccl.clozure.com
Apache License 2.0
855 stars 103 forks source link

parse-ffi confusion when a type name in a cast is a macro #510

Open xrme opened 3 months ago

xrme commented 3 months ago

Consider this fragment of a .ffi file (as produced by the interface translator):

(macro ("test.h" 1) "blarg ( x )" "((char)x)")
(macro ("test.h" 2) "rme_test_constant" "blarg(45)")

If you put this in, say, ccl:darwin-x86-headers64;foo;C;foo.ffi, you can process it from lisp like so:

(in-package :ccl)
(require 'parse-ffi)
(parse-standard-ffi-files :foo)

After doing so, evaluate #1$rme_test_constant, and you'll get 45, as you'd expect. (Continue from the cerror whining about making a constant unbound, if needed.). The argument of 1 forces the cdb file on disk to be consulted, rather than just re-using a possibly already-defined defconstant form.

Now, change the .ffi file (in ccl:darwin-x86-headers64;foo;C;foo.ffi, presuming you're on an x86-64 Mac) to read as follows:

(macro ("test.h" 0) "__TYPE" "char")
(macro ("test.h" 1) "blarg ( x )" "((__TYPE)x)")
(macro ("test.h" 2) "rme_test_constant" "blarg(45)")

Do (parse-standard-ffi-files :foo) again. This time, you'll observe that evaluating #1$rme_test_constant will signal an error "foreign variable not found". Perhaps parse-ffi chokes when the type in a cast is a macro?

Uncommenting the lines in eval-c-expression https://github.com/Clozure/ccl/blob/f9650bc09dbb80d99434f0ad1145b3020427fbb7/library/parse-ffi.lisp#L371-L372 will show that something is getting indigestion.

 parse failed: "rme_test_constant" "blarg(45)"
  tokens = (C::|blarg| C::\( 45 C::\)), error = 45 where ) was expected

This comes up in real life as the following snippet from the MINGW64 winsock2.h header file:

typedef unsigned long u_long;

#define __LONG32 long

#define IOCPARM_MASK 0x7f
#define IOC_VOID 0x20000000
#define IOC_OUT 0x40000000
#define IOC_IN 0x80000000
#define IOC_INOUT (IOC_IN|IOC_OUT)

#define _IOR(x,y,t) (IOC_OUT|(((__LONG32)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))

#define FIONREAD _IOR('f',127,u_long)
(macro ("win64.h" 3) "__LONG32" "long")
(macro ("win64.h" 5) "IOCPARM_MASK" "0x7f")
(macro ("win64.h" 6) "IOC_VOID" "0x20000000")
(macro ("win64.h" 7) "IOC_OUT" "0x40000000")
(macro ("win64.h" 8) "IOC_IN" "0x80000000")
(macro ("win64.h" 9) "IOC_INOUT" "(IOC_IN|IOC_OUT)")
(macro ("win64.h" 11) "_IOR ( x , y , t )" "(IOC_OUT|(((__LONG32)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))")
(macro ("win64.h" 13) "FIONREAD" "_IOR('f',127,u_long)")
(type ("win64.h" 1)
 "u_long"