Simulating the O/S
I coded in C the cut down version of the Mouse-79 interpreter.
Did not like the '$' for the end of code so I made '\n' the end of code marker (still '$' internally) and used '\' as a line continuation code.
The intrepreter does not have unary minus (i.e. you cannot enter negative number directly), so I fixed that.
Finally, the interpreter needs an "exchange" code for the two top of data stack values. In Forth it is called SWAP. It was fixed in Mouse-83 by using the assignment operator. I think the exchange operator is better. I used the '%' symbol for it.
There are a number of Forth operators that could be added but that is for another day.
The Code
I split the code into two halves, the Op-Codes I have written that will be converted into micro-code and the Mouse interpreter. Here is the mouse interpreter:
// MOUSE O/S Language Reference
//
// $ [36] CR/LF or NL end of program code, encoded with '$'
// " [34] print up to next "
// ! [33] print CR/LF inside "'s
// ? [63] read number from stdin and push
// ! [33] pop number from stack and print it
// n [48-57] push the integer n onto stack
// A-Z [65-90] push address of variable on stack
// . [46] replace address on stack with value
// = [61] pop value, pop address, write value at address
// + [43] pop a, pop b, push a + b
// - [45] pop a, pop b, push a - b
// * [42] pop a, pop b, push a * b
// / [47] pop a, pop b, push a / b
// [ [91] pop c, if c<=0 then skip to ] on same level
// ] [93] end if
// ( [40] begin loop
// ) [41] loop back to previous ( at same level
// ^ [94] pop c, if c!=0 then break out of loop
// ' ' [32] space, sometimes necessary to deliminate numbers
// \ [92] continue on next line
// % [37] exchange top two data stack variable
// Example program:
//
// X 100 =
// (
// X. ! " Bottle(s) of beer on the wall,!"
// X. ! " bottle(s) of beer!"
// "Take one down and pass it around,!"
// X X. 1 - =
// X. ! " bottle(s) of beer on the wall.!"
// X. ^
// )
// $
#include <stdio.h>
#include <stdlib.h>
#include "OpCodes.c"
char CODE[256];
int16_t DATA_STACK[20];
int16_t RETURN_STACK[20];
int16_t VAR[26];
int16_t DATA_PTR;
int16_t CODE_PTR;
int16_t RETURN_PTR;
int16_t PARNUM;
int16_t PARBAL;
int16_t TEMPA;
int16_t TEMPB;
char CH;
void GETCHAR(void) {
CODE_PTR=CODE_PTR+1;
CH=CODE[CODE_PTR];
}
void PUSH_DATA(int16_t DATA) {
DATA_PTR=DATA_PTR+1;
DATA_STACK[DATA_PTR]=DATA;
}
int16_t POP_DATA(void) {
int16_t tmp;
tmp=DATA_STACK[DATA_PTR];
DATA_PTR=DATA_PTR-1;
if (DATA_PTR<-1) DATA_PTR=-1;
return(tmp);
}
void PUSH(void) {
RETURN_PTR=RETURN_PTR+1;
RETURN_STACK[RETURN_PTR]=CODE_PTR;
}
void POP(void) {
CODE_PTR=RETURN_STACK[RETURN_PTR];
RETURN_PTR=RETURN_PTR-1;
if (RETURN_PTR<-1) RETURN_PTR=-1;
}
void SKIP (char LCH,char RCH) {
int16_t CNT;
CNT=1;
do {
GETCHAR();
if (CH==LCH) {
CNT=CNT+1;
} else if (CH==RCH) {
CNT=CNT-1;
}
} while (CNT!=0);
}
void GETINT(void) {
int16_t temp,tmp2;
temp=0;
while ((CH>='0')&&(CH<='9')) {
tmp2=temp+temp;
temp=tmp2+tmp2;
temp=temp+temp;
temp=temp+tmp2+CH-48;
GETCHAR();
}
CODE_PTR=CODE_PTR-1;
PUSH_DATA(temp);
}
void QUOTE(void) {
do {
GETCHAR();
if (CH=='!') {
PutChar('\n');
} else if (CH!='"') {
PutChar(CH);
}
} while (CH!='"');
}
int main (void)
{
printf("RTN DATA");
RETURN_PTR=-1;
DATA_PTR=-1;
while (1) {
PutChar('\n');
printf("%3d %4d",RETURN_PTR+1,DATA_PTR+1);
PutChar('>');
// Read Evalute Repeat Loop
CODE_PTR=-1;
do { // Read command
CH=GetChar();
if ((CH!='\r')&&(CH!='\n')&&(CH!='\\')&&(CH!='$')) {
CODE_PTR=CODE_PTR+1;
CODE[CODE_PTR]=CH;
} else if (CH=='\r') {
// Skip
} else if (CH=='\n') {
// Encode as $
CH='$';
CODE_PTR=CODE_PTR+1;
CODE[CODE_PTR]=CH;
} else if (CH=='\n') {
// Skip
} else {
// '\' Extend line
CODE_PTR=CODE_PTR+1;
CODE[CODE_PTR]=' ';
// Skip until \n
while (GetChar()!='\n');
}
} while (CH!='$');
// Evaluate command
CODE_PTR=-1;
do {
GETCHAR();
switch (CH) {
case ' ':
case ']':
case '$':
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
GETINT();
break;
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
case 'V': case 'W': case 'X': case 'Y': case 'Z':
TEMPA=CH-65; // 0 based
PUSH_DATA(TEMPA);
break;
case '?':
TEMPA=rdInt();
PUSH_DATA(TEMPA);
break;
case '!':
TEMPA=POP_DATA();
wrInt(TEMPA);
break;
case '+':
TEMPA=POP_DATA();
TEMPB=POP_DATA();
PUSH_DATA(Add(TEMPA,TEMPB));
break;
case '-':
GETCHAR();
if ((CH>='0')&&(CH<='9')) {
GETINT();
TEMPA=0;
TEMPB=POP_DATA();
} else {
CODE_PTR=CODE_PTR-1;
TEMPA=POP_DATA();
TEMPB=POP_DATA();
}
PUSH_DATA(Sub(TEMPA,TEMPB));
break;
case '*':
TEMPA=POP_DATA();
TEMPB=POP_DATA();
PUSH_DATA(imul(TEMPA,TEMPB));
break;
case '/':
TEMPA=POP_DATA();
TEMPB=POP_DATA();
PUSH_DATA(idiv(TEMPA,TEMPB));
break;
case '.':
TEMPA=POP_DATA();
TEMPB=VAR[TEMPA];
PUSH_DATA(TEMPB);
break;
case'=':
TEMPA=POP_DATA();
TEMPB=POP_DATA();
VAR[TEMPB]=TEMPA;
break;
case '"':
QUOTE();
break;
case '[':
TEMPA=POP_DATA();
if (TEMPA<=0) SKIP('[',']');
break;
case '(':
PUSH();
break;
case '^':
TEMPA=POP_DATA();
if (TEMPA<=0) {
POP();
SKIP('(',')');
}
break;
case ')':
CODE_PTR=RETURN_STACK[RETURN_PTR];
break;
case '%':
TEMPA=POP_DATA();
TEMPB=POP_DATA();
PUSH_DATA(TEMPA);
PUSH_DATA(TEMPB);
break;
}
} while (CH!='$');
};
return 0;
}
Here is a run:
alanx@alanx ~/Documents/AlanC_Ccode_Mint/MouseOS $ ./MouseOS RTN DATA 0 0>\ X 10 = \ ( \ X. ! " Bottle(s) of beer on the wall,!" \ X. ! " bottle(s) of beer!" \ "Take one down and pass it around,!" \ X X. 1 - = \ X. ! " bottle(s) of beer on the wall.!" \ X. ^ \ ) 10 Bottle(s) of beer on the wall, 10 bottle(s) of beer Take one down and pass it around, 9 bottle(s) of beer on the wall. 9 Bottle(s) of beer on the wall, 9 bottle(s) of beer Take one down and pass it around, 8 bottle(s) of beer on the wall. 8 Bottle(s) of beer on the wall, 8 bottle(s) of beer Take one down and pass it around, 7 bottle(s) of beer on the wall. 7 Bottle(s) of beer on the wall, 7 bottle(s) of beer Take one down and pass it around, 6 bottle(s) of beer on the wall. 6 Bottle(s) of beer on the wall, 6 bottle(s) of beer Take one down and pass it around, 5 bottle(s) of beer on the wall. 5 Bottle(s) of beer on the wall, 5 bottle(s) of beer Take one down and pass it around, 4 bottle(s) of beer on the wall. 4 Bottle(s) of beer on the wall, 4 bottle(s) of beer Take one down and pass it around, 3 bottle(s) of beer on the wall. 3 Bottle(s) of beer on the wall, 3 bottle(s) of beer Take one down and pass it around, 2 bottle(s) of beer on the wall. 2 Bottle(s) of beer on the wall, 2 bottle(s) of beer Take one down and pass it around, 1 bottle(s) of beer on the wall. 1 Bottle(s) of beer on the wall, 1 bottle(s) of beer Take one down and pass it around, 0 bottle(s) of beer on the wall. 0 0>^C
I have had enough to drink tonight!
AlanX
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.