Many more ops written, and it compiles. Nothing works yet.
This commit is contained in:
parent
f5f8e38b91
commit
c9f50572ab
17 changed files with 290 additions and 71 deletions
|
|
@ -67,7 +67,7 @@ That's the list of things I've found so far that look useful to me. If I find ot
|
|||
|
||||
### Tag location
|
||||
|
||||
Objects in Lisp have to know that they are. This is what makes it possible to compute with an 'untyped' language: the type is not encoded in the program but in the data. In most conventional Lisp systems, things are typed by having a tag. Back in the day, when we had hardware specially built to run Lisp, Lisp specific hardware often had a word size — and thus registers, and a data bus — wider than the address bus, wider by the number of bits in the tag, and stored the tag on the pointer.
|
||||
Objects in Lisp have to know what they are. This is what makes it possible to compute with an 'untyped' language: the type is not encoded in the program but in the data. In most conventional Lisp systems, things are typed by having a tag. Back in the day, when we had hardware specially built to run Lisp, Lisp specific hardware often had a word size — and thus registers, and a data bus — wider than the address bus, wider by the number of bits in the tag, and stored the tag on the pointer.
|
||||
|
||||
Modern Lisps still, I think, mostly store the tag on the pointer, but they run on commodity hardware which doesn't have those extra bits in the word size. That means that the size of an integer, or the precision of a real, that you can store in one word of memory is much less. It also means either that they can address much less memory than other programming languages on the same hardware, because for every bit you steal out of the address bus you halve the amount of memory you can address; or else that they bit shift up every address before they fetch it.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,81 @@
|
|||
# State of Play
|
||||
|
||||
## 20260415
|
||||
|
||||
OK, I have been diverted down a side-project on a side-project. I decided
|
||||
that since Post Scarcity definitely needs a compiler, I should learn to write
|
||||
a compiler, and so I should start by writing one for a simpler Lisp than Post
|
||||
Scarcity. So I started to write
|
||||
[one in Guile Scheme for Beowulf](https://git.journeyman.cc/simon/naegling).
|
||||
This is started but a long way from finished. I'm also not very enamoured of
|
||||
Guile Scheme, and am starting to wonder whether in fact I should be writing
|
||||
if in [Beowulf](https://git.journeyman.cc/simon/beowulf) for Beowulf.
|
||||
|
||||
I do believe I can complete the Naegling/Beowulf compiler, and that having
|
||||
written it, I can write a Post Scarcity compiler in Post Scarcity. But to do
|
||||
that I still need to have to have at least all of
|
||||
|
||||
* apply
|
||||
* assoc
|
||||
* bind! (or put! or set!, but I *think* I prefer `bind!`)
|
||||
* car
|
||||
* cdr
|
||||
* cons
|
||||
* cond
|
||||
* eq?
|
||||
* equal?
|
||||
* eval
|
||||
* λ
|
||||
* nil
|
||||
* print
|
||||
* read
|
||||
* t
|
||||
|
||||
and, essentially, have all the parts of a working REPL.
|
||||
|
||||
My brain is not working very well at present; I can't do more than a very few
|
||||
hours of focussed work a day, and jumping between Naegling and Post Scarcity
|
||||
is probably not a good plan; but in periods when I need to do thinking about
|
||||
where I'm going with Naegling I may switch to Post Scarcity (and vice versa).
|
||||
|
||||
### Standard signature for compiled functions
|
||||
|
||||
While I'm on this, I'm wondering whether I've got the standard signature for
|
||||
compiled functions right. What we've inherited from the `0.0.X` branch is
|
||||
documented as:
|
||||
|
||||
```c
|
||||
/**
|
||||
* pointer to a function which takes a cons pointer (representing
|
||||
* its argument list) and a cons pointer (representing its environment) and a
|
||||
* stack frame (representing the previous stack frame) as arguments and returns
|
||||
* a cons pointer (representing its result).
|
||||
* \todo check this documentation is current!
|
||||
*/
|
||||
struct cons_pointer ( *executable ) ( struct stack_frame *,
|
||||
struct cons_pointer,
|
||||
struct cons_pointer );
|
||||
```
|
||||
|
||||
But actually the documentation here is wrong, because what we actually pass
|
||||
is a C pointer to a stack frame object (which in `0.0.X` is in vector space),
|
||||
a cons pointer to the cons space object which is the vector pointer to that
|
||||
stack frame, and a cons pointer to the environment.
|
||||
|
||||
We definitely don't need to pass a pointer to the argument list (and in fact
|
||||
we didn't before, the documentation is *wrong*); we also don't need to pass
|
||||
both a C pointer and a cons pointer to the frame, since the frame is now in
|
||||
paged space, so passing our managed pointer is enough.
|
||||
|
||||
It *might be* that passing both an unmanaged and a managed pointer is worth
|
||||
doing, since recovering the managed pointer from the unmanaged pointer is
|
||||
very expensive, and while recovering the unmanaged pointer from the
|
||||
managed pointer is cheap, it isn't free.
|
||||
|
||||
But it's worth thinking about.
|
||||
|
||||
|
||||
|
||||
## 20260331
|
||||
|
||||
Substrate layer `print` is written; all the building blocks for substrate
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue