--- gforth/prim 2008/05/05 13:37:20 1.227 +++ gforth/prim 2012/09/18 15:21:08 1.278 @@ -1,6 +1,6 @@ \ Gforth primitives -\ Copyright (C) 1995,1996,1997,1998,2000,2003,2004,2005,2006,2007 Free Software Foundation, Inc. +\ Copyright (C) 1995,1996,1997,1998,2000,2003,2004,2005,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc. \ This file is part of Gforth. @@ -229,9 +229,28 @@ fprintf(stderr, "dodoes to %x, push %x\n SET_IP(DOES_CODE1(CFA)); #endif /* !defined(NO_IP) */ -(does-handler) ( -- ) gforth-internal paren_does_handler -""just a slot to have an encoding for the DOESJUMP, -which is no longer used anyway (!! eliminate this)"" +(doabicode) ( ... -- ...) gforth-internal paren_doabicode +""run-time routine for @code{ABI-code} definitions"" +abifunc *f = (abifunc *)PFA(CFA); +Float *fp_mem = fp; +sp = (*f)(sp, &fp_mem); +fp = fp_mem; +#ifdef NO_IP +INST_TAIL; +goto *next_code; +#endif /* defined(NO_IP) */ + +(do;abicode) ( ... -- ... ) gforth-internal paren_do_semicolon_abi_code +""run-time routine for @code{;abi-code}-defined words"" +Float *fp_mem = fp; +Address body = (Address)PFA(CFA); +semiabifunc *f = (semiabifunc *)DOES_CODE1(CFA); +sp = (*f)(sp, &fp_mem, body); +fp = fp_mem; +#ifdef NO_IP +INST_TAIL; +goto *next_code; +#endif /* defined(NO_IP) */ \F [endif] @@ -593,6 +612,24 @@ SET_IP((Xt *)a_target); cell+ THEN >r ; +(try1) ( ... a_oldhandler a_recovery -- R:a_recovery R:a_sp R:f_fp R:c_lp R:a_oldhandler a_newhandler ) gforth paren_try1 +a_sp = sp-1; +f_fp = fp; +c_lp = lp; +a_newhandler = rp-5; + +(throw1) ( ... wball a_handler -- ... wball ) gforth paren_throw1 +rp = a_handler; +lp = (Address)rp[1]; +fp = (Float *)rp[2]; +sp = (Cell *)rp[3]; +#ifndef NO_IP +ip=IP; +#endif +SUPER_END; +VM_JUMP(EXEC1(*(Xt *)rp[4])); + + \+ \ don't make any assumptions where the return stack is!! @@ -1066,6 +1103,34 @@ lshift ( u1 n -- u2 ) core l_shift : 0 ?DO 2* LOOP ; +umax ( u1 u2 -- u ) core +if (u1 select ; + +umin ( u1 u2 -- u ) core +if (u1r invert and r> ; + +select ( u1 u2 f -- u ) gforth +""select @i{u1} if @i{f} is true, @i{u2} if false."" +u = f ? u1 : u2; +: + IF swap THEN nip ; + \g compare \ comparisons(prefix, args, prefix, arg1, arg2, wordsets...) @@ -1463,6 +1528,17 @@ c_addr2 = c_addr1+1; : dup 1+ swap c@ ; +cell/ ( n1 -- n2 ) gforth cell_divide +""@i{n2} is the number of cells that fit into @i{n1}"" +n2 = n1 / sizeof(Cell); +: + [ cell + 2/ dup [IF] ] 2/ [ [THEN] + 2/ dup [IF] ] 2/ [ [THEN] + 2/ dup [IF] ] 2/ [ [THEN] + 2/ dup [IF] ] 2/ [ [THEN] + drop ] ; + \g compiler \+f83headerstring @@ -1647,7 +1723,7 @@ wfileid = (Cell)stderr; \+os -form ( -- urows ucols ) gforth +(form) ( -- urows ucols ) gforth paren_form ""The number of lines and columns in the terminal. These numbers may change with the window size. Note that it depends on the OS whether this reflects the actual size and changes with the window size @@ -1662,7 +1738,11 @@ ucols=cols; wcwidth ( u -- n ) gforth ""The number of fixed-width characters per unicode character u"" +#ifdef HAVE_WCWIDTH n = wcwidth(u); +#else +n = 1; +#endif flush-icache ( c_addr u -- ) gforth flush_icache ""Make sure that the instruction cache of the processor (if there is @@ -1674,10 +1754,14 @@ supported on your machine (take a look a your machine has a separate instruction cache. In such cases, @code{flush-icache} does nothing instead of flushing the instruction cache."" -FLUSH_ICACHE(c_addr,u); +FLUSH_ICACHE((caddr_t)c_addr,u); (bye) ( n -- ) gforth paren_bye SUPER_END; +gforth_FP=fp; +gforth_SP=sp; +gforth_RP=rp; +gforth_LP=lp; return (Label *)n; (system) ( c_addr u -- wretval wior ) gforth paren_system @@ -1690,12 +1774,17 @@ is the host operating system's expansion environment variable does not exist, @i{c-addr2 u2} specifies a string 0 characters in length."" /* close ' to keep fontify happy */ -c_addr2 = (Char *)getenv(cstr(c_addr1,u1,1)); +char * string = cstr(c_addr1,u1); +c_addr2 = (Char *)getenv(string); u2 = (c_addr2 == NULL ? 0 : strlen((char *)c_addr2)); +free(string); open-pipe ( c_addr u wfam -- wfileid wior ) gforth open_pipe -wfileid=(Cell)popen(cstr(c_addr,u,1),pfileattr[wfam]); /* ~ expansion of 1st arg? */ +char * string = cstr(c_addr,u); +fflush(stdout); +wfileid=(Cell)popen(string,pfileattr[wfam]); /* ~ expansion of 1st arg? */ wior = IOR(wfileid==0); /* !! the man page says that errno is not set reliably */ +free(string); close-pipe ( wfileid -- wretval wior ) gforth close_pipe wretval = pclose((FILE *)wfileid); @@ -1762,6 +1851,8 @@ if (a_addr1==NULL) else a_addr2 = (Cell *)realloc(a_addr1, u); wior = IOR(a_addr2==NULL); /* !! Define a return code */ +if (a_addr2==NULL) + a_addr2 = a_addr1; strerror ( n -- c_addr u ) gforth c_addr = (Char *)strerror(n); @@ -1777,11 +1868,21 @@ access the stack itself. The stack point variables @code{gforth_SP} and @code{gforth_FP}."" /* This is a first attempt at support for calls to C. This may change in the future */ +IF_fpTOS(fp[0]=fpTOS); gforth_FP=fp; gforth_SP=sp; +gforth_RP=rp; +gforth_LP=lp; +#ifdef HAS_LINKBACK ((void (*)())w)(); +#else +((void (*)(void *))w)(&gforth_pointers); +#endif sp=gforth_SP; fp=gforth_FP; +rp=gforth_RP; +lp=gforth_LP; +IF_fpTOS(fpTOS=fp[0]); \+ \+file @@ -1790,13 +1891,19 @@ close-file ( wfileid -- wior ) file clo wior = IOR(fclose((FILE *)wfileid)==EOF); open-file ( c_addr u wfam -- wfileid wior ) file open_file -wfileid = opencreate_file(tilde_cstr(c_addr,u,1), wfam, 0, &wior); +char * string = tilde_cstr(c_addr,u); +wfileid = opencreate_file(string, wfam, 0, &wior); +free(string); create-file ( c_addr u wfam -- wfileid wior ) file create_file -wfileid = opencreate_file(tilde_cstr(c_addr,u,1), wfam, O_CREAT|O_TRUNC, &wior); +char * string = tilde_cstr(c_addr,u); +wfileid = opencreate_file(string, wfam, O_CREAT|O_TRUNC, &wior); +free(string); delete-file ( c_addr u -- wior ) file delete_file -wior = IOR(unlink(tilde_cstr(c_addr, u, 1))==-1); +char * string = tilde_cstr(c_addr,u); +wior = IOR(unlink(string)==-1); +free(string); rename-file ( c_addr1 u1 c_addr2 u2 -- wior ) file-ext rename_file ""Rename file @i{c_addr1 u1} to new name @i{c_addr2 u2}"" @@ -1821,13 +1928,15 @@ wior = IOR(ftruncate(fileno((FILE *)wfil read-file ( c_addr u1 wfileid -- u2 wior ) file read_file /* !! fread does not guarantee enough */ u2 = fread(c_addr, sizeof(Char), u1, (FILE *)wfileid); +if (u2>0) + gf_regetc((FILE *)wfileid); wior = FILEIO(u2f f+ f/ f+ f2/ ; fcosh ( r1 -- r2 ) float-ext f_cosh +CLOBBER_TOS_WORKAROUND_START; r2 = cosh(r1); +CLOBBER_TOS_WORKAROUND_END; : fexp fdup 1/f f+ f2/ ; ftanh ( r1 -- r2 ) float-ext f_tan_h +CLOBBER_TOS_WORKAROUND_START; r2 = tanh(r1); +CLOBBER_TOS_WORKAROUND_END; : f2* fexpm1 fdup 2. d>f f+ f/ ; fasinh ( r1 -- r2 ) float-ext f_a_cinch +CLOBBER_TOS_WORKAROUND_START; r2 = asinh(r1); +CLOBBER_TOS_WORKAROUND_END; : fdup fdup f* 1. d>f f+ fsqrt f/ fatanh ; facosh ( r1 -- r2 ) float-ext f_a_cosh +CLOBBER_TOS_WORKAROUND_START; r2 = acosh(r1); +CLOBBER_TOS_WORKAROUND_END; : fdup fdup f* 1. d>f f- fsqrt f+ fln ; fatanh ( r1 -- r2 ) float-ext f_a_tan_h +CLOBBER_TOS_WORKAROUND_START; r2 = atanh(r1); +CLOBBER_TOS_WORKAROUND_END; : fdup f0< >r fabs 1. d>f fover f- f/ f2* flnp1 f2/ r> IF fnegate THEN ; @@ -2306,6 +2484,29 @@ faxpy(ra, f_x, nstridex, f_y, nstridey, fdup dup f@ f* over + 2swap dup f@ f+ dup f! over + 2swap LOOP 2drop 2drop fdrop ; +>float1 ( c_addr u c -- f:... flag ) gforth to_float1 +""Actual stack effect: ( c_addr u c -- r t | f ). Attempt to convert the +character string @i{c-addr u} to internal floating-point +representation. If the string represents a valid floating-point number +@i{r} is placed on the floating-point stack and @i{flag} is +true. Otherwise, @i{flag} is false. A string of blanks is a special +case and represents the floating-point number 0."" +Float r; +flag = to_float(c_addr, u, &r, c); +if (flag) { + fp--; + fp[0]=r; +} + +float/ ( n1 -- n2 ) gforth float_divide +n2 = n1 / sizeof(Float); + +dfloat/ ( n1 -- n2 ) gforth sfloat_divide +n2 = n1 / sizeof(DFloat); + +sfloat/ ( n1 -- n2 ) gforth dfloat_divide +n2 = n1 / sizeof(SFloat); + \+ \ The following words access machine/OS/installation-dependent @@ -2393,35 +2594,23 @@ r = fp[u]; \g syslib open-lib ( c_addr1 u1 -- u2 ) gforth open_lib -#if 1 -u2 = (UCell)lt_dlopen(cstr(c_addr1, u1, 1)); -#elif defined(HAVE_LIBDL) || defined(HAVE_DLOPEN) -#ifndef RTLD_GLOBAL -#define RTLD_GLOBAL 0 -#endif -u2=(UCell) dlopen(cstr(c_addr1, u1, 1), RTLD_GLOBAL | RTLD_LAZY); -#else -# ifdef _WIN32 -u2 = (Cell) GetModuleHandle(cstr(c_addr1, u1, 1)); -# else -#warning Define open-lib! -u2 = 0; -# endif -#endif +u2 = gforth_dlopen(c_addr1, u1); lib-sym ( c_addr1 u1 u2 -- u3 ) gforth lib_sym -#if 1 -u3 = (UCell) lt_dlsym((lt_dlhandle)u2, cstr(c_addr1, u1, 1)); +char * string = cstr(c_addr1, u1); +#ifdef HAVE_LIBLTDL +u3 = (UCell) lt_dlsym((lt_dlhandle)u2, string); #elif defined(HAVE_LIBDL) || defined(HAVE_DLOPEN) -u3 = (UCell) dlsym((void*)u2,cstr(c_addr1, u1, 1)); +u3 = (UCell) dlsym((void*)u2,string); #else # ifdef _WIN32 -u3 = (Cell) GetProcAddress((HMODULE)u2, cstr(c_addr1, u1, 1)); +u3 = (Cell) GetProcAddress((HMODULE)u2, string); # else #warning Define lib-sym! u3 = 0; # endif #endif +free(string); wcall ( ... u -- ... ) gforth gforth_FP=fp; @@ -2453,9 +2642,117 @@ l! ( w c_addr -- ) gforth l_store *(Tetrabyte*)(c_addr) = w; lib-error ( -- c_addr u ) gforth lib_error -c_addr = lt_dlerror(); -u = (c_addr == NULL) ? 0 : strlen(c_addr); +""Error message for last failed @code{open-lib} or @code{lib-sym}."" +#ifdef HAVE_LIBLTDL +c_addr = (Char *)lt_dlerror(); +u = (c_addr == NULL) ? 0 : strlen((char *)c_addr); +#elif defined(HAVE_LIBDL) || defined(HAVE_DLOPEN) +c_addr = dlerror(); +u = strlen(c_addr); +#else +c_addr = "libltdl is not configured"; +u = strlen(c_addr); +#endif +be-w! ( w c_addr -- ) gforth w_store_be +""Store the bottom 16 bits of @i{w} at @i{c_addr} in big endian format."" +c_addr[0] = w >> 8; +c_addr[1] = w; + +be-l! ( w c_addr -- ) gforth l_store_be +""Store the bottom 32 bits of @i{w} at @i{c_addr} in big endian format."" +c_addr[0] = w >> 24; +c_addr[1] = w >> 16; +c_addr[2] = w >> 8; +c_addr[3] = w; + +le-w! ( w c_addr -- ) gforth w_store_le +""Store the bottom 16 bits of @i{w} at @i{c_addr} in big endian format."" +c_addr[1] = w >> 8; +c_addr[0] = w; + +le-l! ( w c_addr -- ) gforth l_store_le +""Store the bottom 32 bits of @i{w} at @i{c_addr} in big endian format."" +c_addr[3] = w >> 24; +c_addr[2] = w >> 16; +c_addr[1] = w >> 8; +c_addr[0] = w; + +be-uw@ ( c_addr -- u ) gforth w_fetch_be +""@i{u} is the zero-extended 16-bit big endian value stored at @i{c_addr}."" +u = (c_addr[0] << 8) | (c_addr[1]); + +be-ul@ ( c_addr -- u ) gforth l_fetch_be +""@i{u} is the zero-extended 32-bit big endian value stored at @i{c_addr}."" +u = ((Cell)c_addr[0] << 24) | (c_addr[1] << 16) | (c_addr[2] << 8) | (c_addr[3]); + +le-uw@ ( c_addr -- u ) gforth w_fetch_le +""@i{u} is the zero-extended 16-bit little endian value stored at @i{c_addr}."" +u = (c_addr[1] << 8) | (c_addr[0]); + +le-ul@ ( c_addr -- u ) gforth l_fetch_le +""@i{u} is the zero-extended 32-bit little endian value stored at @i{c_addr}."" +u = ((Cell)c_addr[3] << 24) | (c_addr[2] << 16) | (c_addr[1] << 8) | (c_addr[0]); + +\+64bit + +x! ( w c_addr -- ) gforth x_store +""Store the bottom 64 bits of @i{w} at 64-bit-aligned @i{c_addr}."" +*(UOctabyte *)c_addr = w; + +ux@ ( c_addr -- u ) gforth u_x_fetch +""@i{u} is the zero-extended 64-bit value stored at 64-bit-aligned @i{c_addr}."" +u = *(UOctabyte *)c_addr; + +sx@ ( c_addr -- n ) gforth s_x_fetch +""@i{u} is the sign-extended 64-bit value stored at 64-bit-aligned @i{c_addr}."" +n = *(Octabyte *)c_addr; + +be-x! ( w c_addr -- ) gforth b_e_x_store +""Store the bottom 64 bits of @i{w} at @i{c_addr} in big endian format."" +c_addr[0] = w >> 56; +c_addr[1] = w >> 48; +c_addr[2] = w >> 40; +c_addr[3] = w >> 32; +c_addr[4] = w >> 24; +c_addr[5] = w >> 16; +c_addr[6] = w >> 8; +c_addr[7] = w; + +le-x! ( w c_addr -- ) gforth l_e_x_store +""Store the bottom 64 bits of @i{w} at @i{c_addr} in big endian format."" +c_addr[7] = w >> 56; +c_addr[6] = w >> 48; +c_addr[5] = w >> 40; +c_addr[4] = w >> 32; +c_addr[3] = w >> 24; +c_addr[2] = w >> 16; +c_addr[1] = w >> 8; +c_addr[0] = w; + +be-ux@ ( c_addr -- u ) gforth b_e_u_x_fetch +""@i{u} is the zero-extended 64-bit big endian value stored at @i{c_addr}."" +u = (((Cell)(c_addr[0]) << 56) | + ((Cell)(c_addr[1]) << 48) | + ((Cell)(c_addr[2]) << 40) | + ((Cell)(c_addr[3]) << 32) | + ((Cell)(c_addr[4]) << 24) | + ((Cell)(c_addr[5]) << 16) | + ((Cell)(c_addr[6]) << 8) | + ((Cell)(c_addr[7]))); + +le-ux@ ( c_addr -- u ) gforth l_e_u_x_fetch +""@i{u} is the zero-extended 64-bit little endian value stored at @i{c_addr}."" +u = (((Cell)(c_addr[7]) << 56) | + ((Cell)(c_addr[6]) << 48) | + ((Cell)(c_addr[5]) << 40) | + ((Cell)(c_addr[4]) << 32) | + ((Cell)(c_addr[3]) << 24) | + ((Cell)(c_addr[2]) << 16) | + ((Cell)(c_addr[1]) << 8) | + ((Cell)(c_addr[0]))); + +\+ \+ \g peephole @@ -2503,6 +2800,49 @@ a_addr = groups; \+ +\g primitive_centric + +\ primitives for primitive-centric code +\ another one is does-exec + +abi-call ( #a_callee ... -- ... ) gforth-internal abi_call +/* primitive for compiled ABI-CODE words */ +abifunc *f = (abifunc *)a_callee; +Float *fp_mem = fp; +sp = (*f)(sp, &fp_mem); +fp = fp_mem; + +;abi-code-exec ( #a_cfa ... -- ... ) gforth-internal semi_abi_code_exec +/* primitive for performing ;ABI-CODE words */ +Float *fp_mem = fp; +semiabifunc *f = (semiabifunc *)DOES_CODE1(a_cfa); +Address body = (Address)PFA(a_cfa); +sp = (*f)(sp, &fp_mem, body); +fp = fp_mem; + +lit-execute ( #a_addr -- ) new lit_execute +/* for ;code and code words; a static superinstruction would be more general, + but VM_JUMP is currently not supported there */ +#ifndef NO_IP +ip=IP; +#endif +SUPER_END; +VM_JUMP(EXEC1((Xt)a_addr)); + +\+objects +\g object_pointer + +>o ( c_addr -- r:c_old ) new to_o +c_old = op; +op = c_addr; + +o> ( r:c_addr -- ) new o_restore +op = c_addr; + +o#+ ( #w -- c_addr ) new o_lit_plus +c_addr = op + w; + +\+ \g static_super ifdef(`STACK_CACHE_FILE',