Merge pull request #1319 from xexyl/1992-buzzard2
This commit is contained in:
3 files changed
+64
-54
No files matched your search
@@ -111,7 +111,7 @@ PROG= ${ENTRY}
|
|||||||
#
|
#
|
||||||
OBJ= ${PROG}.o
|
OBJ= ${PROG}.o
|
||||||
DATA=
|
DATA=
|
||||||
TARGET= ${PROG}
|
TARGET= ${PROG} first
|
||||||
#
|
#
|
||||||
ALT_OBJ= ${PROG}.alt.o
|
ALT_OBJ= ${PROG}.alt.o
|
||||||
ALT_TARGET= ${PROG}.alt
|
ALT_TARGET= ${PROG}.alt
|
||||||
|
|||||||
+59
-49
@@ -7,7 +7,8 @@ make all
|
|||||||
|
|
||||||
## To use:
|
## To use:
|
||||||
|
|
||||||
First:
|
First, you must make sure that first is made first (even though `make all`
|
||||||
|
should do it :-) ):
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
make first
|
make first
|
||||||
@@ -16,7 +17,10 @@ make first
|
|||||||
Second:
|
Second:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
# get help:
|
||||||
echo help | cat third help.th - | ./first
|
echo help | cat third help.th - | ./first
|
||||||
|
|
||||||
|
# try out a demo:
|
||||||
cat third demo5.th | ./first
|
cat third demo5.th | ./first
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -102,7 +106,7 @@ To do something interesting, you need to feed first the file
|
|||||||
[third](third) first. In unix, you can do
|
[third](third) first. In unix, you can do
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
% cat third help.th - | ./first
|
cat third help.th - | ./first
|
||||||
```
|
```
|
||||||
|
|
||||||
to do this. Hopefully most operating systems will provide a way to do this. It
|
to do this. Hopefully most operating systems will provide a way to do this. It
|
||||||
@@ -112,17 +116,18 @@ minutes on an 8086 PC); `THIRD` will prompt you when it is finished. The file
|
|||||||
part.
|
part.
|
||||||
|
|
||||||
For more information on what you can do once you've piped [third](third) into
|
For more information on what you can do once you've piped [third](third) into
|
||||||
first, type 'help' and consult FORTH manuals for further reference. Six sample
|
first, type 'help' and consult
|
||||||
THIRD programs are included in the files demo[1-6].th.
|
[FORTH](https://en.wikipedia.org/wiki/Forth_(programming_language)) manuals for
|
||||||
[buzzard.2.README.md](buzzard.2.README.md) has more information.
|
further reference. Six sample THIRD programs are included in the files
|
||||||
|
demo[1-6].th. [buzzard.2.README.md](buzzard.2.README.md) has more information.
|
||||||
|
|
||||||
Keep in mind that you are still running first, and are for the most part limited
|
Keep in mind that you are still running `first`, and are for the most part
|
||||||
by `first`'s tokenizer (notably, unknown words will attempt to be parsed as
|
limited by `first`'s tokenizer (notably, unknown words will attempt to be parsed
|
||||||
integers.) It is possible to build a new parser that parses by hand, reading a
|
as integers.) It is possible to build a new parser that parses by hand, reading
|
||||||
single character at a time; however, such a parser cannot easily use the
|
a single character at a time; however, such a parser cannot easily use the
|
||||||
existing dictionary, and so would have to implement its own, thus requiring
|
existing dictionary, and so would have to implement its own, thus requiring
|
||||||
reimplementing all of first and third a second time--I did not care to tackle
|
reimplementing all of `first` and `third` a second time--I did not care to
|
||||||
this project.
|
tackle this project.
|
||||||
|
|
||||||
|
|
||||||
### Compiling
|
### Compiling
|
||||||
@@ -133,16 +138,16 @@ on smaller machines; `m[]` needs to be at least 2000 long, though.
|
|||||||
I say `first` is portable mainly because it uses native types. Unlike
|
I say `first` is portable mainly because it uses native types. Unlike
|
||||||
[FORTH](https://en.wikipedia.org/wiki/Forth_(programming_language), which
|
[FORTH](https://en.wikipedia.org/wiki/Forth_(programming_language), which
|
||||||
traditionally allows byte and multi-byte operations, all operations are
|
traditionally allows byte and multi-byte operations, all operations are
|
||||||
performed on C `int`s. That means first code is only as portable as the same
|
performed on C `int`s. That means `first` code is only as portable as the same
|
||||||
code would be in C. As in C, the result of dividing -1 by 2 is machine (or
|
code would be in C. As in C, the result of dividing `-1` by `2` is machine (or
|
||||||
rather compiler) dependent.
|
rather compiler) dependent.
|
||||||
|
|
||||||
### How is first obfuscated?
|
### How is first obfuscated?
|
||||||
|
|
||||||
`first` is obfuscated in several ways. Some minor obfuscations like
|
`first` is obfuscated in several ways. Some minor obfuscations like
|
||||||
`&w[&m[1]][s]` for `s+m[w+1]` were in the original source but are no longer
|
`&w[&m[1]][s]` for `s+m[w+1]` were in the original source but are no longer
|
||||||
because, apparently, ANSI doesn't allow it (gcc -ansi -pedantic doesn't mind it,
|
because, apparently, ANSI doesn't allow it (`gcc -ansi -pedantic` doesn't mind
|
||||||
though.)
|
it, though.)
|
||||||
|
|
||||||
Other related obfuscations are still present. The top of the stack is cached in
|
Other related obfuscations are still present. The top of the stack is cached in
|
||||||
a variable, which increases performance massively if the compiler can figure out
|
a variable, which increases performance massively if the compiler can figure out
|
||||||
@@ -153,47 +158,51 @@ register allocate it.)
|
|||||||
More significant are the design obfuscations. `m[0]` is the "dictionary
|
More significant are the design obfuscations. `m[0]` is the "dictionary
|
||||||
pointer", used when compiling words, and `m[1]` is the return stack index. Both
|
pointer", used when compiling words, and `m[1]` is the return stack index. Both
|
||||||
are used as integer offsets into `m`. Both are kept in `m`, instead of as
|
are used as integer offsets into `m`. Both are kept in `m`, instead of as
|
||||||
separate pointers, because they are then accessible to first programs, which is
|
separate pointers, because they are then accessible to `first` programs, which
|
||||||
a crucial property of first. Similarly the way words are stored in the
|
is a crucial property of `first`. Similarly the way words are stored in the
|
||||||
dictionary is not obvious, so it can be difficult to follow exactly what the
|
dictionary is not obvious, so it can be difficult to follow exactly what the
|
||||||
compiler words are doing.
|
compiler words are doing.
|
||||||
|
|
||||||
Assuming you've waded through all that, you still have to penetrate the most
|
Assuming you've waded through all that, you still have to penetrate the most
|
||||||
significant obfuscation. Traditionally, the question is whether a reader can
|
significant obfuscation. Traditionally, the question is whether a reader can
|
||||||
answer the question "what will this do when I run it". A reader who has
|
answer the question "what will this do when I run it". A reader who has
|
||||||
deciphered first to this point may think they know the answer to this question,
|
deciphered `first` to this point may think they know the answer to this
|
||||||
but they may not know the answer to the more important question, "what will this
|
question, but they may not know the answer to the more important question, "what
|
||||||
program do when given the right input?" FORTH aficionados, and especially FORTH
|
will this program do when given the right input?"
|
||||||
implementers, may recognize the similarity of the internal compiler format to
|
[FORTH](https://en.wikipedia.org/wiki/Forth_(programming_language)) aficionados,
|
||||||
many FORTH internal representations, and, being aware that FORTH interpreters
|
and especially FORTH implementers, may recognize the similarity of the internal
|
||||||
can often be self-compiling, may be suspicious that this program can compile
|
compiler format to many FORTH internal representations, and, being aware that
|
||||||
FORTH, or a significant subset of it, or at least be capable of doing so if fed
|
FORTH interpreters can often be self-compiling, may be suspicious that this
|
||||||
the right input. Of course, the name "THIRD" should be a dead giveaway, if the
|
program can compile FORTH, or a significant subset of it, or at least be capable
|
||||||
name "first" wasn't. (These numbers were largely chosen because they were five
|
of doing so if fed the right input. Of course, the name "THIRD" should be a
|
||||||
letters long, like "FORTH", and would not require truncation to five letters,
|
dead giveaway, if the name "first" wasn't. (These numbers were largely chosen
|
||||||
which would be a dead giveaway. Besides, THIRD represents a step backwards, in
|
because they were five letters long, like "FORTH", and would not require
|
||||||
more ways than one.)
|
truncation to five letters, which would be a dead giveaway. Besides, THIRD
|
||||||
|
represents a step backwards, in more ways than one.)
|
||||||
|
|
||||||
|
|
||||||
### What exactly is `first`, then?
|
### What exactly is `first`, then?
|
||||||
|
|
||||||
`first` is a tiny interpreter which implements a sufficient pseudo-subset of
|
`first` is a tiny interpreter which implements a sufficient pseudo-subset of
|
||||||
FORTH to allow it to bootstrap a relatively complete version of FORTH (based
|
[FORTH](https://en.wikipedia.org/wiki/Forth_(programming_language)) to allow it
|
||||||
loosely on forth79), which I call THIRD. Complete relative to what, I'm not
|
to bootstrap a relatively complete version of FORTH (based loosely on forth79),
|
||||||
sure.
|
which I call THIRD. Complete relative to what, I'm not sure.
|
||||||
|
|
||||||
I believe first is close to the smallest amount of code possible to get this
|
I believe `first` is close to the smallest amount of code possible to get this
|
||||||
effect *using forth-style primitives*, and still have some efficiency (it is
|
effect *using forth-style primitives*, and still have some efficiency (it is
|
||||||
possible to get by without multiplication if you have addition, obviously). In
|
possible to get by without multiplication if you have addition, obviously). In
|
||||||
the design file, design, I give a justification for why each primitive in first
|
the design file, design, I give a justification for why each primitive in
|
||||||
was included.
|
`first` was included.
|
||||||
|
|
||||||
THIRD is sorta slow, because first has so few primitives that many things that
|
THIRD is sorta slow, because `first` has so few primitives that many things that
|
||||||
are primitives in FORTH (like swap) take a significant amount of time in THIRD.
|
are primitives in
|
||||||
|
[FORTH](https://en.wikipedia.org/wiki/Forth_(programming_language)) (like swap)
|
||||||
|
take a significant amount of time in THIRD.
|
||||||
|
|
||||||
When you get the 'Ok.' message from third, try out some sample FORTH code (first
|
When you get the `Ok.` message from third, try out some sample
|
||||||
|
[FORTH](https://en.wikipedia.org/wiki/Forth_(programming_language)) code (first
|
||||||
has no way of knowing if keyboard input is waiting, so it can't actually prompt
|
has no way of knowing if keyboard input is waiting, so it can't actually prompt
|
||||||
you in a normal way. It only prints 'Ok.' after you define a word).
|
you in a normal way. It only prints `'Ok.'` after you define a word).
|
||||||
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
@@ -230,18 +239,19 @@ using by typing:
|
|||||||
here .
|
here .
|
||||||
```
|
```
|
||||||
|
|
||||||
The number THIRD replies with is the number of machine words (ints) that the
|
The number THIRD replies with is the number of machine words (`int`s) that the
|
||||||
dictionary (the first code) takes up, plus the 512 ints for the return stack.
|
dictionary (the first code) takes up, plus the 512 `int`s for the return stack.
|
||||||
If you compile the basic THIRD system without the help word (strings take up one
|
If you compile the basic THIRD system without the help word (strings take up one
|
||||||
int per character in the string!), you should find that you're using around 1000
|
`int` per character in the string!), you should find that you're using around
|
||||||
ints (plus the return stack).
|
1000 `int`s (plus the return stack).
|
||||||
|
|
||||||
Thus THIRD gives you a relatively complete FORTH system in less than 700 chars
|
Thus THIRD gives you a relatively complete
|
||||||
of C source + about 1000 ints of memory--and it's portable too (you could copy
|
[FORTH](https://en.wikipedia.org/wiki/Forth_(programming_language)) system in
|
||||||
over the THIRD memory dump to another machine, in theory). If the above numbers
|
less than 700 chars of C source + about 1000 `int`s of memory--and it's portable
|
||||||
seem to you to be mixing apples and oranges (C source and compiled THIRD code),
|
too (you could copy over the THIRD memory dump to another machine, in theory).
|
||||||
note that you should in theory be able to stick the compiled THIRD code into the
|
If the above numbers seem to you to be mixing apples and oranges (C source and
|
||||||
C source.
|
compiled THIRD code), note that you should in theory be able to stick the
|
||||||
|
compiled THIRD code into the C source.
|
||||||
|
|
||||||
Software Construction Company gets credit for rekindling my interest in FORTH
|
Software Construction Company gets credit for rekindling my interest in FORTH
|
||||||
and thus indirectly inspiring me to write this program.
|
and thus indirectly inspiring me to write this program.
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ help.th online listing of THIRD primitives
|
|||||||
|
|
||||||
# FIRST demos:
|
# FIRST demos:
|
||||||
|
|
||||||
Use `first < {demo}`.
|
Use `./first < <demo>`.
|
||||||
|
|
||||||
demo1.1st prints Hello World! assuming ASCII
|
demo1.1st prints Hello World! assuming ASCII
|
||||||
|
|
||||||
# THIRD demos:
|
# THIRD demos:
|
||||||
|
|
||||||
Use `cat third {demo} | first`.
|
Use `cat third <demo> | ./first`.
|
||||||
|
|
||||||
demo1.th prints Hello World! regardless of character set
|
demo1.th prints Hello World! regardless of character set
|
||||||
demo2.th demonstrates a simple loop
|
demo2.th demonstrates a simple loop
|
||||||
@@ -23,7 +23,7 @@ demo6.th demonstrates switching from compiler to execution mode
|
|||||||
|
|
||||||
# Interactive THIRD:
|
# Interactive THIRD:
|
||||||
|
|
||||||
Use `cat third - | first`.
|
Use `cat third - | ./first`.
|
||||||
|
|
||||||
To include the primitive on-line help, use
|
To include the primitive on-line help, use
|
||||||
`cat third help.th - | first`.
|
`cat third help.th - | ./first`.
|
||||||
Reference in new issue
Block a user