Plov : parser and code generator.
The parser reads the text fragments and checks how well they fit in the Plov EBNF definitions. If they fit,
the code generator will produce 'code' but not in the sense of a usual code generator. The Plov will spit out
Palo, an intermediate language. Palo is the language for a virtual stack machine and Palo programs are pure
text files.
The meaning behind this all, is to create a front-end/back-end compiler system. The Plov compiler will do the
semantics and produce errorfree intermediate code for a non existing processor called 'Palo'.
After the Plov compiler works, the Palo code can be used to write dedicated object code for just about any
real processor, using the back-end generator called 'Alto'. In short:
"But then", the smart guy is quibbling to himself, "why don't you use 'C' instead of the Palo language? C is
the universal assembler language, don't you forget that!". And in a way that person is right.
My reason to come up with the Palo language was rather simple. If Plov is to produce C code, it must produce
errorfree C code and C is mainly targeted to the PDP-8 processor. Not many of them around, nowadays. The Palo
language on the other hand is a simple language, with a slight resemblance to Forth.
Forth used to be the universal assembler, until some C guys borrowed it, never to give it back. Palo is like
Forth. Palo is easy to implement in just about any processor. You could even use your assembler of choice and
just translate all Palo instructions into macro's to produce a simple Alto back end generator. Try that with
C....
OK, there are lots of C compilers around. And for those cases, it could have been better to have Plov produce C code. But there are still lots of processors that are not covered by a C compiler. And writing a C compiler is not as easy as writing a Plov compiler.... So in the end, it will pay off to use the Palo Alto detour.
People familiar with the life and times of Professors Wirth and Gutknecht by now will understand why I chose the names for the front/back end generators. Call it a tribute to three parties.
Palo : the virtual language.
As I told above: Palo is a simple language. It is intended to be intermediate code. It is liable to change
while still a toddler (born on April 1, 2006). At this moment, Palo is defined as follows. On the left is the
mnemonic. On the right is a description. Refer to the diagram in the top of this page, depicting what TOS and
TOS-1 mean. Of course you alredy knew this was TopOfStack and TopOfStack-1. Just testing you...
| PALO | Description | Action |
|---|---|---|
| Local and global variables | ||
| VARIABLE | Create a global variable and remind the address | |
| LOCAL | Dynamically create variable local to a PROCEDURE | |
| RELEASE | Remove local variables from storage | |
| Store and retrieve | ||
| STORE NUMBER | Put NUMBER on top of the data stack (TOS). | TOS := NUMBER |
| STORE ADDRESS OF | Put ADDRESS of variable on top of the data stack (=TOS). | TOS := ADDRESS |
| FETCH VALUE OF | Get the specified value and put it on top of the datastack | TOS := value |
| SAVE RESULT | Store the NUMBER which is in TOS at the address which is in TOS-1. | [TOS-1] := TOS |
| Data operations | ||
| SWAP | Swap top two elements on the data stack | TOS := TOS-1; TOS-1 := TOS |
| MULTIPLY | Multiply top two elements on the data stack and store the result on the stack | TOS := TOS-1 * TOS |
| DIVIDE | Divide TOS-1 by TOS; leave result on the stack | TOS := TOS-1 / TOS |
| MODULO | Determine Modulo function for TOS-1 and TOS | TOS := TOS-1 MOD TOS |
| ADD | Add top of data stack to the element before it | TOS := TOS-1 + TOS |
| SUBTRACT | Subtract TOS from TOS-1 | TOS := TOS-1 - TOS |
| SHIFT LEFT | Shift data to the left; shiftcount is TOS, number to be shifted is TOS-1. | TOS := TOS-1 << TOS |
| SHIFT RIGHT | Shift data to the right; shiftcount is TOS, number to be shifted is TOS-1. | TOS := TOS-1 >> TOS |
| AND | Logical AND of top elements on stack | TOS := TOS-1 AND TOS |
| OR | Logical OR of top elements on stack | TOS := TOS-1 OR TOS |
| XOR | Logical XOR of top elements on stack | TOS := TOS-1 XOR TOS |
| PACK {data} | Store ASCII or other data in one machineword, depending on the endian-ness of the processor family. | TOS is address of data |
| PORT READ | Read from an I/O port. Port address is in TOS. | TOS := IOREAD (TOS) |
| PORT WRITE | Write to an I/O port. Port address is in TOS-1, datavalue is in TOS. | IOWRITE (TOS-1, TOS) |
| Jump and call | ||
| LABEL | Defines a label for the ALTO backend | |
| JUMP TO LABEL | Jump to LABEL | |
| CALL | Temporarily jump to the address of the specified subroutine | |
| RETURN | Abandon subroutine and return to where we left off | |
| IF Condition JUMP TO | If the condition is true, jump to the specified label | |
| Conditions | ||
| LESS | Compare TOS-1 and TOS | TOS-1 < TOS |
| LESS OR EQUAL | TOS-1 <= TOS | |
| EQUAL | TOS = TOS-1 | |
| GREATER OR EQUAL | TOS-1 >= TOS | |
| GREATER | TOS-1 > TOS | |
| NOT EQUAL | TOS # TOS-1 | |
Palo : the wirthian trick.
In his Oberon-0 compiler, Professor Wirth uses a neat trick. He applies numbers and constants to just about
any keyword. This makes checking and sorting easier. I decided to follow his example and I applied numbers to
the most appropriate keywords:
| PALO | Code | PALO | Code | PALO | Code | ||
|---|---|---|---|---|---|---|---|
| VARIABLE | 1 | MODULO | 16 | LABEL | 31 | ||
| LOCAL | 2 | ADD | 17 | CALL | 32 | ||
| RELEASE | 3 | SUBTRACT | 18 | RETURN | 33 | ||
| STORE | 4 | SHIFT | 19 | IF | 34 | ||
| NUMBER | 5 | LEFT | 20 | LESS | 35 | ||
| ADDRESS | 6 | RIGHT | 21 | EQUAL | 36 | ||
| OF | 7 | AND | 22 | GREATER | 37 | ||
| FETCH | 8 | OR | 23 | NOT | 38 | ||
| VALUE | 9 | XOR | 24 | ||||
| VECTOR | 10 | PACK | 25 | ||||
| SAVE | 11 | PORT | 26 | ||||
| RESULT | 12 | READ | 27 | ||||
| SWAP | 13 | WRITE | 28 | ||||
| MULTIPLY | 14 | JUMP | 29 | ||||
| DIVIDE | 15 | TO | 30 |
Palo : Version 2.
Below is a table with the old and the new PALO codes. PALO version 1 was too complex to parse. Too much
filling. Too much candles on the cake. I blew some of them out. The target is to get single PALO keywords,
wherever possible.
| PALO old | PALO new | Description | Action |
|---|---|---|---|
| Local and global variables | |||
| VARIABLE | Create a global variable and remind the address | ||
| LOCAL | Dynamically create variable local to a PROCEDURE | ||
| PARAMETER |
Pass parameter from caller to procedure
Store as local variable |
||
| RELEASE | Remove local variables from storage | ||
| Store and retrieve | |||
| STORE NUMBER | STORE | Put NUMBER on top of the data stack (TOS). | TOS := NUMBER |
| STORE ADDRESS OF | ADDRESS | Put ADDRESS of variable on top of the data stack (=TOS). | TOS := ADDRESS |
| FETCH VALUE OF | FETCH | Get the specified value and put it on top of the datastack | TOS := value |
| SAVE RESULT | SAVE | Store the NUMBER which is in TOS at the address which is in TOS-1. | [TOS-1] := TOS |
| Data operations | |||
| SWAP | Swap top two elements on the data stack | TOS := TOS-1; TOS-1 := TOS | |
| INCREMENT | Increment the data contained in the variable param | param := param + 1 | |
| DECREMENT | Decrement the data contained in the variable param | param := param - 1 | |
| MULTIPLY | Multiply top two elements on the data stack and store the result on the stack | TOS := TOS-1 * TOS | |
| DIVIDE | Divide TOS-1 by TOS; leave result on the stack | TOS := TOS-1 / TOS | |
| MODULO | Determine Modulo function for TOS-1 and TOS | TOS := TOS-1 MOD TOS | |
| ADD | Add top of data stack to the element before it | TOS := TOS-1 + TOS | |
| SUBTRACT | Subtract TOS from TOS-1 | TOS := TOS-1 - TOS | |
| SHIFT LEFT | LEFTSHIFT | Shift data to the left; shiftcount is TOS, number to be shifted is TOS-1. | TOS := TOS-1 << TOS |
| SHIFT RIGHT | RIGHTSHIFT | Shift data to the right; shiftcount is TOS, number to be shifted is TOS-1. | TOS := TOS-1 >> TOS |
| AND | Logical AND of top elements on stack | TOS := TOS-1 AND TOS | |
| OR | Logical OR of top elements on stack | TOS := TOS-1 OR TOS | |
| XOR | Logical XOR of top elements on stack | TOS := TOS-1 XOR TOS | |
| PACK {data} | Store ASCII or other data in one machineword, depending on the endian-ness of the processor family. | TOS is address of data | |
| PORT READ | INPORT | Read from an I/O port. Port address is in TOS. | TOS := IOREAD (TOS) |
| PORT WRITE | OUTPORT | Write data to I/O port. Port address is in TOS-1, datavalue is in TOS. | IOWRITE (TOS, TOS-1) |
| Jump and call | |||
| LABEL | Defines a label for the ALTO backend | ||
| JUMP TO LABEL | GOTO | Jump to LABEL | |
| CALL | Temporarily jump to the address of the specified subroutine | ||
| RETURN | Abandon subroutine and return to where we left off | ||
| IF Condition JUMP TO | IFTRUE | If the condition is true, jump to the specified label | |
| Conditions | |||
| LESS | Compare TOS-1 and TOS | TOS-1 < TOS | |
| LESS OR EQUAL | LEQ | TOS-1 <= TOS | |
| EQUAL | TOS = TOS-1 | ||
| GREATER OR EQUAL | GREQ | TOS-1 >= TOS | |
| GREATER | TOS-1 > TOS | ||
| NOT EQUAL | DIFFERENT | TOS # TOS-1 | |
Palo 2 : the wirthian numbers re-applied.
| PALO | Code | PALO | Code | PALO | Code | ||
|---|---|---|---|---|---|---|---|
| VARIABLE | 1 | RIGHTSHIFT | 16 | GREQ | 31 | ||
| LOCAL | 2 | AND | 17 | GREATER | 32 | ||
| RELEASE | 3 | OR | 18 | DIFFERENT | 33 | ||
| STORE | 4 | XOR | 19 | PARAMETER | 34 | ||
| ADDRESS | 5 | PACK | 20 | INCREMENT | 35 | ||
| FETCH | 6 | INPORT | 21 | DECREMENT | 36 | ||
| VECTOR | 7 | OUTPORT | 22 | ||||
| SAVE | 8 | GOTO | 23 | ||||
| SWAP | 9 | LABEL | 24 | ||||
| MULTIPLY | 10 | CALL | 25 | ||||
| DIVIDE | 11 | RETURN | 26 | ||||
| MODULO | 12 | IFTRUE | 27 | ||||
| ADD | 13 | LESS | 28 | ||||
| SUBTRACT | 14 | LEQ | 29 | ||||
| LEFTSHIFT | 15 | EQUAL | 30 | ||||
Page created 1 March 2006,
Page equipped with FroogleBuster technology