Skip to content

Instantly share code, notes, and snippets.

@Johann150
Last active February 24, 2020 21:28
Show Gist options
  • Save Johann150/70d6f90531ca06af3965057b81bc3517 to your computer and use it in GitHub Desktop.
Save Johann150/70d6f90531ca06af3965057b81bc3517 to your computer and use it in GitHub Desktop.
https://esolangs.org/wiki/BTree implementation in C89 aka C90 aka ANSI C
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<math.h>
#include<string.h>
#include<stdint.h>
void skip_whitespace(FILE* f){
char c;
while(!feof(f)&&isspace(c=getc(f)));
if(!feof(f)){
/* this will always take one character too much, so put it back */
ungetc(c,f);
}
}
/* returns the number of nodes read */
int parse(FILE* f,char*** p_tree){
int nodes=0;
char** tree=NULL;
while(!feof(f)){
{/* scope the 'new' variable */
char** new=realloc(tree,(++nodes)*sizeof(char*));
if(NULL==new){
perror("allocating new node");
goto parse_error;
}else{
tree=new;
}
}
tree[nodes-1]=calloc(1,sizeof(char));
/* error checks */
if(NULL==tree[nodes-1]){
perror("allocating new buffer");
goto parse_error;
}
int i=1;
int again=1;
while(again){
skip_whitespace(f);/* ignore whitespace */
if(feof(f)) break;
/* assume this is just a normal node */
again=0;
tree[nodes-1][i-1]=getc(f);
/* check assumption and make corretions if needed */
switch(tree[nodes-1][i-1]){
case '{':
/* skip comment */
while(!feof(f)&&getc(f)!='}');
again=1;/* did not read a node yet */
break;
case ';':{
void* new=realloc(tree[nodes-1],++i*sizeof(char));
if(NULL==new){
perror("scanning node");
goto parse_error;
}else{
/* reallocation was successfull */
tree[nodes-1]=new;
skip_whitespace(f);/* ignore whitespace */
if(feof(stdin)){
fputs("unexpected EOF\n",stderr);
goto parse_error;
}
tree[nodes-1][i-2]=getc(f);/* index i-1 to adjust for the reallocation */
again=1;/* semicolon means there is more coming */
}
break;
}
default:
i++;
break;
}
}
skip_whitespace(f);/* so we do not have to allocate an unnecessary node */
}
*p_tree=tree;
return nodes;
parse_error:/* do some cleanup before returning */
free(tree);/* the tree scanned this far is unusable, so trash it */
return 0;
}
typedef struct{
int_fast8_t* val;
unsigned cap,len;
} deque;
int resize(deque* d,unsigned size){
if(size==d->cap) return 1;
int_fast8_t* new=realloc(d->val,size*sizeof(int_fast8_t));
if(NULL==new&&size>0){
perror("allocating deque");
return 0;
}else{
d->val=new;
d->cap=size;
return 1;
}
}
void run(char** n,int size){
int_fast8_t A=0,B=0;
deque d;
d.val=NULL;
d.cap=0;
d.len=0;
resize(&d,8);
int current=0;
while(current<size&&current>=0){
int i;
for(i=0;i<strlen(n[current]);i++){
switch(n[current][i]){
case '0':/* Set A to 0. */
A=0;
break;
case '-':/* Set A to -1. */
A=-1;
break;
case '+':/* Set A to +1. */
A=1;
break;
case '^':{/* Exchange the content of A and B. */
int_fast8_t temp=B;
B=A;
A=temp;
break;
}
case 'a':/* Insert the content of A at the end of the deque. */
d.val[d.len++]=A;
if(d.len==d.cap&&!resize(&d,d.cap+8)){
/* deque is full, but resizing failed */
return;
}
break;
case 'A':/* Remove the element at the start of the deque and put it in B, or 0 if the deque is empty. */
if(0==d.len){
B=0;
}else{
B=d.val[0];
/* remove first element, other elements have to be shuffled up */
memmove(d.val,d.val+1,--d.len);
}
break;
case 'b':/* Insert the content of A at the start of the deque. */
memmove(d.val+1,d.val,d.len++);/* move all elements of deque one element up */
d.val[0]=A;/* insert A accumulator */
break;
case 'B':/* Remove the element at the end of the deque and put it in B, or 0 if the deque is empty. */
if(0==d.len){
B=0;
}else{
B=d.val[--d.len];
}
break;
case '&':/* Set A to the minimum of A and B (ternary AND). */
if(B<A)
A=B;
break;
case '|':/* Set A to the maximum of A and B (ternary OR). */
if(B>A)
A=B;
break;
case '=':/* Set A to 1 if A and B are equal, else -1. */
if(A==B){
A=1;
}else{
A=-1;
}
break;
case '!':/* Multiply A by -1 (ternary NOT). */
A*=-1;
break;
case 'i':{/* Input a ternary number (-, 0 or +) and put it in A. */
char c;
do{
c=getchar();
}while(c!='-'&&c!='+'&&c!='0');
switch(c){
case '0':
A=0;
break;
case '-':
A=-1;
break;
case '+':
A=1;
break;
}
break;
}
case 'o':/* Output the content of A (-, 0 or +). */
if(A==0){
printf("0");
}else if(A<0){
printf("-");
}else{/* A<0 */
printf("+");
}
break;
}
}
/* select next node */
if(A==0){
/* parent */
current=(current-1)>>1;/* same as integer division by 2 */
}else{
current=(current+1)*2-(-1==A);/* select left if A==-1, else select right */
}
}
}
int main(int argc,char** argv){
if(argc<2){
fputs("missing file argument\n",stderr);
return EXIT_FAILURE;
}else{
FILE* f=fopen(argv[1],"r");
if(NULL==f){
perror("opening file");
return EXIT_FAILURE;
}else{
char** n=NULL;
int nodes=parse(f,&n);
run(n,nodes);
}
}
return EXIT_SUCCESS;
}
.PHONY: all run
all: BTree
run: all truth.btr
./BTree truth.btr
BTree: BTree.c
gcc BTree.c -lm -o BTree -ggdb -ansi
{ BTree truth machine }
{ "-" is 0 and "+" is 1 }
;i;aA
o ;^;o;^-
. . 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment