[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Gnu-arch-users] arch roadmap 2 (and "what's tom up to")
From: |
Tom Lord |
Subject: |
[Gnu-arch-users] arch roadmap 2 (and "what's tom up to") |
Date: |
Mon, 28 Jun 2004 12:55:56 -0700 (PDT) |
This is the first of three messages, the third of which will be
delayed a little bit.
The messages begin to introduce furth, a new extension language that I
plan to add to tla (and use for other purposes as well). They are:
1. First Furth intro (for C hackers)
What is furth and how does it work?
2. First Furth intro (in general)
What is furth and what does it look like?
3. Arch Roadmap
Where's arch going and where does furth fit in.
Furth in Too Small a Nutshell
[This is not yet an accurate or complete tutorial though it
will grow up to be one as furth progresses.]
A furth program is a list of commands. Each command is read and
then executed.
Every _thing_ in furth is both a _value_ and a _command_. There is
no distinction between commands and values: they are synonyms.
Two examples of commands in furth are:
2 ; the command "integer constant 2"
:print ; the "print" command
and so two trivial Furth programs are:
"hello world\(nl)" ; push the string "hello world\n" on the stack
:display ; write it to stdout
and
2 2 :+ ; push 2 on the stack twice, then replace
; those with their sum
:print ; print the result
So, yes, furth is one of those annoying languages like Forth or
Postscript that uses RPN.
* Quoting
The command "2" is considered "self-quoting" because, when executed,
it pushes itself on the data stack. The command ":print" is not
self-quoting. What if you want to push the command :print on the
stack rather than executing it? The quoting syntax does that:
|:print ; | == quote. Push the :print command on
; the stack.
:print ; print the value on top of the stack.
The output of that program is the string ":print".
* All Values are Dictionaries
As in many other high-level languages, all values are dictionaries.
Here is one example of a (self-quoting) value:
#(x_coord => 0 y_coord => 1)
You can read and modify (most) dictionaries in unsurprising ways:
#(x_coord => 0 y_coord => 1) ; push on stack
|y_coord ; push (quoted) field name on stack
:ref ; pop name and dictionary,
; push binding
:print
That program prints "1".
Even something like the value "2" is a dictionary, although it's not
a very interesting one. You can't modify the dictionary "2" (it's
"immutable" aka "read-only"). And, the dictinoary "2" has no
fields.
2 |y-coord :ref :print
prints ":hcf" which is what furth uses for "no defined binding".
You can read ":hcf" as "Holy Cow, Fred!" (expressing your surprise
about a missing binding) or, more properly, as "halt and catch
fire". ":hcf", in addition to being the "undefined value", is also
the the "halt and catch fire" command which causes the VM to
shut-down while indicating an error condition.
Speaking of :hcf, the following furth program is a reasonable
implementation of the unix standard utility `/bin/false':
:hcf
You can implement `/bin/true' instead with:
:halt
* Complex Commands
You can group commands in parentheses, forming a list. For example:
(2 2 +)
is a complex command with three subcommands. When executed, the
complex command executes the subcommands in sequence.
Complex commands also provide flow control. For example, the
complex command:
:(if a b)
pops a value from the stack. If that value is "#f" (aka "false")
then b is executed. Otherwise, a is executed.
Additional flow of control complex commands (e.g., loops) are also
provided although, ultimately, these can all be regarded as library
routines that reduce to more primitive constructs.
* Namespaces and $env
Every value is a dictionary. At every point during the execution of
a program, one value, called $env, "the environment", is
distinguished as the default dictionary in which to look up or
define values.
Thus this program:
42 |x :def
x x :* :print
is equivalent to:
42 $env |x :define ; 42 |x :def
:$env |x :ref :$env |x :ref :* :print ; x x :* :print
You can switch default namespaces with commands such as:
:set-$env
:ref-$env
Namespaces have single inheritence. You can construct a new
namespace, specifying that it inherits bindings from some other
namespace.
* The Stack and $tuple
Furth is stack oriented. The program fragment:
2 3
pushes the numbers 2 and 3 on the stack.
The register $tuple contains the entire stack. For example,
if the above fragment is executed, starting with an
empty stack, then at the end of the fragment we know:
$tuple = #(2 3)
Other commands can use that notation to define what they do.
For example, the :+ command could be described:
:+
before $tuple = #( ... a b)
=>
after $tuple = #( ... a+b)
The tuple is a first class value just like any other. For example,
here is an interesting definition:
:$tuple
before $tuple = #( ... a)
=>
after $tuple = #( ... a #( ... a))
(in other words, the command $tuple pushes a copy of the entire
stack onto the stack).
* Variable Capture
A command of the form:
:(capture name0 name1 .... nameN)
empties the data stack, creating a new namespace which inherits from
the current $env, has bindings for each NAME0 ... NAMEN, and takes
the values of those bindings from the old stack. The new namespace
is stored in $env.
This is, in essense, the "callee-side" of a function-call
convention. For example, this program:
1 2 3 :(capture a b c)
a :print
b :print
c :print
prints the values 1, 2, and 3.
One complement of capture is:
:pop-$env
with an unsurprising meaning, illustrated by this program
1 |x :def
2 :(capture x)
x :print
:pop-$env
x :print
which prints "2" then "1".
* $inx and $next
Whenever a command is about to be executed, $inx contains that
command. The register $next contains the "rest of the program".
Normally, a command does what it needs to do and then moves the
value in $next to $inx. That way, on the next cycle, "the rest
of the program" begins execution.
In furth, three commands are of particular interest:
:goto
before
$inx = :goto
$next = <X>
$tuple = #( ... a)
=>
after
$inx = a
$next = :hcf
$tuple = #( ... )
is an absolute "goto". And:
:jsr ("jump to subroutine")
before
$inx = :jsr
$next = <X>
$tuple = #( ... a)
=>
after
$inx = a
$next = <X>
$tuple = #( ... )
is a kind of subroutine call. Finally, there is the famous
command (from other languages):
:call/cc ("call with current continuation)
before
$inx = :call/cc
$next = <X>
$tuple = #( ... a)
=>
after
$inx = a
$next = <X>
$tuple = #(... <X>)
All flow of control constructs you are familiar with can be
implemented in terms of :goto, :call/cc, and :if. The addition
of :jsr is just an optimization, the same effect could be achieved
by prepending a ":drop" ("drop from stack") command to every
subroutine. I.e.,:
<X> :jsr
is equivalent to:
|(:drop <X>) :call/cc
* $global
$global is the final register. It functions as an alternative to
$env. By convention, $env is used to hold lexical environments
("local variables", more or less) and $global is used to hold
dynamic environments ("global variables", sort of).
* That's About It
That's about it for core Furth. I haven't enumerated obvious
things (such as the list of arithmetic operators or the list of
commands for operating on arrays). But I have given the core
concepts that provide flow of control and variables.
Furth is obviously very low-level in the sense that (virtual)
machine registers are available and can be directly manipulated.
On the other hand:
1) Furth has facilities for "syntactic extension" which
haven't been described here (since they aren't done yet).
So, you can define a higher-level language that
"hides" the registers yet compiles in a fairly trivial
way to Furth. To name one example, it would be easy
to implement a Scheme-on-Furth this way.
2) Yes, registers are exposed but that doesn't mean that
furth is "low level" in the sense of "hard to program".
* "Hey, where's my language?"
This brief proto-tutorial has left out some things you might
have expected.
For example, no standard way is provided for defining a new command,
written in Furth.
You can sort-of see how to do that: presumably you want to define a
name in the $env dictionary and somehow arrange for that name to be
"callable" as a command. But no details have been given.
That's because there's more than one way to do it. Those kinds of
features are things that will have to be built up in furth libraries
and in standard extensions to furth. The greater flexability of the
current approach makes it worth definiing on its own, first.
-t
;;; arch-tag: Tom Lord Mon Jun 28 12:48:52 2004 (furth/README.furth)
----
Like my work on GNU arch, Pika Scheme, and other technical contributions
to the public sphere? Show your support!
https://www.paypal.com/xclick/business=lord%40emf.net&item_name=support+for+arch+and+other+free+software+efforts+by+tom+lord&no_note=1&tax=0¤cy_code=USD
and
address@hidden for www.moneybookers.com payments.
-----
"Hello, all of you boys and girls,
I'd like to take you to the inside world."
- Claypool
- [Gnu-arch-users] arch roadmap 2 (and "what's tom up to"),
Tom Lord <=