Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 24 Jan 1999 21:48:27 +0900 (JST)
From:      dcs@newsguy.com
To:        FreeBSD-gnats-submit@FreeBSD.ORG
Subject:   bin/9663: Getting builtin's parameters from the stack in loader
Message-ID:  <199901241248.VAA00508@daniel.sobral>

next in thread | raw e-mail | index | archive | help

>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 <sys/param.h>		/* 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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199901241248.VAA00508>