elikaski / BF-it

A C-like language to Brainfuck compiler, written in Python
MIT License
120 stars 11 forks source link

16-bit ints #26

Open NeeEoo opened 3 years ago

NeeEoo commented 3 years ago

This would probably be a long term thing.

A 16-bit is stored as 2 cells since this is an 8-bit compiler. The 16-bit max value is 65535.

A 16-bit int is also called a short.

The number 512 would be stored as 2 0. The number 12941 would be stored as 50 141.

The compiler would have to keep track of the type of the variable. It would also need to keep track of the type of the variable that is going to be assigned.

Bools and chars should still be treated as ints

This would also mean we would have to implement 2 versions of every algorithm since it would have to support shorts.

Casting an 8-bit int to a 16-bit int could be hard but it could be done by making a copy of the 8-bit number and setting the lowest cell of the short to the copy.

A short is defined like this

short x = 1241;

Converting from an int to a short could be implemented as implicit casting but it would require more work from the compiler.

int x = 65;
short y = x;

But it could also be implemented this way.

int x = 65;
short y = (short) x;

But there is a problem. What if we do:

short x = 6135;
if(x > 31) {
}

The number literal 31 is an int, we would need a short.

The compiler would also need support for short temp variables for copying.

Since printing only supports 8-bit cells in an 8-bit environment, we should print the lowest cell, and reading a char would only fill the lowest cell if it is defined like this:

short ch = readchar();
// or
short ch = (short) readchar();

The library function readint would work with shorts but it would need some changes.

Since this would also need to support arrays it would need to do some extra math to get the index.

1 dimensional array:

short arr[5]; // Makes an array that is 10 (5 * 2) cells large
// 0 0, 0 0, 0 0, 0 0, 0 0
arr[2] = 2834; // Sets the 4th and 5th cells. (0-indexed)
// real index = 2 * 2 + 1 = 5
// The real index points to the lowest cell of the short.

multidimensional array:

short arr[5][5]; // Makes an array that is 50 (5 * 5 * 2) cells large
arr[3][2] = 2834; // Sets the 34th and 35th cells. (0-indexed)
// real index = ((3*5) + 2) * 2 + 1 = 35
// The real index points to the lowest cell of the short.

Implementation:

The pseudo code of shows some ways to implement some algorithms that would use shorts.

These algorithms only support shorts and not a mix of shorts and ints.

But there are some algorithms where I provided with a mix of shorts and ints

Basic Math:

# x is the value before the operator
# x = short

increment: # x++;
    x.low += 1
    if x.low == 0: # (overflow from 255 to 0)
        x.high += 1

decrement: # x--;
    x.low -= 1
    if x.low == -1: # (255)
        x.high -= 1

add: (a) # a = short
    while a.high != 0 or a.low != 0:
        a.low -= 1
        if a.low == -1:
            a.high -= 1

        x.low += 1
        if x.low == 0:
            x.high += 1

sub: (a) # a = short
    while a.high != 0 or a.low != 0:
        a.low -= 1
        if a.low == -1:
            a.high -= 1

        x.low -= 1
        if x.low == -1:
            x.high -= 1

add: (a) # a = int
    while a != 0:
        a -= 1
        x.low += 1
        if x.low == 0:
            x.high += 1

sub: (a) # a = int
    while a != 0:
        a -= 1
        x.low -= 1
        if x.low == -1:
            x.high -= 1

Multiplication could be implemented in 2 ways: Using the add code, or making a new algorithm.

Relational Operators:

To make a mixed version you could probably just replace b.high with 0

# Tested and it works (1h taken)
>: (a, b) # This could probably be optimized
    if a.high > b.high:
        return True
    else:
        if b.high > a.high:
            return False
        else: # a.high and b.high are equal
            return a.low > b.low

# Tested and it works (1h taken)
<: (a, b) # This could probably be optimized
    if a.high < b.high:
        return True
    else:
        if b.high < a.high:
            return False
        else: # a.high and b.high are equal
            return a.low < b.low

# Tested and it works (2h 12m taken)
>=: (a, b) # This could probably be optimized
    if a.high == b.high:
        return a.low >= b.low
    else:
        if a.high > b.high:
            return True
        else:
            if b.high > a.high:
                return False
            else:
                return a.low > b.low

# Tested and it works (2h 12m taken)
<=: (a, b) # This could probably be optimized
    if a.high < b.high:
        return True
    else:
        if b.high < a.high:
            return False
        else:
            return a.low <= b.low

# Tested and it works (2h 12m taken)
!=: (a, b)
    if a.high != b.high:
        return True
    else:
        return a.low != b.low

# Tested and it works (2h 12m taken)
==: (a, b) # a = short b = short
    if a.high != b.high:
        return False
    else:
        return a.low == b.low

==: (a, b) # a = short b = int
    if a.high != 0:
        return False
    else:
        return a.low == b.low

==: (a, b) # a = int b = short
    if b.high != 0:
        return False
    else:
        return a.low == b.low
elikaski commented 3 years ago

That's a good idea But I fear it will be a nightmare to implement 😢

In the meantime, what do you say about making the interpreter have 16-bit mode? Something like a flag to the interpreter to treat data cells as 16-bit. (Can be any arbitrary number of bits as well I guess)

NeeEoo commented 3 years ago

If we implement #30 i might try to make this. Since the framework for custom sized variables would exist then

abhra2020-smart commented 3 years ago

elikaski

That's a good idea But I fear it will be a nightmare to implement 😢

In the meantime, what do you say about making the interpreter have 16-bit mode? Something like a flag to the interpreter to treat data cells as 16-bit. (Can be any arbitrary number of bits as well I guess)

This pr may be what you suggested: #66