From owner-freebsd-bugs Sun Jan 24 04:50:08 1999 Return-Path: Received: (from majordom@localhost) by hub.freebsd.org (8.8.8/8.8.8) id EAA00444 for freebsd-bugs-outgoing; Sun, 24 Jan 1999 04:50:08 -0800 (PST) (envelope-from owner-freebsd-bugs@FreeBSD.ORG) Received: from freefall.freebsd.org (freefall.FreeBSD.ORG [204.216.27.21]) by hub.freebsd.org (8.8.8/8.8.8) with ESMTP id EAA00367 for ; Sun, 24 Jan 1999 04:50:00 -0800 (PST) (envelope-from gnats@FreeBSD.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.8.8/8.8.5) id EAA17385; Sun, 24 Jan 1999 04:50:02 -0800 (PST) Received: from peach.ocn.ne.jp (peach.ocn.ne.jp [210.145.254.87]) by hub.freebsd.org (8.8.8/8.8.8) with ESMTP id EAA00326 for ; Sun, 24 Jan 1999 04:49:19 -0800 (PST) (envelope-from dcs@newsguy.com) Received: from daniel.sobral by peach.ocn.ne.jp (8.9.1a/OCN) id VAA29182; Sun, 24 Jan 1999 21:49:01 +0900 (JST) Received: (from root@localhost) by daniel.sobral (8.9.1/8.9.2) id VAA00508; Sun, 24 Jan 1999 21:48:27 +0900 (JST) (envelope-from root) Message-Id: <199901241248.VAA00508@daniel.sobral> Date: Sun, 24 Jan 1999 21:48:27 +0900 (JST) From: dcs@newsguy.com Reply-To: dcs@newsguy.com To: FreeBSD-gnats-submit@FreeBSD.ORG X-Send-Pr-Version: 3.2 Subject: bin/9663: Getting builtin's parameters from the stack in loader Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org >Number: 9663 >Category: bin >Synopsis: Making builtin's state-aware in loader >Confidential: no >Severity: non-critical >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Sun Jan 24 04:50:01 PST 1999 >Closed-Date: >Last-Modified: >Originator: Daniel C. Sobral >Release: FreeBSD 4.0-CURRENT i386 >Organization: >Environment: Current as of Jan 23 >Description: Loader's builtin command always get their parameters from The Input Buffer, presently. People have expressed interest in having parameters passed through the stack when the builtin word is used during compilation. >How-To-Repeat: UTSL. >Fix: The following fix makes builtins state-aware. When they get compiled, their execution semantics become to expect ( An Un ... A2 U2 A1 U1 n -- ) on the stack, where n is the number of strings defined by the pairs Ax Ux, which will make up the parameters for the builtin. These parameters are concatenated together in LIFO order, with spaces being added between each of them. If the builtin is interpreted instead of compiled, it's behavior remains unchanged. With this change, getting the xt of a builtin with ' or ['] for later use with EXECUTE or CATCH becomes illegal. Well, you can still do so, but that will always act as if the word is being POSTPONEd. The new compilation semantics can be achieve by use of a proxy word. For example: : proxy-ls ls ; s" /boot" 1 ' proxy-ls catch . Though this is inconvenient, given that the use of CATCH with the builtins is indicated for most programs, it cannot be helped given the desired semantics for the builtins. We *could* remove the THROWing from the builtins, but that has undesirable side-effects too. --- src/sys/boot/common/interp_forth.c 1999/01/23 07:16:57 1.8 +++ src/sys/boot/common/interp_forth.c 1999/01/24 12:28:21 @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: interp_forth.c,v 1.8 1999/01/23 07:16:57 root Exp $ + * $Id: interp_forth.c,v 1.11 1999/01/24 12:28:08 root Exp root $ */ #include /* to pick up __FreeBSD_version */ @@ -66,6 +66,7 @@ int len; struct bootblk_command **cmdp; bootblk_cmd_t *cmd; + int nstrings, i; int argc, result; char **argv; @@ -80,18 +81,42 @@ } if (cmd == NULL) panic("callout for unknown command '%s'", name); + + /* Check whether we have been compiled or are being interpreted */ + if (stackPopINT32(vm->pStack)) { + /* + * Get parameters from stack, in the format: + * an un ... a2 u2 a1 u1 n -- + * Where n is the number of strings, a/u are pairs of + * address/size for strings, and they will be concatenated + * in LIFO order. + */ + nstrings = stackPopINT32(vm->pStack); + for (i = 0, len = 0; i < nstrings; i++) + len += stackFetch(vm->pStack, i * 2).i + 1; + line = malloc(strlen(name) + len + 1); + strcpy(line, name); + + if (nstrings) + for (i = 0; i < nstrings; i++) { + len = stackPopINT32(vm->pStack); + cp = stackPopPtr(vm->pStack); + strcat(line, " "); + strncat(line, cp, len); + } + } else { + /* Get remainder of invocation */ + tail = vmGetInBuf(vm); + for (cp = tail, len = 0; cp != vm->tib.end && *cp != 0 && *cp != '\n'; cp++, len++) + ; - /* Get remainder of invocation */ - tail = vmGetInBuf(vm); - for (cp = tail, len = 0; cp != vm->tib.end && *cp != 0 && *cp != '\n'; cp++, len++) - ; - - line = malloc(strlen(name) + len + 2); - strcpy(line, name); - if (len > 0) { - strcat(line, " "); - strncat(line, tail, len); - vmUpdateTib(vm, tail + len); + line = malloc(strlen(name) + len + 2); + strcpy(line, name); + if (len > 0) { + strcat(line, " "); + strncat(line, tail, len); + vmUpdateTib(vm, tail + len); + } } DEBUG("cmd '%s'", line); @@ -119,6 +144,73 @@ } /* + * Replace a word definition (a builtin command) with another + * one that: + * + * - Throw error results instead of returning them on the stack + * - Pass a flag indicating whether the word was compiled or is + * being interpreted. + * + * There is one major problem with builtins that cannot be overcome + * in anyway, except by outlawing it, such as done below. We want + * builtins to behave differently depending on whether they have been + * compiled or they are being interpreted. Notice that this is *not* + * the current state. For example: + * + * : example ls ; immediate + * : problem example ; + * example + * + * Notice that the current state is different in the two invocations + * of "example", but, in both cases, "ls" has been *compiled in*, which + * is what we really want. + * + * The problem arises when you tick the builtin. For example: + * + * : example-1 ['] ls postpone literal ; immediate + * : example-2 example-1 execute ; immediate + * : problem example-2 ; + * example-2 + * + * We have no way, when we get EXECUTEd, of knowing what our behavior + * should be. Thus, our only alternative is to "outlaw" this. See RFI + * 0007, and ANS Forth Standard's appendix D, item 6.7. + * + * The problem is compounded by the fact that ' builtin CATCH is valid + * and desirable. The only solution is to create an intermediary word. + * For example: + * + * : my-ls ls ; + * : example ['] my-ls catch ; + * + * As the this definition is particularly tricky, and it's side effects + * must be well understood by those playing with it, I'll be heavy on + * the comments. + * + * (if you edit this definition, pay attention to trailing spaces after + * each word -- I warned you! :-) ) + */ +#define BUILTIN_CONSTRUCTOR \ +": builtin: " \ + ">in @ " /* save the tib index pointer */ \ + "' " /* get next word's xt */ \ + "swap >in ! " /* point again to next word */ \ + "create " /* create a new definition of the next word */ \ + ", " /* save previous definition's xt */ \ + "immediate " /* make the new definition an immediate word */ \ + \ + "does> " /* Now, the *new* definition will: */ \ + "state @ if " /* if in compiling state: */ \ + "1 postpone literal " /* pass 1 flag to indicate compile */ \ + "@ compile, " /* compile in previous definition */ \ + "postpone throw " /* throw stack-returned result */ \ + "else " /* if in interpreting state: */ \ + "0 swap " /* pass 0 flag to indicate interpret */ \ + "@ execute " /* call previous definition */ \ + "throw " /* throw stack-returned result */ \ + "then ; " + +/* * Initialise the Forth interpreter, create all our commands as words. */ void @@ -131,8 +223,8 @@ ficlInitSystem(4000); /* Default dictionary ~4000 cells */ bf_vm = ficlNewVM(); - /* Builtin word "creator" */ - ficlExec(bf_vm, ": builtin: >in @ ' swap >in ! create , does> @ execute throw ;", -1); + /* Builtin constructor word */ + ficlExec(bf_vm, BUILTIN_CONSTRUCTOR, -1); /* make all commands appear as Forth words */ SET_FOREACH(cmdp, Xcommand_set) { >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message