Aubergine, 225 bytes ( 222 bytes with error )
:Ba=aA-A1=ba-b1:BA-Ai+Ai+a1=bi=oA+a1:bA+a1+iA=a1-ii? \0B*Fizz\0\0FBuzz\0[-aa=aA-aA+ai-ai=bi-bi+iA=ab-a1=oA=oB=bi-bi+B1+b1=oB+b1-aa:aB+ii=a1=aA+A1+A1-aa=aA-a1-a1=bA-a1-bA=Ab-ib-a1-AA-a1-AA-aa-a1-A1-a1=bA-a1-Ab-a1+A1-a1-iAo01
* four \0
mean NUL(ASCII 0) character
Try it online!
The equivalent pseudo code in C is like below;
#include <stdio.h>
#include <stdint.h>
#define I(x) ((intptr_t)&&x)
#define P(x) *(void*)(x)
static void nop(void) {}
int main(void) {
intptr_t
*cp,*cpt,t,p,
pvars0[] =
{ I(Tj3)-I(Tj1), I(Tj2)-I(Tj1), I(Tj2)-I(Tj1), 0, I(Tc1)-I(Tj3),
I(Lb), 3, 'F', 'i', 'z', 'z', 0, I(Lb)-I(Tx2), },
pvars1[] =
{ I(Lj), 5, 'B', 'u', 'z', 'z', 0, I(Lc)-I(Tx2), },
dvars[] = { I(Tc2)-I(Tj3), '0', '1', '\n', 10, },
*pbase[] = { &pvars0[6], &pvars1[1] },
*dbase3=&dvars[2], *dbase1=&dvars[4];
int i=0;
Lx: // Fizz/Buzz print ( i=0 for Fizz, i=1 for Buzz )
// decrement counter
cp = pbase[i];
*cp-=1;
if ( *cp!=0 ) goto P(*(cp-1)); // skip printing and jump to Lb/Jj
*cp+=3; // restore the counter to 3 ( add more 2 for Buzz in Lc )
cp+=1;
p=I(Tx1);
Tx1: // putchar loop
putchar(*cp);
cp+=1;
if ( *cp!=0 ) goto P(p); // jump to Tx1
goto P(I(Tx2)+*(cp+1)); // jump to Lb/Lc
Tx2:
Lb: // Buzz print
i=1;
goto Lx;
Lj: // number print and post process
cp=pbase[0];
// select &pvars[0] thru &pvars[2] as jump offset
cp-=*cp;
cp-=3;
cpt=dbase3;
goto P( I(Tj1)+*cp ); // jump to Tj3(when Fizz) or Tj1/Tj2
Tj1: // print the upper digit
cp=cpt-1;
putchar(*cp);
Tj2: // print the lower digit
putchar(*cpt);
Tj3: // print a new line and increment the lower digit
cp=dbase3;
*cp+=1;
cp+=1;
putchar(*cp);
cp+=1;
i=0;
if ( *cp!=0 ) goto Lx; // next iteration
return 0; // exit
Lc: // after Buzz
// add more 2 to the Buzz counter
cp=pbase[1];
*cp+=2;
// switch pvars0[3] ( jump offset ) between 0 and pvars0[4]
cp=pbase[0]-2;
t=*cp;
cp-=1;
t-=*cp;
*cp=t;
goto P( I(Tc1)-t ); // jump to Tc1/Tj3
Tc1: // carry up
// reset jump offsets in pvars[1],pvars[2]
// so that the 1st "goto" in Lj jump to Tj1 instead of Tj2
cp-=1;
*cp=0;
cp-=1;
*cp=0;
// decrement global loop counter
cp=dbase1;
*cp-=1;
// decrease the lower digit by 10
cp-=1;
t=*cp;
cp-=1;
*cp-=t;
// increment the upper digit
cp-=1;
*cp+=1;
cp-=1;
goto P(I(Tc2)-*cp); // jump to Tj3
Tc2:
nop(); // not reached
}
Each code block handles;
- Label Lx
Print Fizz ( when i=0 ) or Buzz ( when i=1 ) if n
is the multiple of 3 or 5.
- Label Lb
Just jump to Lx after setting i=1.
- Label Lj
Print n
itself ( when Fizz or Buzz are not printed ) and do post-process.
- Label Lc
Carry-up operation.
In Aubergine code, each address range corresponds to;
- 0 thru 2
The 1st instruction :Ba
has no effect, but stores pbase[]
.
pbase[0]
is ord(':')
=58, pbase[1]
is ord('B')
=66.
- 3 thru 50
The code block with label Lx.
Lx: =aA-A1=ba-b1:BA-Ai+Ai+a1=bi=oA+a1:bA+a1+iA
, Tx1: =a1-ii
* set i=0 ( -ii
) to implement goto Lx
- 51
A blank area.
- 52 thru 72
Stores pvars0[]
and pvars1[]
- 73 thru 135
The code block with Label Lj.
Lj: -aa=aA-aA+ai-ai=bi-bi+iA
, Tj1: =ab-a1=oA
, Tj2: =oB
, TJ3: =bi-bi+B1+b1=oB+b1-aa:aB+ii
The last instruction +ii
jumps to an address out of range to stop the program.
- 136 thru 219
The code block with Label Lc.
Lc: =a1=aA+A1+A1-aa=aA-a1-a1=bA-a1-bA=Ab-ib
, Tc1: -a1-AA-a1-AA-aa-a1-A1-a1=bA-a1-Ab-a1+A1-a1-iA
- 220 thru 224
Stores dvars[]
This area is accessed via minus addresses such as dbase1=-1 or dbase3=-3.
The 222 bytes version, which is shown below, outputs some error.
:Ba=aA-A1=ba-b1:BA-Ai+Ai+a1=bi=oA+a1:bA+a1+iA=a1-ii? \0Q*Fizz\0\0\x9aBuzz\0=a1=aA+A1+A1-aa=aA-a1-a1=bA-a1-bA=Ab+ib-a1-AA-a1-AA-aa-a1-A1-a1=bA-a1-Ab-a1+A1-a1+iA-aa=aA-aA+ai-ai=bi-bi+iA=ab-a1=oA=oB=bi-bi+B1+b1=oB+b1-aa:aB$01
* \0
is NUL, and \x9a
is a byte 232
This code cannot be run on TIO because TIO requires codes to be UTF-8 clean. ( a single \x9a
is not valid as UTF-8 byte sequence )
The differences between 225B version and this 222B version are;
- Exchange the position in code of the Lj code block and the Lc code block.
- Replace relative backward jump instructions
-ib
, -iA
in Lc code block to forward jumps +ib
, `+iA.
- Omit the instruction
+ii
, which works to stopping the code, from Lj code block.
* The code stops in error when the instruction pointer points the dvars
area just after the Lj code block.