BFLang is designed to be an improved, cleaner version of C. BFLang currently compiles to only 64-bit NASM-compatible assembly for Linux (windows support in future update.)
There are no comments yet
The entrypoint in BF is _start
, so instead of C's main
you have to use _start
Constants/numbers can only be represented as decimal for now, no hexadecimal and no octal.
You have these default types:
int
, equivalent to C'sint32_t
short
, equivalent to C'sint16_t
byte
, equivalent to C'sint8_t
No unsigned yet ;)
Here's an example on how you declare a variable with a default type:
int:some_variable = 0;
There is also structs, which are, for example, defined like this:
PutYourStructNameHere {
int:firstMember;
short:secondMember;
int:thirdMember;
}
Note that structs can only be defined in the top-level of your code.
After you declare a struct, you can use structs as if they are default types.
YOU CAN:
- You can copy a struct instance to another struct instance of the same type. For example:
SomeStruct:x = y;
- You can access a structs members just like how you would in C.
- You can have members of a struct have a struct type.
HOWEVER:
- Structs cannot be the return type of a function
- You cannot cast to a struct, and a struct cannot be casted
First of all, here's an example on how to declare a function with a return type of byte
, that takes in two int
parameters:
byte:SomeFunction(int:x, int:y)
{
}
To return a value from a function, you can use return(...)
(YOU NEED THE PARENTHESES) to return a value, like so:
int:AddOne(int:x)
{
return(x + 1);
}
Also, functions can only be defined in the top-level of your code, just like structs.
References in BF act just like how they would in C++.
You can specify that you want a parameter to be passed by reference, using &
like so:
int:AddOne(&int:toBePassedByReference)
{
toBePassedByReference = toBePassedByReference + 1;
}
Operators are used just like how they're used in C.
-
All operators require that both operands have matching types.
-
The order of operations is right-to-left, but you can use parentheses if necessary.
-
You cannot use structs for any operator, except
=
to copy as shown earlier.
=
+
-
*
/
%
<
>
==
>>
<<
The definitions for them is the same as C.
Conditional operators may only be used in the if
, while
or for
statements.
The if
statement is used like in C, but has a semicolon after its closing bracket. Example:
if (1 < 2)
{
};
The while
loop is used like in C, but has a semicolon after its closing bracket. Example:
while (x > y)
{
};
The for
loop is used like in C, but has a semicolon after its closing bracket, and the first statement is required. Example:
for (int:x = 0;x < 100;x = x + 1)
{
};
Casting only works for integral default types for now, until I implement floating-point types. Here's how to cast a short to an int for example, which should be self-explanatory:
byte:someByte = 120;
int:final = cast(int:someByte);
So far, there is no input, but there is a handy print
function which takes in a constant or a variable of type byte
, short
or int
, and prints it as a single character.
Example:
print(10);
In this example, it would print a newline, since the decimal ASCII code for a newline is 10.
byte:IsPrime(int:x)
{
for (int:i = 2;i < x;i = i + 1)
{
if ((x % i) == 0)
{
return(0);
};
};
return(1);
}
_start()
{
int:scale = 4;
for (int:i = 1;i < scale + 1;i = i + 1)
{
for (int:j = 0;j < i;j = j + 1)
{
print(48 + j);
};
print(10);
};
}
vec2 {
int:x;
int:y;
}
int:vecSub(&vec2:z, vec2:w)
{
z.x = z.x - w.x;
z.y = z.y - w.y;
}
int:vecDot(vec2:x, vec2:y)
{
int:mX = (x.x * y.x) / 256;
int:mY = (x.y * y.y) / 256;
return(mX + mY);
}
int:barycentric(vec2:p0, vec2:p1, vec2:p2, vec2:p, &int:u, &int:v, &int:w)
{
vec2:v0 = p1;
vec2:v1 = p2;
vec2:v2 = p;
vecSub(v0, p0);
vecSub(v1, p0);
vecSub(v2, p0);
int:d00 = vecDot(v0, v0);
int:d01 = vecDot(v0, v1);
int:d11 = vecDot(v1, v1);
int:d20 = vecDot(v2, v0);
int:d21 = vecDot(v2, v1);
int:denom = (((d00 * d11) / 256) - ((d01 * d01) / 256));
u = (d11 * d20) / 256;
u = u - ((d01 * d21) / 256);
u = (u * 256) / denom;
v = (d00 * d21) >> 8;
v = v - ((d01 * d20) / 256);
v = (v * 256) / denom;
w = (((1 * 256) - u) - v);
}
int:_start()
{
vec2:p0;
vec2:p1;
vec2:p2;
vec2:p;
p0.x = 4 << 8;
p0.y = 4 << 8;
p1.x = 16 << 8;
p1.y = 4 << 8;
p2.x = 6 << 8;
p2.y = 16 << 8;
for (int:i = 0;i < 20;i = i + 1)
{
for (int:j = 0;j < 20;j = j + 1)
{
int:u = 0;
int:v = 0;
int:w = 0;
p.x = j << 8;
p.y = i << 8;
barycentric(p0, p1, p2, p, u, v, w);
if (u > 0)
{
if (v > 0)
{
if ((u + v) < (1 << 8))
{
print(49);
};
if ((u + v) > ((1 << 8) - 1))
{
print(48);
};
};
if (v < 1)
{
print(48);
};
};
if (u < 1)
{
print(48);
};
};
print(10);
};
}
int:cos(int:x)
{
int:modX = x % (1 << 10);
int:modX2 = x % (2 << 10);
int:result = 4 * (modX - ((modX * modX) >> 10));
if (modX2 > (1 << 10))
{
return(result * ~1);
};
return(result);
}
int:sin(int:x)
{
x = x + (3 << 9);
return(cos(x););
}
int:_start()
{
int[1600]:framebuff;
int[1600]:depthbuff;
int:A = 0;
int:B = 0;
while (1 < 2)
{
for (int:__Count = 0;__Count < 1600;__Count = __Count + 1)
{
framebuff[__Count] = 0;
depthbuff[__Count] = ~1000000;
};
for (int:theta = 0;theta < 2000;theta = theta + 4)
{
for (int:phi = 0;phi < 2000;phi = phi + 4)
{
int:nx1 = cos(phi);
int:ny1 = sin(phi);
int:y1 = (ny1 * 5) + (10 << 10);
int:z1 = nx1 * 5;
int:x1 = 0;
int:rx1 = ((x1 * cos(theta)) >> 10) - ((y1 * sin(theta)) >> 10);
int:ry1 = ((x1 * sin(theta)) >> 10) + ((y1 * cos(theta)) >> 10);
ny1 = ((ny1 * cos(theta)) >> 10);
int:ry2 = ((z1 * sin(A)) >> 10) + ((ry1 * cos(A)) >> 10);
int:rz2 = ((z1 * cos(A)) >> 10) - ((ry1 * sin(A)) >> 10);
int:ry3 = ((rx1 * sin(B)) >> 10) + ((ry2 * cos(B)) >> 10);
int:rx3 = ((rx1 * cos(B)) >> 10) - ((ry2 * sin(B)) >> 10);
if (depthbuff[(20 + rx3 >> 10) + 40 * (20 + ry3 >> 10)] < rz2)
{
depthbuff[(20 + rx3 >> 10) + 40 * (20 + ry3 >> 10)] = rz2;
if (ny1 < 0)
{
ny1 = 1 << 7;
};
framebuff[(20 + rx3 >> 10) + 40 * (20 + ry3 >> 10)] = ny1 >> 7;
};
};
};
for (int:y = 0;y < 40;y = y + 1)
{
for (int:x = 0;x < 40;x = x + 1)
{
if (framebuff[x + y * 40] > 1)
{
print(48 + framebuff[x + y * 40]);
};
if (framebuff[x + y * 40] == 0)
{
print(32);
};
if (framebuff[x + y * 40] == 1)
{
print(95);
};
};
print(10);
};
A = A + 40;
B = B + 16;
print(10);
};
}
vec3 {
float:x;
float:y;
}
int:_start()
{
vec3:p0;
vec3:p1;
vec3:p2;
p0.x = cast(float:10);
p0.y = cast(float:10);
p1.x = cast(float:90);
p1.y = cast(float:40);
p2.x = cast(float:50);
p2.y = cast(float:90);
int[10000]:framebuff;
float:s0 = (p2.x - p0.x) / (p2.y - p0.y);
float:s1 = (p1.x - p0.x) / (p1.y - p0.y);
float:x0 = p0.x;
float:x1 = p0.x;
float:y = p0.y;
while (cast(int:y) < cast(int:p1.y))
{
int:startX0 = cast(int:x0);
int:startX1 = cast(int:x1);
if (startX1 < startX0)
{
int:temp = startX0;
startX0 = startX1;
startX1 = temp;
};
while (startX0 < startX1 + 1)
{
framebuff[startX0 + 100 * cast(int:y)] = 1;
startX0 = startX0 + 1;
};
x0 = x0 + s0;
x1 = x1 + s1;
y = y + cast(float:1);
};
s1 = (p2.x - p1.x) / (p2.y - p1.y);
while (cast(int:y) < cast(int:p2.y) + 1)
{
int:startX0 = cast(int:x0);
int:startX1 = cast(int:x1);
if (startX1 < startX0)
{
int:temp = startX0;
startX0 = startX1;
startX1 = temp;
};
while (startX0 < startX1 + 1)
{
framebuff[startX0 + 100 * cast(int:y)] = 1;
startX0 = startX0 + 1;
};
x0 = x0 + s0;
x1 = x1 + s1;
y = y + cast(float:1);
};
for (int:i = 0;i < 100;i = i + 1)
{
for (int:j = 0;j < 100;j = j + 1)
{
print(48 + framebuff[j + 100 * i]);
};
print(10);
};
}