[gforth] / gforth / libcc.fs  

gforth: gforth/libcc.fs


1 : anton 1.1 \ libcc.fs foreign function interface implemented using a C compiler
2 :    
3 :     \ Copyright (C) 2006 Free Software Foundation, Inc.
4 :    
5 :     \ This file is part of Gforth.
6 :    
7 :     \ Gforth is free software; you can redistribute it and/or
8 :     \ modify it under the terms of the GNU General Public License
9 :     \ as published by the Free Software Foundation; either version 2
10 :     \ of the License, or (at your option) any later version.
11 :    
12 :     \ This program is distributed in the hope that it will be useful,
13 :     \ but WITHOUT ANY WARRANTY; without even the implied warranty of
14 :     \ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 :     \ GNU General Public License for more details.
16 :    
17 :     \ You should have received a copy of the GNU General Public License
18 :     \ along with this program; if not, write to the Free Software
19 :     \ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
20 :    
21 :    
22 :     \ What this implementation does is this: if it sees a declaration like
23 :    
24 : anton 1.2 \ \ something that tells it that the current library is libc
25 : anton 1.6 \ \c #include <unistd.h>
26 : anton 1.2 \ c-function dlseek lseek n d n -- d
27 : anton 1.1
28 :     \ it genererates C code similar to the following:
29 :    
30 :     \ #include <gforth.h>
31 : anton 1.2 \ #include <unistd.h>
32 : anton 1.1 \
33 : anton 1.2 \ void gforth_c_lseek_ndn_d(void)
34 : anton 1.1 \ {
35 :     \ Cell *sp = gforth_SP;
36 :     \ Float *fp = gforth_FP;
37 : anton 1.2 \ long long result; /* longest type in C */
38 :     \ gforth_ll2d(lseek(sp[3],gforth_d2ll(sp[2],sp[1]),sp[0]),sp[3],sp[2]);
39 :     \ gforth_SP = sp+2;
40 : anton 1.1 \ }
41 :    
42 :     \ Then it compiles this code and dynamically links it into the Gforth
43 :     \ system (batching and caching are future work). It also dynamically
44 :     \ links lseek. Performing DLSEEK then puts the function pointer of
45 : anton 1.2 \ the function pointer of gforth_c_lseek_ndn_d on the stack and
46 :     \ calls CALL-C.
47 :    
48 :     \ other things to do:
49 :    
50 :     \ c-variable forth-name c-name
51 :     \ c-constant forth-name c-name
52 :    
53 :    
54 :     \ data structures
55 :    
56 :     \ c-function word body:
57 :     \ cell function pointer
58 :     \ char return type index
59 :     \ char parameter count n
60 :     \ char*n parameters (type indices)
61 :     \ counted string: c-name
62 :    
63 : anton 1.3 : .nb ( n -- )
64 : anton 1.2 0 .r ;
65 :    
66 :     : const+ ( n1 "name" -- n2 )
67 :     dup constant 1+ ;
68 :    
69 : anton 1.6 \ linked list stuff (should go elsewhere)
70 :    
71 :     hex
72 :    
73 :     require struct.fs
74 :    
75 :     struct
76 :     cell% field list-next
77 :     1 0 field list-payload
78 :     end-struct list%
79 :    
80 :     : list-insert { node list -- }
81 :     list list-next @ node list-next !
82 :     node list list-next ! ;
83 :    
84 :     : list-append { node endlistp -- }
85 :     \ insert node at place pointed to by endlistp
86 :     node endlistp @ list-insert
87 :     node list-next endlistp ! ;
88 :    
89 :     : list-map ( ... list xt -- ... )
90 :     \ xt ( ... node -- ... )
91 :     { xt } begin { node }
92 :     node while
93 :     node xt execute
94 :     node list-next @
95 :     repeat ;
96 :    
97 :     \ C prefix lines
98 :    
99 :     \ linked list of longcstrings: [ link | count-cell | characters ]
100 :    
101 :     list%
102 :     cell% field c-prefix-count
103 :     1 0 field c-prefix-chars
104 :     end-struct c-prefix%
105 :    
106 :     variable c-prefix-lines 0 c-prefix-lines !
107 :     variable c-prefix-lines-end c-prefix-lines c-prefix-lines-end !
108 :    
109 :     : save-c-prefix-line ( c-addr u -- )
110 :     align here 0 , c-prefix-lines-end list-append ( c-addr u )
111 :     longstring, ;
112 :    
113 :     : \c ( "rest-of-line" -- )
114 :     -1 parse save-c-prefix-line ;
115 :    
116 :     : print-c-prefix-line ( node -- )
117 :     dup c-prefix-chars swap c-prefix-count @ type cr ;
118 :    
119 :     : print-c-prefix-lines ( -- )
120 :     c-prefix-lines @ ['] print-c-prefix-line list-map ;
121 :    
122 :     \c #include "engine/libcc.h"
123 : anton 1.5
124 : anton 1.6 print-c-prefix-lines
125 : anton 1.5
126 : anton 1.6 \ Types (for parsing)
127 : anton 1.5
128 : anton 1.2 wordlist constant libcc-types
129 :    
130 :     get-current libcc-types set-current
131 :    
132 :     \ index values
133 :     -1
134 :     const+ -- \ end of arguments
135 :     const+ n \ integer cell
136 : anton 1.5 const+ a \ address cell
137 : anton 1.2 const+ d \ double
138 :     const+ r \ float
139 :     const+ func \ C function pointer
140 :     const+ void
141 :     drop
142 :    
143 :     set-current
144 :    
145 :     : parse-libcc-type ( "libcc-type" -- u )
146 :     parse-name libcc-types search-wordlist 0= -13 and throw execute ;
147 :    
148 :     : parse-function-types ( "{libcc-type}" "--" "libcc-type" -- )
149 :     here 2 chars allot here begin
150 :     parse-libcc-type dup 0>= while
151 :     c,
152 :     repeat
153 : anton 1.3 drop here swap - over char+ c!
154 :     parse-libcc-type dup 0< -32 and throw swap c! ;
155 : anton 1.2
156 :     : type-letter ( n -- c )
157 : anton 1.5 chars s" nadrfv" drop + c@ ;
158 : anton 1.2
159 :     \ count-stacks
160 :    
161 :     : count-stacks-n ( fp-change1 sp-change1 -- fp-change2 sp-change2 )
162 :     1+ ;
163 :    
164 : anton 1.5 : count-stacks-a ( fp-change1 sp-change1 -- fp-change2 sp-change2 )
165 : anton 1.2 1+ ;
166 :    
167 :     : count-stacks-d ( fp-change1 sp-change1 -- fp-change2 sp-change2 )
168 :     2 + ;
169 :    
170 :     : count-stacks-r ( fp-change1 sp-change1 -- fp-change2 sp-change2 )
171 :     swap 1+ swap ;
172 :    
173 :     : count-stacks-func ( fp-change1 sp-change1 -- fp-change2 sp-change2 )
174 :     1+ ;
175 :    
176 :     : count-stacks-void ( fp-change1 sp-change1 -- fp-change2 sp-change2 )
177 :     ;
178 :    
179 :     create count-stacks-types
180 :     ' count-stacks-n ,
181 : anton 1.5 ' count-stacks-a ,
182 : anton 1.2 ' count-stacks-d ,
183 :     ' count-stacks-r ,
184 :     ' count-stacks-func ,
185 :     ' count-stacks-void ,
186 :    
187 :     : count-stacks ( pars -- fp-change sp-change )
188 :     \ pars is an addr u pair
189 :     0 0 2swap over + swap u+do
190 : anton 1.3 i c@ cells count-stacks-types + @ execute
191 : anton 1.2 loop ;
192 :    
193 :     \ gen-pars
194 :    
195 :     : gen-par-n ( fp-depth1 sp-depth1 -- fp-depth2 sp-depth2 )
196 : anton 1.5 ." sp[" 1- dup .nb ." ]" ;
197 : anton 1.2
198 : anton 1.5 : gen-par-a ( fp-depth1 sp-depth1 -- fp-depth2 sp-depth2 )
199 : anton 1.2 ." (void *)(" gen-par-n ." )" ;
200 :    
201 :     : gen-par-d ( fp-depth1 sp-depth1 -- fp-depth2 sp-depth2 )
202 : anton 1.4 ." gforth_d2ll(" gen-par-n ." ," gen-par-n ." )" ;
203 : anton 1.2
204 :     : gen-par-r ( fp-depth1 sp-depth1 -- fp-depth2 sp-depth2 )
205 : anton 1.3 swap 1- tuck ." fp[" .nb ." ]" ;
206 : anton 1.2
207 :     : gen-par-func ( fp-depth1 sp-depth1 -- fp-depth2 sp-depth2 )
208 : anton 1.5 gen-par-a ;
209 : anton 1.2
210 :     : gen-par-void ( fp-depth1 sp-depth1 -- fp-depth2 sp-depth2 )
211 :     -32 throw ;
212 :    
213 :     create gen-par-types
214 :     ' gen-par-n ,
215 : anton 1.5 ' gen-par-a ,
216 : anton 1.2 ' gen-par-d ,
217 :     ' gen-par-r ,
218 :     ' gen-par-func ,
219 :     ' gen-par-void ,
220 :    
221 :     : gen-par ( fp-depth1 sp-depth1 partype -- fp-depth2 sp-depth2 )
222 : anton 1.3 cells gen-par-types + @ execute ;
223 : anton 1.2
224 :     \ the call itself
225 :    
226 :     : gen-wrapped-call { d: pars d: c-name fp-change1 sp-change1 -- }
227 :     c-name type ." ("
228 : anton 1.3 fp-change1 sp-change1 pars over + swap u+do
229 : anton 1.2 i c@ gen-par
230 :     i 1+ i' < if
231 :     ." ,"
232 :     endif
233 :     loop
234 :     2drop ." )" ;
235 :    
236 :     \ calls for various kinds of return values
237 :    
238 :     : gen-wrapped-void ( pars c-name fp-change1 sp-change1 -- fp-change sp-change )
239 :     2dup 2>r gen-wrapped-call 2r> ;
240 :    
241 : anton 1.3 : gen-wrapped-n ( pars c-name fp-change1 sp-change1 -- fp-change sp-change )
242 : anton 1.5 2dup gen-par-n 2>r ." =" gen-wrapped-call 2r> ;
243 : anton 1.3
244 : anton 1.5 : gen-wrapped-a ( pars c-name fp-change1 sp-change1 -- fp-change sp-change )
245 :     2dup gen-par-n 2>r ." =(Cell)" gen-wrapped-call 2r> ;
246 : anton 1.3
247 :     : gen-wrapped-d ( pars c-name fp-change1 sp-change1 -- fp-change sp-change )
248 :     ." gforth_ll2d(" gen-wrapped-void
249 : anton 1.5 ." ," gen-par-n ." ," gen-par-n ." )" ;
250 : anton 1.3
251 :     : gen-wrapped-r ( pars c-name fp-change1 sp-change1 -- fp-change sp-change )
252 : anton 1.5 2dup gen-par-r 2>r ." =" gen-wrapped-void 2r> ;
253 : anton 1.3
254 :     : gen-wrapped-func ( pars c-name fp-change1 sp-change1 -- fp-change sp-change )
255 : anton 1.5 gen-wrapped-a ;
256 : anton 1.3
257 : anton 1.2 create gen-wrapped-types
258 :     ' gen-wrapped-n ,
259 : anton 1.5 ' gen-wrapped-a ,
260 : anton 1.2 ' gen-wrapped-d ,
261 :     ' gen-wrapped-r ,
262 :     ' gen-wrapped-func ,
263 :     ' gen-wrapped-void ,
264 :    
265 :     : gen-wrapped-stmt ( pars c-name fp-change1 sp-change1 ret -- fp-change sp-change )
266 : anton 1.3 cells gen-wrapped-types + @ execute ;
267 : anton 1.2
268 :     : gen-wrapper-function ( addr -- )
269 :     \ addr points to the return type index of a c-function descriptor
270 :     c@+ { ret } count 2dup { d: pars } chars + count { d: c-name }
271 : anton 1.6 print-c-prefix-lines
272 : anton 1.2 ." void gforth_c_" c-name type ." _"
273 : anton 1.5 pars bounds u+do
274 :     i c@ type-letter emit
275 : anton 1.2 loop
276 :     ." _" ret type-letter emit .\" (void)\n"
277 : anton 1.4 .\" {\n Cell MAYBE_UNUSED *sp = gforth_SP;\n Float MAYBE_UNUSED *fp = gforth_FP;\n "
278 : anton 1.2 pars c-name 2over count-stacks ret gen-wrapped-stmt .\" ;\n"
279 :     ?dup-if
280 : anton 1.3 ." gforth_SP = sp+" .nb .\" ;\n"
281 : anton 1.2 endif
282 :     ?dup-if
283 : anton 1.3 ." gforth_FP = fp+" .nb .\" ;\n"
284 : anton 1.2 endif
285 : anton 1.3 .\" }\n" ;
286 : anton 1.2
287 : anton 1.5 : compile-wrapper-function ( -- )
288 :     s" gcc -fPIC -shared -Wl,-soname,xxx.so.1 -Wl,-export_dynamic -o xxx.so.1 -O xxx.c" system
289 :     $? abort" compiler generated error" ;
290 :     \ s" ar rcs xxx.a xxx.o" system
291 :     \ $? abort" ar generated error" ;
292 :    
293 :     : link-wrapper-function ( -- )
294 :     s" /home/anton/gforth/xxx.so.1" open-lib ( lib-handle )
295 :     s" gforth_c_strlen_a_n" rot lib-sym dup 0= -32 and throw ;
296 :    
297 : anton 1.2 : c-function ( "forth-name" "c-name" "{libcc-type}" "--" "libcc-type" -- )
298 :     create here >r 0 , \ place for the wrapper function pointer
299 :     parse-name { d: c-name }
300 :     parse-function-types c-name string,
301 : anton 1.5 r@ cell+
302 :     s" xxx.c" w/o create-file throw ( file-id )
303 :     dup >r >outfile gen-wrapper-function outfile<
304 :     r> close-file throw
305 :     compile-wrapper-function
306 :     link-wrapper-function
307 :     r> !
308 : anton 1.2 does> ( ... -- ... )
309 :     @ call-c ;
310 :    
311 :    
312 :    
313 : anton 1.1
314 :    
315 :     s" Library not found" exception constant err-nolib
316 :    
317 :     : library ( "name" "file" -- ) \ gforth
318 :     \G Dynamically links the library specified by @i{file}. Defines a
319 :     \G word @i{name} ( -- lib ) that starts the declaration of a
320 :     \G function from that library.
321 :     create parse-name open-lib dup 0= err-nolib and throw ,
322 :     does> ( -- lib )
323 :     @ ;
324 :    
325 : anton 1.3 \ test
326 : anton 1.1
327 : anton 1.5 \ test all parameter and return types
328 :    
329 :     \ cr .( #include "engine/libcc.h")
330 :     \ cr .( #include <unistd.h>)
331 :     \ cr ." typedef void (* func)(int);
332 :     \ cr ." int test1(int,char*,long,double,void (*)(int));"
333 :     \ cr ." Cell *test2(void);"
334 :     \ cr ." int test3(void);"
335 :     \ cr ." float test4(void);"
336 :     \ cr ." func test5(void);"
337 :     \ cr ." void test6(void);"
338 :     \ cr
339 :    
340 :     \ c-function dlseek lseek n d n -- d
341 :     \ c-function n test1 n a d r func -- n
342 :     \ c-function a test2 -- a
343 :     \ c-function d test3 -- d
344 :     \ c-function r test4 -- r
345 :     \ c-function func test5 -- func
346 :     \ c-function void test6 -- void
347 :    
348 :     c-function strlen strlen a -- n
349 :    
350 :     cr s\" fooo\0" 2dup dump drop .s strlen cr .s cr

CVS Admin

Powered by ViewCVS 1.0-dev
(Powered by ViewCVS)

ViewCVS and CVS Help