\r\nwhile (1)\r\n{\r\n if (istoken(xt))\r\n {\r\n switch(extract_token(xt) \r\n { \r\n \/\/ A gigantic switch statement implementing\r\n \/\/ the semantics of each token.\r\n case TOKEN_DROP: \/\/ This is how a token is implemented.\r\n sp++;\r\n break;\r\n }\r\n } else {\r\n w = extract_index(xt);\r\n xt = dictionary[w];\r\n continue;\r\n }\r\n\r\n w = ip++;\r\n xt = dictionary[w];\r\n}\r\n<\/pre>\nThe Usual Elements of a Threaded Interpreter<\/h2>\n
After the operation of the inner interpreter has been decided a lot of pieces easily fall into place.<\/p>\n
Nest<\/h3>\n
Nest into a definition, used by words created by a colon definition:<\/p>\n
\r\n *(--rp) = ip; \/\/ Save the current ip on the return stack.\r\n ip = w + 1; \/\/ The new threaded code starts one cell after w.\r\n<\/pre>\nUnnest<\/h3>\n
Undo what Nest did:<\/p>\n
\r\n ip = *(rp++); \/\/ Pull the saved ip from the return stack.\r\n<\/pre>\nDoVar<\/h3>\n
The execution semantics of variables.<\/p>\n
\r\n *(--sp) = (cell)(&dictionary[w + 1]); \/\/ The address of the cell after w.\r\n<\/pre>\nDoConst<\/h3>\n
The execution semantics of Forth constants.<\/p>\n
\r\n *(--sp) = dictionary[w + 1]; \/\/ The contents of the cell after w.\r\n<\/pre>\nDoCreat<\/h3>\n
The execution semantics of words defined by CREATE DOES><\/span>.
\nIn this model the DOES><\/span> part is a valid execution token (which might nest).<\/p>\n\r\n \/\/ The address of the 2nd cell after w.\r\n *(--sp) = (cell)(&dictionary[w + 2]);\r\n\r\n \/\/ Fetch the XT stored in the CREATEd word \r\n \/\/ that corresponds to the DOES> part of the definition.\r\n xt = dictionary[w + 1];\r\n\r\n \/\/ We are going back to the top of the while(1) loop. \r\n continue; \r\n<\/pre>\nUsing the Parameter Bits<\/h2>\n
In order to keep the implementation simple execution tokens are cell sized, which currently means always 32 bits. Certain tokens do in fact need extra data which is traditionally stored in the next cell in the dictionary. Because of the large token size I have decided to make to use of some of the bits inside them instead of using a second cell for it.<\/p>\n
Branch and 0Branch<\/h3>\n
Branch tokens that are used for implementing forth control structures such as IF ELSE THEN BEGIN WHILE AGAIN UNTIL REPEAT CASE OF ENDOF ENDCASE<\/span> use the parameter bits as an adjustment to ip.<\/p>\n\r\n ip += sign_extend(extract_parameter(xt));\r\n<\/pre>\nShort Literals<\/h3>\n
Short literals are supported that take the parameter bits and either sign extend or zero extend them and push them on the data stack, e.g.:<\/p>\n
\r\n *(--sp) = sign_extend(extract_parameter(xt));\r\n<\/pre>\nAdd Immediate<\/h3>\n
For implementing words such as 1+<\/span>, 1-<\/span> and CELL+<\/span>.<\/p>\n\r\n *sp += sign_extend(extract_parameter(xt));\r\n<\/pre>\nDO LOOP<\/h3>\n
Words that implement the Forth loop construct (DO ?DO LOOP +LOOP<\/span>) also use the parameter in a similar fashion as branches do.<\/p>\nDoUser<\/h3>\n
The token behind per execution thread variables (in Forth parlance USER variables) also keeps the index of the user variable in the parameter bits of the token. i.e. It pushes the start of the user area + parameter on the stack.<\/p>\n
The Forth Runtime Context<\/h2>\n
The runtime context is a data structure that contains all sorts of variables that need to be separate if two copies of the Embeddable Forth Interpreter are run in the same address space (i.e. in threads). In theory the entire dictionary could be cloned and have separate copies of everything but that is the heavyweight way of doing it. The lightweight multi-threading support is to just have separate stacks for each instance that is running, separate search order, terminal buffer, exception handler, etc. Different threads also cannot write to anything in the dictionary space, thus normal variables cannot be used thus USER<\/span> variable support is provided to allow per thread variables if the application chooses to run multiple threads that share the dictionary.<\/p>\nThe function pointers that tell Forth how to interact with the terminal are also part of the runtime context (for example one thread might talk to a serial console while the other might talk to a TCP socket — the function pointers that implement what ACCEPT<\/span> and TYPE<\/span> and their kin does take care of dealing with that.<\/p>\n","protected":false},"excerpt":{"rendered":"I have to admit that I am not great on threading. Two highly publicized systems I wrote a while ago generated native code. At least one RPM system I have recently used in a product did not even allow compiling … Continue reading →<\/span><\/a><\/p>\n","protected":false},"author":7,"featured_media":0,"parent":37,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":[],"_links":{"self":[{"href":"https:\/\/forth.teleonomix.com\/wp-json\/wp\/v2\/pages\/45"}],"collection":[{"href":"https:\/\/forth.teleonomix.com\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/forth.teleonomix.com\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/forth.teleonomix.com\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/forth.teleonomix.com\/wp-json\/wp\/v2\/comments?post=45"}],"version-history":[{"count":0,"href":"https:\/\/forth.teleonomix.com\/wp-json\/wp\/v2\/pages\/45\/revisions"}],"up":[{"embeddable":true,"href":"https:\/\/forth.teleonomix.com\/wp-json\/wp\/v2\/pages\/37"}],"wp:attachment":[{"href":"https:\/\/forth.teleonomix.com\/wp-json\/wp\/v2\/media?parent=45"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}