26.18Suspended execution. 4tH 4tH Forth compiler
ಜಾಹಿರಾತು
ಜಾಹಿರಾತು
CHAPTER 26. USING THE 4TH API 506 static unit Division [] = {
’\x01’, ’\x02’, ’\x04’, ’\x00’, ’\xff’, ’\xff’, ’\xff’, ’\x7f’, ’\x04’,
’\x62’, ’\x03’, ’\x08’, ’\x02’, ’\x09’, ’\x08’, ’\x08’, ’\x08’, ’\x08’,
’\x32’, ’\x02’, ’\x0a’, ’\x11’, ’\x07’, ’\x10’, ’\x33’, ’\x10’, ’\x07’,
’\x0e’, ’\x32’, ’\x02’, ’\x07’, ’\x08’, ’\xc8’
}; int main (int argc, char** argv)
{
Hcode* cell
Instance;
Result;
/* load addition HX code */
Instance = fetch_4th (Addition);
/* execute: add 5 to 7 */
Result = exec_4th (Instance, 0, NULL, 2, (cell) 5, (cell) 7);
/* free instance */ free_4th (Instance);
/* load division HX code */
Instance = fetch_4th (Division);
/* execute: div Result by 6 */
Result = exec_4th (Instance, 0, NULL, 2, Result, (cell) 6);
/* free instance */ free_4th (Instance);
/* print Result and exit */ printf ("Result: %ld\n", (long) Result); return (EXIT_SUCCESS);
}
There are no restrictions whatsoever to the use of the rest of the 4tH API, since fetch_4th() returns an ordinary Hcode pointer. For instance, you can still use load_4th() to load additional HX-files. Happy embedding!
26.18
Suspended execution
People are wondering how they can enable hibernation
4
. Well, you can’t. Only a 4tH programmer can do that by using the word ’PAUSE’. Normally, 4tH closes all files, releases the runtime environment and exits. When ’PAUSE’ is encountered, 4tH creates a stackframe, closes all files and exits. All API functions recognize a dormant VM and act accordingly, so there is not much you can do. You can recognize a dormant VM by examining the ”Offset” member of the Hcode structure. If is non-zero, you got a dormant VM at your hands:
Object->Offset
Still, there is a lot you can do with a dormant VM as long as you have created special provisions in your 4tH program. Take this very simple interpreter: include lib/interprt.4th
\ The words supported by the interpreter
: bye ." ZZzzzz.." cr pause ." Waky, waky!" cr ;
: test ." Test successfully executed!" cr ;
: _+ + ;
: _- - ;
: _* * ;
: _/ / ;
: _.( [char] ) parse type ;
4
Also referred to as ’hibernation’, ’sleeping VMs’ or ’dormant VMs’.
CHAPTER 26. USING THE 4TH API 507
: _cr cr ;
: _. . ;
\ The dictionary of the interpreter create wordlist
," bye" ’ bye ,
," test"
," +"
," -"
," *"
," /"
," .("
," cr"
," ."
NULL ,
’ test ,
’ _+ ,
’ _- ,
’ _* ,
’ _/ ,
’ _.( ,
’ _cr ,
’ _. , wordlist to dictionary
\ The interpreter itself
: go [’] interpret catch if ." Oops!" cr then ;
: prompt ." OK" cr refill drop go ;
: script 1 args tib place 0 >in ! go bye ;
: run begin argn 2 = if script else prompt then again ; run
Note you can only suspend this program. When you provide a commandline argument, it will interpret it as a script and execute it. That is neat! Now take a look at this C program:
#include "4th.h"
#include <stdio.h>
#include <stdlib.h>
#define HX "tiny.hx"
/*
This function starts an interactive session
*/ void Prompt (Hcode *Program)
{ puts ("Keyboard control enabled..\n");
(void) exec_4th (Program, 0, NULL, 0); puts ("\nHost control enabled..");
}
/*
This function builds an argument list and starts a script
*/ void Script (Hcode *Program, char *script)
{ char *(Args [3]); /* mimics argv[][] */
}
Args [0] = HX;
Args [1] = script;
Args [2] = NULL; puts ("Script control enabled..\n");
(void) exec_4th (Program, 2, Args, 0); puts ("\nHost control enabled..");
/* the program name */
/* the script itself */
/* the list terminator */
/*
Host program, which calls the shots
CHAPTER 26. USING THE 4TH API 508
*/ int main (int argc, char** argv)
{
Hcode *Program;
Program = load_4th (HX); if (Program)
{
/* if loading was successful */
Prompt (Program); /* interactive session */
Script (Program, ".( This is a test) cr test test test");
Prompt (Program); /* interactive session */
Script (Program, ".( Leaving an item on the stack) cr 23 45 +");
Prompt (Program); /* interactive session */
} puts ("Host shutting down.."); free_4th (Program); /* free resources */
} return (EXIT_SUCCESS);
There is a function that supplies arguments and executes a script and a function that does not supply arguments and enters interactive mode. In main() we call these functions alternately. It is a pretty mean program! You can allow a user to do what he wants and when he relinguishes control, you can execute whatever you want from your C program. It is so mean that even when the user enters something like:
11 13 * 4 + bye .( I still gotta do this!) cr
The part after ’BYE’ will still be executed before the interpreter starts executing a script.
Whatever is on the stack stays on the stack, no matter if it was left there by a script or an interactive session. Now that is powerful! But there are more neat things you can do with suspended execution. You can also use it to read or write 4tH data. That may seem a bit tricky at first, but as a matter of fact it is very easy. Take a look at this example:
10 constant NUMCELLS
NUMCELLS array Xarray
32 string Xstring
: export out ! pause ; \ save literal and sleep
: run
Xarray export \ export Xarray
Xarray 10 bounds do i ? loop cr \ show array contents s" This comes straight from 4tH!" Xstring place
Xstring export
." Famous last words.." cr
\ export Xstring
\ final message
; run
\ array size
\ array to be exported
\ string to be exported
You probably remember that the contents of OUT are returned by exec_4th(), so what
’EXPORT’ actually does is saving an address of a variable before returning control to the C program. ’EXPORT’ is called almost immediately in this example. Obviously something has been done, since the contents of ’XARRAY’ are dumped. Then a string variable is initialized and ’EXPORT’ is called again. Finally a message is printed. Doesn’t that make you wonder what the C program does?
#include "4th.h"
#include "cmds_4th.h"
CHAPTER 26. USING THE 4TH API 509
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MK_CP(a,b) ((a)->CellSeg + STACKSIZ + SYS4TH + (b))
#define MK_UP(a,b) ((a)->UnitSeg + (b))
#define NUMCELLS 10
#define HX "bulk.hx" int main (int argc, char** argv)
{ cell cell
Pointer;
Carray [] = { 0L, 10L, 20L, 30L, 40L, 50L, 60L, 70L, 80L, 90L };
Hcode *Program; cell
*p; int x;
Program = load_4th (HX); if (Program)
{
/* if loading was successful */
/* fill the 4tH array */
Pointer = exec_4th (Program, 0, NULL, 0); p = MK_CP (Program, Pointer); for (x = 0; x < NUMCELLS; x++, p++) *p = Carray [x];
/* show array and setup string */
Pointer = exec_4th (Program, 0, NULL, 0); puts (MK_UP (Program, Pointer));
/* show famous last words */
Pointer = exec_4th (Program, 0, NULL, 0); free_4th (Program); /* free hcode */
}
} return (EXIT_SUCCESS);
The first thing you notice are the two macros, MK_CP() and MK_UP(). They have been defined to create pointers to the Integer Segment and the Character Segment. It is very easy: just call 4tH from C and export your variable of choice with ’EXPORT’. In this program, the value is stored in ’Pointer’. Note that it is essential that you know exactly what has been returned: a C
ELL or a U
NIT
.
In this example, exec_4th() first returns a cell, so we have to call MK_CP() to convert it to a pointer to a cell. After that we can transfer the contents of a C array to 4tH. The second time exec_4th() returns a unit, so we’ll have to call MK_UP() to convert it to a pointer to an unit. After that we can use the pointer to print the string. Then exec_4tH() is called for the last time and a string is printed. Note that you don’t have to let 4tH finish.
You can call free_4th() any moment you want to.
That is still not enough for you? You’d like to see something even fancier? Well, what do you think about this tiny cooperative multitasker:
#include "4th.h"
#include <stdlib.h>
#define MAX_TASK 16
Hcode *Processes [MAX_TASK]; /* process slots */
/*
This routine adds a task to the process space. It returns the PID if successful, CELL_MIN if not.
*/ cell task_4th (Hcode **Process, Hcode *Task)
CHAPTER 26. USING THE 4TH API
{ cell x; if (Task) for (x = 0; x < MAX_TASK; x++) if (Process [x] == NULL)
{
Process [x] = Task; return (x);
}
} return (CELL_MIN);
510
/* if there is a task */
/* search all process slots */
/* if empty slot found */
/* add the task */
/* and return success */
/* if not, return failure */
/*
This routine searches the process space for a given task. If found, it is executed and the return value returned to the calling process. If not found, it signals termination.
*/ cell wake_4th (Hcode **Process, cell task)
{ cell x, y;
} for (x = task; x < MAX_TASK; x++) /* search slots beginning with task */ if (Process [x])
{
/* if it is an active process */
/* execute it */ y = exec_4th (Process [x], 0, NULL, 1, x);
/* if the process has terminated */ if (Process [x]->Offset == 0)
{ free_4th (Process [x]);
Process [x] = NULL;
/* free the process */
/* and set the pointer to NULL */
}
/* return next process number */ return (y == CELL_MIN ? ++x : y);
}
/* signal no active processes found */ return (task == 0 ? CELL_MIN : MAX_TASK);
/*
This is the true multitasker. It keeps on looping through the processes until it receives a kill signal from wake_4th().
*/ void multi_4th (Hcode **Process)
{ cell pid = 0L; /* process id */
} while (pid >= 0L)
{ pid = wake_4th (Process, pid); if (pid >= MAX_TASK) pid = 0;
}
/* seach all process slots */
/* now wake this process */
/* and loop around */
/*
Host program, which calls the shots
*/ int main (int argc, char** argv)
{ cell x;
ಡೌನ್ಲೋಡ್ ಮಾಡಿ
ಜಾಹಿರಾತು