equi

A self-descriptive stack-based PC platform
git clone git://git.luxferre.top/equi.git
Log | Files | Refs | README | LICENSE

commit 6466fa7d879f55b75b9ba110a70266944c216f6c
parent f99b95fcd2f2f870da3411e4de8cdd043a92fd30
Author: Luxferre <lux@ferre>
Date:   Wed, 10 Aug 2022 17:53:10 +0300

Fixed return instruction and EOF behavior

Diffstat:
MREADME.md | 9+++++----
Mequi.c | 11+++++++----
2 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/README.md b/README.md @@ -56,7 +56,7 @@ The interpreter can run in one of the four modes: command (default), interpretat In the command mode, the interpreter doesn't perform any instruction execution and doesn't manipulate program counter (PC). Instead, it accumulates all characters typed from the standard input into the so-called command buffer. The only instruction Equi must react to in this mode is CR, the carriage return character, that sets PC to the command buffer start, sets the IM flag, **clears the CLT** and starts execution in the interpretation mode. Note that this also means that every Equi program file, even when run in a non-interactive environment, must end with a CR character, and as long as it does and every program has a halting `Q` instruction, you can safely concatenate several Equi programs in a single file to be executed sequentially. -In the interpretation mode (IM flag set), when the interpreter encounters any of the following characters - `_0-9A-Fa-z` (not including `-`) - it pushes their ASCII values bytewise onto the literal stack (32-byte long, the overflown bytes are discarded). When any other character (except `:`, `"` or `'`) is encountered when the literal stack is not empty, the `#` instruction logic (see below) is performed automatically. If `:` is encountered, compilation mode logic is performed instead. If a `Q` instruction or a on-printable character is encountered, Equi returns to the command mode immediately. +In the interpretation mode (IM flag set), when the interpreter encounters any of the following characters - `_0-9A-Fa-z` (not including `-`) - it pushes their ASCII values bytewise onto the literal stack (32-byte long). When any other character (except `:`, `"` or `'`) is encountered when the literal stack is not empty, the `#` instruction logic (see below) is performed automatically. If `:` is encountered, compilation mode logic is performed instead. If a `Q` instruction or a on-printable character is encountered, Equi returns to the command mode immediately. In the compilation mode, all instructions except `;` are skipped while the CM flag is set. When the interpreter encounters `;` instruction, it performs the finalizing logic to save the compiled word into CLT (see below) and returns to the interpretation mode. @@ -68,14 +68,14 @@ Equi's core instruction set is: Op |Stack state |Meaning ---|--------------------------------|---------------------------------------------------------- -`#`|`( -- )` |Literal: pop all characters from the literal stack, discard all `_a-z` characters, leave the top 4 characters and push the 16-bit value from them (in the order they were pushed) onto the main stack +`#`|`( -- )` |Literal: pop all characters from the literal stack, discard all `_a-z` characters, leave the top 4 characters (replacing the missing ones with 0) and push the 16-bit value from them (in the order they were pushed) onto the main stack `"`|`( -- lit1 lit2 ... )` |Pop all the values from the literal stack and push them onto the main stack as 16-bit values ` `|`( -- )` |No operation: whitespace can be used in the code for clarity and not affect anything except PC `(`|`( -- )` |Set the II flag: when it is set, the interpreter must ignore all instructions except `)`, used for writing comments `)`|`( -- )` |Unset the II flag, returning to the normal interpretation or compilation mode `:`|`( -- )` |Compilation mode start: set CM flag and set CBP to PC+1 value -`;`|`( -- )` |Compilation mode end: replace this instruction in-memory with `R` instruction, pop all characters from the literal stack, append the lookup table with the first 6 chars and CBP value, unset the CM flag and increase CLTP value by 8 -`'`|`( -- )` |Call the compiled word: pop all characters from the literal stack, leave the first 6, look them up in CLT for a CBP value, set PC to CBP if found, error out if not, then push PC to return stack and set PC to the CBP value +`;`|`( -- )` |Compilation mode end: replace this instruction in-memory with `R` instruction, pop all characters from the literal stack, append the lookup table with their CRC16 hash and CBP value, unset the CM flag and increment CLTP value +`'`|`( -- )` |Call the compiled word: pop all characters from the literal stack, compute their CRC16 hash, look it up in CLT for a CBP value, set PC to CBP if found, error out if not, then push PC to return stack and set PC to the CBP value CR |`( -- )` |In the command mode, output a line break and switch to the interpretation mode (see above); in all other modes, identical to whitespace `R`|`( -- )` |**R**eturn: pop and assign the PC value from the return stack `]`|`( a -- )` |Pop the value from main stack and push onto return stack @@ -105,6 +105,7 @@ CR |`( -- )` |In the command mode, output a line break an `\|`|`( a b -- a\|b )` |Bitwise OR `^`|`( a b -- a^b )` |Bitwise XOR `.`|`( a -- ) ` |Output a character by the ASCII (or Unicode, if supported) value into the standard terminal +`H`|`( a -- ) ` |Output the hexadecimal 16-bit value from the stack top into the standard terminal `,`|`( -- a ) ` |Non-blocking key input of an ASCII (or Unicode, if supported) value from the standard terminal `?`|`( -- a ) ` |Blocking key input of an ASCII (or Unicode, if supported) value from the standard terminal `P`|`( p1 p2 port -- r1 r2 status )`|**P**ort I/O: pass two 16-bit parameters to the port and read the operation status and results into the words on the stack top diff --git a/equi.c b/equi.c @@ -301,8 +301,8 @@ void equi_main_loop() { ram.pc = 65535U; while(1) { /* iterate over the instructions in the command buffer */ instr = ram.cmdbuf[++ram.pc]; - /* silently exit on zero */ - if(instr == 0) break; + /* silently exit on zero or FF */ + if(instr == 0 || instr == 0xFFu) break; /* first, check for II mode */ if(ram.II) { if(instr == INS_IIEND) @@ -364,7 +364,8 @@ void equi_main_loop() { lhash = crc16(&ram.literal_stack[0], ram.lsp); for(pbuf=0;pbuf<CLT_ENTRIES_MAX;++pbuf) if(ram.clt[pbuf].nhash == lhash) { - ram.pc = ram.clt[pbuf].loc; + pushRet(ram.pc); /* first, save the PC into the return stack */ + ram.pc = ram.clt[pbuf].loc; /* then jump to the word location */ break; } if(pbuf >= CLT_ENTRIES_MAX) @@ -547,7 +548,9 @@ int main(int argc, char* argv[]) { while(1) { /* Now, we're in the command mode loop */ instr = ram.cmdbuf[++ram.ibp] = cgetc(); /* Fetch the next instruction from the keyboard */ - if(instr == BS && ram.ibp > ram.cmd_start) { /* process the backspace */ + if(instr == 0xFFU || instr == 0U) /* exit */ + break; + else if(instr == BS && ram.ibp > ram.cmd_start) { /* process the backspace */ #ifdef __CC65__ cputc(instr); /* echo it */ #endif