Skip to content

jhlagado/Mindy

Repository files navigation

Mindy Language 0.1

Mindy is a minimalist character-based interpreter but one which aims at fast performance, readability and ease of use. It is written for the Z80 microprocessor and is 2K.

What is Mindy?

Mindy is a bytecode interpreter - this means that all of its instructions are 1 byte long. However, the choice of instruction uses printable ASCII characters, as a human readable alternative to assembly language. The interpreter handles 16-bit integers and addresses which is sufficient for small applications running on an 8-bit cpu.

Reverse Polish Notation (RPN)

RPN is a concatenative way of writing expressions in which the operators come after their operands. Concatenative languages make use of a stack which is uses to collect data to do work on. The results are pushed back on the stack.

Here is an example of a simple Mindy program that uses RPN:

10 20 + .

As the interpreter encounters numbers it pushes them on to the stack. Then it encounters the + operator which is uses to add the two items on the stack and pushes the result back on the stack. The result becomes the data for the . operator which prints the number to the console.

Numbers

Mindy on the Z80 uses 16-bit integers to represent numbers. A valid (but not very interesting) Mindy program can be simply a sequence of numbers. Nothing will happen to them though until the program encounters an operator.

There are two main types of numbers in Mindy: decimal numbers and hexadecimal numbers.

Decimal numbers

Decimal numbers are represented in Mindy in the same way that they are represented in most other programming languages. For example, the number 12345 is represented as 12345. A negative number is preceded by a - as in -786.

Hexadecimal numbers

Hexadecimal numbers are represented in Mindy using the uppercase letters A to F to represent the digits 10 to 15. Hexadecimal numbers are prefixed with a ' character. So for example, the hexadecimal number 1F3A is represented as '1F3A. Unlike decimal numbers, hexadecimal numbers are assumed to be positive in Mindy.

Printing

Printing numbers

Mindy provides commands for printing numbers in decimal and hexadecimal format.

The . operator prints numbers to the console in decimal. The , operator prints numbers to the console in hexadecimal.

Printing text

Mindy allows the user to easily print literal text by using ` quotes.

For example

100 x !
`The value of x is ` x .

prints The value of x is 100

Stack Manipulation

In Mindy, the stack is a central data structure that stores values temporarily. Let's explore some fundamental operators that help you manage the stack

Duplicate

The # or "dup" operator duplicates the top element of the stack.

The following code prints 10 10

10 # . .

Drop

The \ or "drop" removes the top element of the stack.

The following code prints 20

20 30 \ .

Swap

The $ of "swap" operator exchanges the positions of the top two elements on the stack.

The following code prints 50 40

40 50 $ . .

Over

The % of "over" operator copies the second element from the top of the stack and places it on top.

The following code prints 60 70 60

60 70 % . . .

Variables

Variables are named locations in memory that can store data. Mindy has a limited number of global variables which have single letter names. In Mindy a variable can be referred to by a singer letter from a to z so there are 26 global variables in Mindy. Global variables can be used to store numbers, strings, arrays, blocks, functions etc.

To assign the value 10 to the global variable x use the ! operator.

10 x !

In this example, the number 10 is assigned to the variable x

The code below adds 3 to the value stored in variable x and then prints it.

3 x + .

The following code assigns the hexadecimal number '3FFF to variable a The second line fetches the value stored in a and prints it.

'3FFF a !
a .

In this longer example, the number 10 is stored in a and the number 20 is stored in b. The values in these two variables are then added together and the answer 30 is stored in z. Finally z is printed.

10 a !
20 b !
a b + z !
z .

System variables

In addition to the 26 general purpose variables, Mindy has a 26 system variables which have special uses. System variables start with a / followed by a lowercase character.

Basic arithmetic operations

In this program the numbers 5 and 4 are operands to the operator * which multiplies them together. The . operator prints the result of the multiplication.

5 4 * .

This program subtracts 20 from 10 which results in the negative value -10 The . operator prints the difference.

10 20 - .

This program divides 5 with 4 prints the result.

5 4 / . .

The remainder of the last division operation is available in the /r system variable.

/r .

Logical operators

Mindy uses numbers to define boolean values.

  • false is represented by the number 0
  • true is represented by the number -1of 'FFFF.

For clarity Mindy allows boolean values to be expressed as /t and /f (that's true and false respectively)

3 0 = .

prints 0

0 0 = .

prints 1

Mindy has a set of bitwise logical operators that can be used to manipulate bits. These operators are:

& performs a bitwise AND operation on the two operands.
| performs a bitwise OR operation on the two operands.
^ performs a bitwise XOR operation on the two operands.
~ performs a bitwise NOT on one operand.
/L shifts the bits of the operand to the left by one.
/R shifts the bits of the operand to the right by one.

The bitwise logical operators can be used to perform a variety of operations on bits, such as:

  • Checking if a bit is set or unset.
  • Setting or clearing a bit.
  • Flipping a bit.
  • Counting the number of set bits in a number.

Here is an example of how to use the bitwise logical operators in Mindy:

Check if the first bit of the number 10 is set

11 1 & ,

this will print 0001

Shift 1 three times to the left (i.e. multiple by 8) and then OR 1 with the least significant bit.

1 3 /L 1 | ,

prints 0009

Shift 1 two times to the left (i.e. multiple by 4) and then XOR '000F and then mask with '000F.

1 2 /L 'F ^ 'F & ,

The following inverts 'FFFF and prints 0

'FFFF ~ .

prints 000B

Arrays

Basic arrays

Mindy arrays are a type of data structure that can be used to store a collection of elements. Arrays are indexed, which means that each element in the array has a unique number associated with it. This number is called the index of the element. In Mindy, array indexes start at 0

To create a Mindy array, you can use the following syntax:

[ element1 element2 ... ]

for example

[ 1 2 3 ]

Arrays can be assigned to variables just like number values

[ 1 2 3 ] a !

An array of 16-bit numbers can be defined by enclosing them within square brackets:

[ 1 2 3 4 5 6 7 8 9 0 ]

Defining an array puts its start address onto the stack

These can then be allocated to a variable, which acts as a pointer to the array in memory

[ 1 2 3 4 5 6 7 8 9 0 ] a !

To fetch the Nth member of the array, we can create use the index operator @

The following prints the item at index 2 (which is 3).

[ 1 2 3 ] 2@  .

Array size

The size of an array can be determined with the /S operator which puts the number of items in the array on the stack.

The following prints 5 on the console.

[ 1 2 3 4 5 ] /S .

Nested arrays

In Mindy arrays can be nested inside one another.

The following code shows an array with another array as its second item. This code accesses the second item of the first array with 1@ . It then accesses the first item of the inner array with 0@ and prints the result (which is 2).

[1 [2 3]] 1@  0@  .

Loops

Looping in Mindy is of the form

number (code to execute)

The number represents the number of times the code between parentheses will be repeated. If the number is zero then the code will be skipped. If the number is ten it will be repeated ten times. If the number is -1 then the loop will repeat forever.

0(this code will not be executed but skipped)
1(this code will be execute once)
10(this code will execute 10 times)
/f(this code will not be executed but skipped)
/t(this code will be execute once)
/u(this code will be execute forever)

This code following prints ten x's.

10 (`x`)

The following code repeats ten times and adds 1 to the variable t each time. When the loop ends it prints the value of t which is 10.

0t! 10( t 1+ t! ) t .

Mindy provides a special variable /i which acts as a loop counter. The counter counts up from zero. Just before the counter reaches the limit number it terminates.

This prints the numbers 0 to 9.

10 ( /i . )

Loops can repeat forever by specifying an "unlimited" loop with /u. These can be controlled with the "while" operator /W. Passing a false value to /W will terminate the loop.

This code initialises t to zero and starts a loop to repeat 10 times. The code to repeat accesses the /i variable and compares it to 4. When /i exceeds 4 it breaks the loop. Otherwise it accesses t and adds 1 to it.

Finally when the loop ends it prints the value of t which is 5.

0t! /u(/i 4 < /W /i t 1+ t!) t .

Loops can be nested and then special /j variable is provided to access the counter of the outer loop.

The following has two nested loops with limits of 2. The two counter variables are summed and added to t. When the loop ends t prints 4.

0t! 2(2(/i /j + t + t! )) t .

Conditional code

Mindy's looping mechanism can also be used to execute code conditionally. In Mindy boolean false is represented by 0 and true is represented by 1.

/f(this code will not be executed but skipped)
/t(this code will be execute once)

The following tests if x is less that 5.

3 x!
x 5 < (`true`)

The syntax for a Mindy IF-THEN-ELSE or "if...else" operator in Mindy is and extension of the loop syntax.

boolean (code-block-then) /e (code-block-else)

If the condition is true, then code-block-then is executed. Otherwise, code-block-else is executed.

Here is an example of a "if...else" operator in Mindy:

10 x !
20 y !

x y > ( `x is greater than y` ) /e ( `y is greater than x` )

In this example, the variable x is assigned the value 10 and the variable y is assigned the value 20. The "if...else" operator then checks to see if x is greater than y. If it is, then the string "x is greater than y" is returned. Otherwise, the string "y is greater than x" is returned.

Here is another example of the "if...else" operator in Mindy. This time, instead of creating a string just to print it, the following code conditionally prints text straight to the console.

18 a !

`This person` a 17 > (`can`) /e (`cannot`) `vote`

In this example, the variable a is assigned the value 18. The "if...else" operator then checks to see if age is greater than 17. If it is, then the text "can" is printed to the console. Otherwise, the string "cannot" is printed.

Functions

You can put any code inside : and ; block which tells Mindy to "execute this later".

Functions are stored in variables with uppercase letters. There are 26 variables for storing functions in Mindy and use the uppercase letter A to Z.

The following stores a function in the variable Z.

:Z `hello` 1. 2. 3. ;

Running the function by stored in uppercase Z by referring to it

Z

will print out.

hello 1 2 3

A basic function to square a value.

:F " * ;

The function stored in F duplicates the value on the stack and then multiplies them together.

4 F .

Calling the function with 4 returns 16 which is then printed.

Function with multiple arguments

You can also define functions with multiple arguments. For example:

:F $ . . ;

This function swaps the top two arguments on the stack and then prints them using ..

Calling functions

Functions are called by referring to them

:F * ;
30 20 F .

This code passes the numbers 30 and 20 to a function which multiplies them and returns the result which is then printed.

Using functions

Once you've assigned functions to variables, you can use them in your Mindy code.

Example:

10 A       // prints 10
3 7 B      // prints 10, the sum of 3 and 7

In the first line, we execute the function stored in variable A with the argument 10, which prints 10. In the second line, we execute the function stored in variable B with arguments 3 and 7, which results in 10 being printed (the sum of the two arguments).

Anonymous functions

Mindy code is not restricted to upper case variables. Functions an be declared without a variable(i.e. anonymously) by using the :: operator. A function declared this way puts the address of the function on the stack.

A function at an address can be executed with the /G operator.

This code declares an anonymous function and stores its address in a. This function will increment its argument by 1.

The next line pushs the number 3 on the stack and executes the function in a. The function adds 1 and prints 4 to the console.

:: 1+ ; a!
3 a /G .

Anonymous functions can be stored in arrays and can even be used as a kind of "switch" statement. This code declares an array containing 3 anonymous functions. The next line accesses the array at index 2 and runs it. "two" is printed to the console.

[:: `zero` ; :: `one` ; :: `two` ;] b!
b 2@ /G

Appendices

Using Mindy on the TEC-1

Mindy was designed for for small Z80 based systems but specifically with the small memory configuration of the TEC-1 single board computer. It is only 2K to work with the original TEC-1 and interfaces to the serial interface via a simple adapter.

On initialisation it will present a user prompt ">" followed by a CR and LF. It is now ready to accept commands from the keyboard.

List of operators

Maths Operators

Symbol Description Effect
- 16-bit integer subtraction SUB a b -- c
/ 16-bit by 8-bit division DIV a b -- c
+ 16-bit integer addition ADD a b -- c
* 8-bit by 8-bit integer multiplication MUL a b -- c

Logical Operators

Symbol Description Effect
> 16-bit comparison GT a b -- c
< 16-bit comparison LT a b -- c
= 16 bit comparison EQ a b -- c
& 16-bit bitwise AND a b -- c
| 16-bit bitwise OR a b -- c
^ 16-bit bitwise XOR a b -- c
~ 16-bit bitwise NOT a -- c
/L shift left n n --
/R shift right n n --

Stack Operations

Symbol Description Effect
\ drop the top member of the stack DROP a a -- a
# duplicate the top member of the stack DUP a -- a a
$ swap the top 2 members of the stack SWAP a b -- b a
% over - take the 2nd member of the stack and copy to top of the stack a b -- a b a
/D stack depth -- n

Input & Output Operations

Symbol Description Effect
. print the number on the stack as a decimal a --
, print the number on the stack as a hexadecimal a --
` print the literal string between ` and ` --
/E prints a character to output n --
/K read a char from input -- c
/O output to an I/O port n p --
/I input from a I/O port p -- n
' the following number is in hexadecimal a --
Symbol Description Effect
; end of user definition END
: define a new command DEF
/: define an anonymous command DEF -- adr
/G execute Mindy code at address adr -- ?
/X execute machine code at address adr -- ?

NOTE: is an uppercase letter immediately following operation which is the name of the definition

Loops and conditional execution

Symbol Description Effect
( BEGIN a loop which will repeat n times n --
) END a loop code block --
/W if false break out of loop b --
/e else condition -- b
/i loop counter variable -- n
/j outer loop counter variable -- n

NOTE 1: a loop with a boolean value for a loop limit (i.e. 0 or 1) is a conditionally executed block of code

0(`will not execute`)
1(`will execute`)

NOTE 2: if you follow a code block with /e followed by another code block, this second code block will execute the "else" condition.

0(`will not execute`) /e (`will execute`)
1(`will execute`) /e (`will not execute`)

Memory and Variable Operations

Symbol Description Effect
! STORE a value to memory n adr --
/B toggle byte mode --

Array Operations

Symbol Description Effect
[ begin an array definition --
] end an array definition -- adr
@ get address of array item adr idx -- adr
/S array size adr -- n

System Variables

Symbol Description Effect
/c carry flag variable -- b
/e else condition -- b
/f false -- b
/h heap pointer -- adr
/i loop counter -- n
/j outer loop counter -- n
/k text input buffer pointer -- adr
/p last access pointer -- adr
/r last division remainder -- adr
/s data stack start -- adr
/t true -- b
/u unlimited loop -- n
/z last definition -- char

Miscellaneous

Symbol Description Effect
// comment text, skips reading until end of line --

Utility commands

Symbol Description Effect
/UN prints a CRLF --
/UE edit command char --
/UP print prompt --
/US print stack --

Control keys

Symbol Description
^E edit a definition
^H backspace
^J re-edit
^L list definitions
^P print stack

About

Daughter of MINT

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published