# Re: [stack] Digest Number 85

## Soren Renner — 2000-09-05 14:11:21

    >     I had considered a certain extension of Joy, something like

    > a macro preprocessor. Louis said it would not be necessary because

    > "Joy is its own macro language". While it is true that Joy can

    > manipulate its own programs, that isn't quite the same as being

    > its own macro language. In a later message I suggested looking at

    > M4 as a suitable testbed. (Whether M4 is the best is debateable,

    > but if it was good enough for Ratfor, then it is good enough for

    > some experiments here).

    >     For ease of reading, I'll define macro names with a capital

    > letter. Then the joy definition of square and the M4 definition

    > of Square look like this:

    >     square  ==  dup *

    >     define(Square, dup *)

    > Both can be used in  the same way:

    >     3 square  ==  9

    >     3 Square  ==  9

    > But Square is an in-line version of square. For example

    >     [square] size  ==  1

    >     [Square] size  ==  [dup *] size  == 2

    > Some people want inline definitions for efficiency, since it saves

    > a call. I am not all that keen on it.

     The second kind of definition can easily be implemented in the interpreter. If the interpreter keeps a dictionary and looks up each name encountered to find the corresponding op -- instead of just using a case statement or if-elsif series to match names to ops -- then "macro definition" can be done in the language itself with one primitive:

    [dup mul] "square" define

    define takes a quotation and a string and adds an entry to the interpreter dictionary (key, value) is (string, contents of quotation). After the above code is executed,

    [2 3 4] [square] map

    will be parsed as

    [2 3 4] [dup mul] map

    Now for the confession: this is the only kind of definition my machine has. I hadn't realized before this morning that there were two kinds. The machine is written in Oberon.

    sr

## phimvt@lurac.latrobe.edu.au — 2000-09-07 02:11:59

    On Date: Tue, 05 Sep 2000 18:11:21 +0400

    Soren Renner <srenner@...> wrote

     >

    >>     For ease of reading, I'll define macro names with a capital

    >> letter. Then the joy definition of square and the M4 definition

    >> of Square look like this:

    >>     square  ==  dup *

    >>     define(Square, dup *)

    >> Both can be used in  the same way:

    >>     3 square  ==  9

    >>     3 Square  ==  9

    >> But Square is an in-line version of square. For example

    >>     [square] size  ==  1

    >>     [Square] size  ==  [dup *] size  == 2

    >> Some people want inline definitions for efficiency, since it saves

    >> a call. I am not all that keen on it.

    >

    >The second kind of definition can easily be implemented in the interpreter. If the interpreter keeps a dictionary and looks up each name encountered to find the corresponding op -- instead of just using a case statement or if-elsif series to match names to ops -- then "macro definition" can be done in the language itself with one primitive:

    >

    >[dup mul] "square" define

    >

    >

    >define takes a quotation and a string and adds an entry to the interpreter dictionary (key, value) is (string, contents of quotation). After the above code is executed,

    >

    >[2 3 4] [square] map

    >

    >will be parsed as

    >

    >[2 3 4] [dup mul] map

    >

    >Now for the confession: this is the only kind of definition my machine has. I hadn't realized before this morning that there were two kinds. The machine is written in Oberon.

    >

    >sr

     1. There are two possible styles:

       [dup mul] "square" define

       "square" [dup mul] define

    I have a suspicion (just a suspicion) that the second style would be

    more useful. Of course one could always do a swap first to get the

    other style.

    2. If your definitions always do the textual replacement as you

    indicated, then you will not be able to have simple recursive

    definitions, and even less mutually recursive definitions. For

    recursion you do need the notion of a function calling itself,

    so the functions need to be _called_ at run time. In that case

        [square] size  ==  1

    of course.

    3. In my prototype I use a particular method of garbage collection

    and a small device which saves some collection time. It would take

    long to explain what the device is, but I regret it already. The

    upshot is that the two dynamic styles of definitions would not

    fit easily into my prototype implementation. This is just a warning

    in case anybody tries to add dynamic definitions to my prototype

    implementation.

    Best wishes for your own Oberon implementation, and stay in touch,

        Manfred