Assemble ud-chain and use that for register allocation

This commit is contained in:
Mid 2023-08-31 15:26:08 +03:00
parent 62c5a0ff47
commit 5666568c1c
8 changed files with 384 additions and 113 deletions

View File

@ -31,3 +31,33 @@ int ast_expression_equal(AST *a, AST *b) {
return 0; return 0;
} }
// ... Ew
int ast_stmt_is_after(const AST *chunk, const AST *s1, const AST *s2) {
const AST *s = chunk->chunk.statementFirst;
while(s) {
if(s == s1) {
return 0;
}
if(s == s2) {
return 1;
}
if(s->nodeKind == AST_STMT_IF) {
int i = ast_stmt_is_after(s->stmtIf.then, s1, s2);
if(i != -1) {
return i;
}
} else if(s->nodeKind == AST_STMT_LOOP) {
int i = ast_stmt_is_after(s->stmtLoop.body, s1, s2);
if(i != -1) {
return i;
}
}
s = s->statement.next;
}
return -1;
}

View File

@ -168,7 +168,7 @@ typedef struct {
typedef struct { typedef struct {
ASTStmt; ASTStmt;
ASTChunk *body; union AST *body;
} ASTStmtLoop; } ASTStmtLoop;
typedef struct { typedef struct {
@ -254,4 +254,6 @@ typedef union AST {
AST *ast_expression_optimize(AST*); AST *ast_expression_optimize(AST*);
int ast_expression_equal(AST*, AST*); int ast_expression_equal(AST*, AST*);
int ast_stmt_is_after(const AST *chunk, const AST *s1, const AST *s2);
#endif #endif

View File

@ -99,6 +99,8 @@ static const char *xop(AST *e) {
xv(e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing)); xv(e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing));
} else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_REF && e->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL) { } else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_REF && e->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL) {
snprintf(ret, XOPBUFSZ, "%s", e->exprUnOp.operand->exprVar.thing->data.symbol.name); snprintf(ret, XOPBUFSZ, "%s", e->exprUnOp.operand->exprVar.thing->data.symbol.name);
} else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF && e->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_VAR) {
snprintf(ret, XOPBUFSZ, "[%s]", xv(e->exprUnOp.operand->exprVar.thing));
} else { } else {
return NULL; return NULL;
} }
@ -265,9 +267,15 @@ void cg_go(AST *a) {
VarTableEntry *v2 = vars[v2i]; VarTableEntry *v2 = vars[v2i];
/* 1D intersection test */ /* 1D intersection test */
if((v1->data.var.start >= v2->data.var.start && v1->data.var.start <= v2->data.var.end) // if((v1->data.var.start >= v2->data.var.start && v1->data.var.start <= v2->data.var.end)
|| (v1->data.var.end >= v2->data.var.start && v1->data.var.end <= v2->data.var.end)) { // || (v1->data.var.end >= v2->data.var.start && v1->data.var.end <= v2->data.var.end)) {
if(
(ast_stmt_is_after(a, v1->data.var.usedefFirst->stmt, v2->data.var.usedefFirst->stmt) == 1
&& ast_stmt_is_after(a, v2->data.var.usedefLast->stmt, v1->data.var.usedefFirst->stmt) == 1)
||
(ast_stmt_is_after(a, v1->data.var.usedefLast->stmt, v2->data.var.usedefFirst->stmt) == 1
&& ast_stmt_is_after(a, v2->data.var.usedefLast->stmt, v1->data.var.usedefLast->stmt) == 1)
) {
VarTableEntry *min = v1 < v2 ? v1 : v2; VarTableEntry *min = v1 < v2 ? v1 : v2;
VarTableEntry *max = v1 < v2 ? v2 : v1; VarTableEntry *max = v1 < v2 ? v2 : v1;

View File

@ -6,26 +6,8 @@
// But CP is NECESSARY, otherwise it creates too many variables // But CP is NECESSARY, otherwise it creates too many variables
// that are unable to be coalesced by the regallocator // that are unable to be coalesced by the regallocator
static void recalc_lifespan(VarTableEntry *vte) {
assert(vte->kind == VARTABLEENTRY_VAR);
size_t start = 0xFFFFFFFF, end = 0;
UseDef *ud = vte->data.var.usedefFirst;
while(ud) {
if(ud->t < start) start = ud->t;
if(ud->t > end) end = ud->t;
ud = ud->next;
}
vte->data.var.start = start;
vte->data.var.end = end;
}
void optim_chunk(ASTChunk *chu) { void optim_chunk(ASTChunk *chu) {
AST *s = chu->statementFirst, *sPrev = NULL; /*AST *s = chu->statementFirst, *sPrev = NULL;
while(s) { while(s) {
if(s->nodeKind == AST_STMT_ASSIGN && s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_VAR) { if(s->nodeKind == AST_STMT_ASSIGN && s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_VAR) {
VarTableEntry *dst = ((AST*) s->stmtAssign.what)->exprVar.thing; VarTableEntry *dst = ((AST*) s->stmtAssign.what)->exprVar.thing;
@ -89,5 +71,5 @@ void optim_chunk(ASTChunk *chu) {
copypropfail: copypropfail:
sPrev = s; sPrev = s;
s = s->statement.next; s = s->statement.next;
} }*/
} }

View File

@ -9,17 +9,26 @@
#include<stdint.h> #include<stdint.h>
#include<signal.h> #include<signal.h>
typedef struct {
UseDef ud;
VarTableEntry *to;
} UseDefToAdd;
typedef struct { typedef struct {
Token *tokens; Token *tokens;
ssize_t i; ssize_t i;
size_t t;
VarTable *scope; VarTable *scope;
// Used to coalesce all scopes into one after parsing, to perform global register allocation
ASTChunk *topLevel;
// Used by pushstat to add statements
ASTChunk *currentChunk; ASTChunk *currentChunk;
ASTChunk *topLevel; // Used by pushstmt to assemble use-def chain
size_t udsToAddCount;
UseDefToAdd *udsToAdd;
} Parser; } Parser;
static Token get(Parser *P) { static Token get(Parser *P) {
@ -59,6 +68,23 @@ static int maybe(Parser *P, TokenKind t) {
} }
static void pushstat(Parser *P, void *a) { static void pushstat(Parser *P, void *a) {
for(size_t i = 0; i < P->udsToAddCount; i++) {
VarTableEntry *to = P->udsToAdd[i].to;
UseDef *ud = malloc(sizeof(*ud));
memcpy(ud, &P->udsToAdd[i].ud, sizeof(*ud));
ud->stmt = a;
if(to->data.var.usedefFirst) {
to->data.var.usedefLast->next = ud;
to->data.var.usedefLast = ud;
} else {
to->data.var.usedefFirst = to->data.var.usedefLast = ud;
}
}
P->udsToAddCount = 0;
if(P->currentChunk->statementFirst) { if(P->currentChunk->statementFirst) {
P->currentChunk->statementLast->statement.next = a; P->currentChunk->statementLast->statement.next = a;
P->currentChunk->statementLast = a; P->currentChunk->statementLast = a;
@ -86,15 +112,31 @@ static ASTExprPrimitive *parse_prim(Parser *P) {
return ret; return ret;
} }
static AST *exprvar(Parser *P, VarTableEntry *v) { static void newusedef(Parser *P, VarTableEntry *v, AST *expr) {
if(v->kind == VARTABLEENTRY_VAR) { for(size_t i = 0; i < v->data.var.reachingDefs->defCount; i++) {
v->data.var.end = P->t; P->udsToAdd = realloc(P->udsToAdd, sizeof(*P->udsToAdd) * (++P->udsToAddCount));
P->udsToAdd[P->udsToAddCount - 1] = (UseDefToAdd) {
.ud = {
.def = v->data.var.reachingDefs->defs[i],
.use = expr,
.stmt = NULL, // set by pushstmt
.next = NULL,
},
.to = v
};
} }
}
static AST *exprvar(Parser *P, VarTableEntry *v) {
AST *a = malloc(sizeof(ASTExprVar)); AST *a = malloc(sizeof(ASTExprVar));
a->nodeKind = AST_EXPR_VAR; a->nodeKind = AST_EXPR_VAR;
a->exprVar.type = v->type; a->exprVar.type = v->type;
a->exprVar.thing = v; a->exprVar.thing = v;
if(v->kind == VARTABLEENTRY_VAR) {
newusedef(P, v, a);
}
return a; return a;
} }
@ -318,28 +360,6 @@ AST *nct_parse_expression(Parser *P, int lOP) {
stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Invalid combination of operator and operand types."); stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Invalid combination of operator and operand types.");
} }
if(0) if(operand->nodeKind == AST_EXPR_PRIMITIVE) {
VarTableEntry *thing = malloc(sizeof(*thing));
thing->type = operand->expression.type;
thing->kind = VARTABLEENTRY_VAR;
thing->data.var.start = thing->data.var.end = P->t;
P->topLevel->vars = realloc(P->topLevel->vars, sizeof(*P->topLevel->vars) * (P->topLevel->varCount + 1));
P->topLevel->vars[P->topLevel->varCount++] = thing;
AST *decl = malloc(sizeof(ASTStmtDecl));
decl->nodeKind = AST_STMT_DECL;
decl->stmtDecl.thing = thing;
decl->stmtDecl.expression = operand;
pushstat(P, decl);
AST *operand2 = malloc(sizeof(ASTExprVar));
operand2->nodeKind = AST_EXPR_VAR;
operand2->expression.type = operand->expression.type;
operand2->exprVar.thing = thing;
operand = operand2;
}
astop->operands[1] = operand; astop->operands[1] = operand;
if(!astop->type) { if(!astop->type) {
@ -541,36 +561,38 @@ static AST *parse_declaration(Parser *P) {
} else { } else {
entry = calloc(sizeof(*entry), 1); entry = calloc(sizeof(*entry), 1);
entry->type = type; entry->type = type;
vartable_set(P->scope, name.content, entry);
} }
ASTStmtDecl *ret = malloc(sizeof(*ret)); AST *ret = NULL;
ret->nodeKind = AST_STMT_DECL;
ret->thing = entry;
ret->next = NULL;
if(maybe(P, TOKEN_EQUALS)) { if(maybe(P, TOKEN_EQUALS) || (peek(P, 0).type == TOKEN_SEMICOLON && !isExternal && !isLocal)) {
if(isLocal || isExternal) { /* Impossible, error. */ /*if(isExternal || isLocal) {
fputs("'local' and 'extern' keywords are to be used for symbol declaration only.\n", stderr); fputs("'local' and 'extern' keywords are to be used for symbol declaration only.\n", stderr);
abort(); abort();
return NULL; return NULL;
} }*/
entry->kind = VARTABLEENTRY_VAR; entry->kind = VARTABLEENTRY_VAR;
entry->data.var.start = entry->data.var.end = P->t;
entry->data.var.priority = 1; entry->data.var.priority = 1;
ret->expression = NULL; ASTStmtAssign *assign = malloc(sizeof(*assign));
pushstat(P, ret);
AST *assign = malloc(sizeof(ASTStmtAssign));
assign->nodeKind = AST_STMT_ASSIGN; assign->nodeKind = AST_STMT_ASSIGN;
assign->stmtAssign.what = exprvar(P, entry);
assign->stmtAssign.to = nct_parse_expression(P, 0);
ret = assign; entry->data.var.reachingDefs = reachingdefs_push(NULL);
} else if(maybe(P, TOKEN_COLON)) { reachingdefs_set(entry->data.var.reachingDefs, (AST*) assign);
assign->what = exprvar(P, entry);
assign->to = peek(P, 0).type == TOKEN_SEMICOLON ? NULL : nct_parse_expression(P, 0);
ret = (AST*) assign;
} else {
ASTStmtDecl *decl = malloc(sizeof(*ret));
decl->nodeKind = AST_STMT_DECL;
decl->thing = entry;
decl->next = NULL;
if(maybe(P, TOKEN_COLON)) {
if(isExternal) { if(isExternal) {
fputs("External symbols may not be defined.\n", stderr); fputs("External symbols may not be defined.\n", stderr);
abort(); abort();
@ -582,9 +604,9 @@ static AST *parse_declaration(Parser *P) {
entry->data.symbol.isExternal = isExternal; entry->data.symbol.isExternal = isExternal;
entry->data.symbol.name = name.content; entry->data.symbol.name = name.content;
ret->expression = nct_cast_expr(nct_parse_expression(P, 0), type); decl->expression = nct_cast_expr(nct_parse_expression(P, 0), type);
if(ret->expression) { if(decl->expression) {
//if(ret->expression->expression.constantType == EXPRESSION_NOT_CONSTANT) { //if(ret->expression->expression.constantType == EXPRESSION_NOT_CONSTANT) {
// stahp(1, 4142, "Symbol declaration may contain constant expressions only."); // stahp(1, 4142, "Symbol declaration may contain constant expressions only.");
//} //}
@ -595,16 +617,17 @@ static AST *parse_declaration(Parser *P) {
entry->data.symbol.isExternal = isExternal; entry->data.symbol.isExternal = isExternal;
entry->data.symbol.name = name.content; entry->data.symbol.name = name.content;
} else { } else {
entry->kind = VARTABLEENTRY_VAR; abort();
entry->data.var.start = entry->data.var.end = P->t;
entry->data.var.priority = 1;
ret->expression = NULL;
} }
ret = (AST*) decl;
}
vartable_set(P->scope, name.content, entry);
expect(P, TOKEN_SEMICOLON); expect(P, TOKEN_SEMICOLON);
return (AST*) ret; return ret;
backtrack: backtrack:
P->i = oldIdx; P->i = oldIdx;
return NULL; return NULL;
@ -612,8 +635,6 @@ backtrack:
ASTChunk *nct_parse_chunk(Parser*, int, int); ASTChunk *nct_parse_chunk(Parser*, int, int);
void nct_parse_statement(Parser *P) { void nct_parse_statement(Parser *P) {
P->t++;
if(maybe(P, TOKEN_IF)) { if(maybe(P, TOKEN_IF)) {
expect(P, TOKEN_PAREN_L); expect(P, TOKEN_PAREN_L);
AST *e = nct_parse_expression(P, 0); AST *e = nct_parse_expression(P, 0);
@ -625,11 +646,11 @@ void nct_parse_statement(Parser *P) {
ret->expression = e; ret->expression = e;
pushstat(P, ret);
expect(P, TOKEN_SQUIGGLY_L); expect(P, TOKEN_SQUIGGLY_L);
ret->then = (AST*) nct_parse_chunk(P, 0, 0); ret->then = (AST*) nct_parse_chunk(P, 0, 0);
expect(P, TOKEN_SQUIGGLY_R); expect(P, TOKEN_SQUIGGLY_R);
pushstat(P, ret);
return; return;
} else if(maybe(P, TOKEN_LOOP)) { } else if(maybe(P, TOKEN_LOOP)) {
ASTStmtLoop *ret = malloc(sizeof(*ret)); ASTStmtLoop *ret = malloc(sizeof(*ret));
@ -637,7 +658,7 @@ void nct_parse_statement(Parser *P) {
ret->next = NULL; ret->next = NULL;
expect(P, TOKEN_SQUIGGLY_L); expect(P, TOKEN_SQUIGGLY_L);
ret->body = nct_parse_chunk(P, 0, 1); ret->body = (AST*) nct_parse_chunk(P, 0, 1);
expect(P, TOKEN_SQUIGGLY_R); expect(P, TOKEN_SQUIGGLY_R);
pushstat(P, ret); pushstat(P, ret);
@ -730,6 +751,10 @@ void nct_parse_statement(Parser *P) {
ret->what = e; ret->what = e;
ret->to = nct_parse_expression(P, 0);//nct_cast_expr(nct_parse_expression(P, 0), ret->what->expression.type); ret->to = nct_parse_expression(P, 0);//nct_cast_expr(nct_parse_expression(P, 0), ret->what->expression.type);
if(ret->what->nodeKind == AST_EXPR_VAR) {
reachingdefs_set(ret->what->exprVar.thing->data.var.reachingDefs, (AST*) ret);
}
expect(P, TOKEN_SEMICOLON); expect(P, TOKEN_SEMICOLON);
pushstat(P, ret); pushstat(P, ret);
@ -748,6 +773,9 @@ void nct_parse_statement(Parser *P) {
} }
ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize) { ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize) {
if(P->scope) {
}
AST *ret = malloc(sizeof(ASTChunk)); AST *ret = malloc(sizeof(ASTChunk));
ret->nodeKind = AST_CHUNK; ret->nodeKind = AST_CHUNK;
ret->chunk.statementFirst = ret->chunk.statementLast = NULL; ret->chunk.statementFirst = ret->chunk.statementLast = NULL;
@ -763,6 +791,8 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize) {
P->topLevel = &ret->chunk; P->topLevel = &ret->chunk;
} }
vartable_new_reachingdefs_for_all_vars(P->scope);
/* Find all symbol names and struct types ahead of time. Searches for colons as those can only mean symbol declarations */ /* Find all symbol names and struct types ahead of time. Searches for colons as those can only mean symbol declarations */
{ {
@ -790,7 +820,7 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize) {
} while(P->i >= 0 && P->tokens[P->i].type != TOKEN_SEMICOLON && P->tokens[P->i].type != TOKEN_SQUIGGLY_R && P->tokens[P->i].type != TOKEN_PAREN_R); } while(P->i >= 0 && P->tokens[P->i].type != TOKEN_SEMICOLON && P->tokens[P->i].type != TOKEN_SQUIGGLY_R && P->tokens[P->i].type != TOKEN_PAREN_R);
P->i++; P->i++;
ASTStmtDecl *d = &parse_declaration(P)->stmtDecl; AST *d = parse_declaration(P);
if(!d) abort(); if(!d) abort();
free(d); /* We don't need it. */ free(d); /* We don't need it. */
@ -805,6 +835,8 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize) {
nct_parse_statement(P); nct_parse_statement(P);
} }
vartable_coalesce_reachingdefs_for_all_vars(P->scope);
size_t nonSymbols = 0; size_t nonSymbols = 0;
for(size_t i = 0; i < P->scope->count; i++) { for(size_t i = 0; i < P->scope->count; i++) {
if(P->scope->data[i]->kind == VARTABLEENTRY_VAR) { if(P->scope->data[i]->kind == VARTABLEENTRY_VAR) {
@ -831,9 +863,7 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize) {
AST *nct_parse(Token *tokens) { AST *nct_parse(Token *tokens) {
Parser P; Parser P;
memset(&P, 0, sizeof(P));
P.tokens = tokens; P.tokens = tokens;
P.t = 0;
P.i = 0;
P.scope = NULL;
return (AST*) nct_parse_chunk(&P, 1, 0); return (AST*) nct_parse_chunk(&P, 1, 0);
} }

View File

@ -4,6 +4,30 @@
#include<stdlib.h> #include<stdlib.h>
#include<string.h> #include<string.h>
struct ReachingDefs *reachingdefs_push(struct ReachingDefs *this) {
struct ReachingDefs *ret = calloc(1, sizeof(*ret));
ret->parent = this;
return ret;
}
struct ReachingDefs *reachingdefs_coalesce(struct ReachingDefs *this) {
struct ReachingDefs *parent = this->parent;
if(parent) {
parent->defs = realloc(parent->defs, sizeof(*parent->defs) * (parent->defCount + this->defCount));
memcpy(&parent->defs[parent->defCount], this->defs, sizeof(*this->defs) * this->defCount);
parent->defCount += this->defCount;
}
free(this->defs);
free(this);
return parent;
}
void reachingdefs_set(struct ReachingDefs *this, union AST *def) {
this->defCount = 1;
this->defs = realloc(this->defs, sizeof(*this->defs) * this->defCount);
this->defs[0] = def;
}
VarTable *vartable_new(VarTable *parent) { VarTable *vartable_new(VarTable *parent) {
VarTable *ret = malloc(sizeof(*ret)); VarTable *ret = malloc(sizeof(*ret));
ret->parent = parent; ret->parent = parent;
@ -39,5 +63,30 @@ VarTableEntry *vartable_set(VarTable *this, const char *name, VarTableEntry *e)
this->names[this->count] = name; this->names[this->count] = name;
this->data[this->count] = e; this->data[this->count] = e;
this->count++; this->count++;
if(e->kind == VARTABLEENTRY_VAR) e->data.var.name = name;
return e; return e;
} }
void vartable_new_reachingdefs_for_all_vars(VarTable *this) {
for(size_t i = 0; i < this->count; i++) {
if(this->data[i]->kind == VARTABLEENTRY_VAR) {
this->data[i]->data.var.reachingDefs = reachingdefs_push(this->data[i]->data.var.reachingDefs);
}
}
if(this->parent) {
vartable_new_reachingdefs_for_all_vars(this->parent);
}
}
void vartable_coalesce_reachingdefs_for_all_vars(VarTable *this) {
for(size_t i = 0; i < this->count; i++) {
if(this->data[i]->kind == VARTABLEENTRY_VAR) {
this->data[i]->data.var.reachingDefs = reachingdefs_coalesce(this->data[i]->data.var.reachingDefs);
}
}
if(this->parent) {
vartable_coalesce_reachingdefs_for_all_vars(this->parent);
}
}

View File

@ -7,13 +7,25 @@ typedef enum {
VARTABLEENTRY_SYMBOL, VARTABLEENTRY_TYPE, VARTABLEENTRY_VAR VARTABLEENTRY_SYMBOL, VARTABLEENTRY_TYPE, VARTABLEENTRY_VAR
} VarTableEntryKind; } VarTableEntryKind;
union AST;
typedef struct UseDef { typedef struct UseDef {
union AST *use; //expr union AST *def; // assign stmt
union AST *def; //assign stmt union AST *use; // corresponding AST_EXPR_VAR
size_t t; union AST *stmt; // whole using stmt
struct UseDef *next; struct UseDef *next;
} UseDef; } UseDef;
// Stack, necessary for "possible reaching defs" such as from if statements
typedef struct ReachingDefs {
size_t defCount;
union AST **defs;
struct ReachingDefs *parent;
} ReachingDefs;
struct ReachingDefs *reachingdefs_push(struct ReachingDefs*);
struct ReachingDefs *reachingdefs_coalesce(struct ReachingDefs*);
void reachingdefs_set(struct ReachingDefs*, union AST*);
typedef struct VarTableEntry { typedef struct VarTableEntry {
Type *type; Type *type;
@ -26,18 +38,28 @@ typedef struct VarTableEntry {
const char *name; const char *name;
} symbol; } symbol;
struct { struct {
uint16_t color, degree; // For debugging
size_t start, end;
const char *name;
// Register allocation
// vars in loops have higher priority
// a more advanced approach would be to use weights for different colors (e.g. vars for mul "should" be in eax)
uint8_t priority; uint8_t priority;
uint16_t color, degree;
// Used during parsing
ReachingDefs *reachingDefs;
// Optimizations
UseDef *usedefFirst; UseDef *usedefFirst;
UseDef *usedefLast; UseDef *usedefLast;
} var; } var;
}; };
struct VarTableEntry *offset;
} data; } data;
void *userdata;
} VarTableEntry; } VarTableEntry;
typedef struct VarTable { typedef struct VarTable {
@ -53,4 +75,7 @@ VarTableEntry *vartable_get(VarTable*, const char*);
VarTableEntry *vartable_find(VarTable*, const char*); VarTableEntry *vartable_find(VarTable*, const char*);
VarTableEntry *vartable_set(VarTable*, const char*, VarTableEntry*); VarTableEntry *vartable_set(VarTable*, const char*, VarTableEntry*);
void vartable_new_reachingdefs_for_all_vars(VarTable*);
void vartable_coalesce_reachingdefs_for_all_vars(VarTable*);
#endif #endif

145
tests/mandelbrot.b Normal file
View File

@ -0,0 +1,145 @@
A mandelbrot set fractal viewer in brainf*** written by Erik Bosman
+++++++++++++[->++>>>+++++>++>+<<<<<<]>>>>>++++++>--->>>>>>>>>>+++++++++++++++[[
>>>>>>>>>]+[<<<<<<<<<]>>>>>>>>>-]+[>>>>>>>>[-]>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-]+
<<<<<<<+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>>+>>>>>>>>>>>>>>>>>>>>>>>>>>
>+<<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+[>>>>>>[>>>>>>>[-]>>]<<<<<<<<<[<<<<<<<<<]>>
>>>>>[-]+<<<<<<++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>+<<<<<<+++++++[-[->>>
>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>+<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[[-]>>>>>>[>>>>>
>>[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>
[>>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<
<<]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]>>>>>>>>>+++++++++++++++[[
>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[
>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>[
-<<+>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<
<<[>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<
[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>
>>>>[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+
<<<<<<[->>>[-<<<+>>>]<<<[->>>+>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>
>>>>>>>]<<<<<<<<<[>>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<<]>>[->>>>>>>>>+<<<<<<<<<]<<
+>>>>>>>>]<<<<<<<<<[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<
<]<+<<<<<<<<<]>>>>>>>>>[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>
>>>>>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+>>>>>>>>>>>>>>>>>>>>>+<<<[<<<<<<
<<<]>>>>>>>>>[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<<
<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-<<<+>>>]<<<[->
>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<
<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]<<<<<<<[->+>>>-<<<<]>>>>>>>>>+++++++++++++++++++
+++++++>>[-<<<<+>>>>]<<<<[->>>>+<<[-]<<]>>[<<<<<<<+<[-<+>>>>+<<[-]]>[-<<[->+>>>-
<<<<]>>>]>>>>>>>>>>>>>[>>[-]>[-]>[-]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>>>>>>[>>>>>
[-<<<<+>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>[-<<<<<<<<
<+>>>>>>>>>]>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>>>>>>]+>[-
]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>+>>>>>>>>]<<<
<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<[->>[-<<+>>]<
<[->>+>+<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>[->>>>
>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[-]<->>>
[-<<<+>[<->-<<<<<<<+>>>>>>>]<[->+<]>>>]<<[->>+<<]<+<<<<<<<<<]>>>>>>>>>[>>>>>>[-<
<<<<+>>>>>]<<<<<[->>>>>+<<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>+>>>>>>>>
]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<[->>[-<<+
>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>
[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[-
]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>>>>>
[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>++++++++
+++++++[[>>>>>>>>>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>>>>>>>>[-<<<<<<<+
>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[
-]>>>]<<<<<<<<<[<<<<<<<<<]>>>>+>[-<-<<<<+>>>>>]>[-<<<<<<[->>>>>+<++<<<<]>>>>>[-<
<<<<+>>>>>]<->+>]<[->+<]<<<<<[->>>>>+<<<<<]>>>>>>[-]<<<<<<+>>>>[-<<<<->>>>]+<<<<
[->>>>->>>>>[>>[-<<->>]+<<[->>->[-<<<+>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]
+>>>>>>[>>>>>>>>>]>+<]]+>>>[-<<<->>>]+<<<[->>>-<[-<<+>>]<<[->>+<<<<<<<<<<<[<<<<<
<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<
[<<<<<<<<<]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>>>>>>>]<<<<<
<<<+<[>[->>>>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>>[->>>+<<<]<]>[->>>-<<<<<<<<<
<<<<<+>>>>>>>>>>>]<<]>[->>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>>+<<<]<<
<<<<<<<<<<]>>>>[-]<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>[-<->]<[->+<]>>>>>>>>]<<<
<<<<<+<[>[->>>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>[->>>>+<<<<]>]<[->>>>-<<<<<<<
<<<<<<<+>>>>>>>>>>]<]>>[->>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>]>]<[->>>>+<<<<
]<<<<<<<<<<<]>>>>>>+<<<<<<]]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>>>>>>>>>]<<<<<<<<<
[>[->>>>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>>[->>>+<<<]<]>[->>>-<<<<<<<<<<<<<<
+>>>>>>>>>>>]<<]>[->>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>>+<<<]<<<<<<<
<<<<<]]>[-]>>[-]>[-]>>>>>[>>[-]>[-]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-<
<<<+>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[
[>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+
[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>
[-<<+>>]<<[->>+>+<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<
<[>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[
>[-]<->>>[-<<<+>[<->-<<<<<<<+>>>>>>>]<[->+<]>>>]<<[->>+<<]<+<<<<<<<<<]>>>>>>>>>[
>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]>
>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>[-]>>>>+++++++++++++++[[>>>>>>>>>]<<<<<<<<<-<<<<<
<<<<[<<<<<<<<<]>>>>>>>>>-]+[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<
<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-
<<<+>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>
>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>>>
[-<<<->>>]<<<[->>>+<<<]>>>>>>>>]<<<<<<<<+<[>[->+>[-<-<<<<<<<<<<+>>>>>>>>>>>>[-<<
+>>]<]>[-<<-<<<<<<<<<<+>>>>>>>>>>>>]<<<]>>[-<+>>[-<<-<<<<<<<<<<+>>>>>>>>>>>>]<]>
[-<<+>>]<<<<<<<<<<<<<]]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>
>>>>>>]<<<<<<<<+<[>[->+>>[-<<-<<<<<<<<<<+>>>>>>>>>>>[-<+>]>]<[-<-<<<<<<<<<<+>>>>
>>>>>>>]<<]>>>[-<<+>[-<-<<<<<<<<<<+>>>>>>>>>>>]>]<[-<+>]<<<<<<<<<<<<]>>>>>+<<<<<
]>>>>>>>>>[>>>[-]>[-]>[-]>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>[-]>>>>>[>>>>>>>[-<<<<<
<+>>>>>>]<<<<<<[->>>>>>+<<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>+>[-<-<<<<+>>>>
>]>>[-<<<<<<<[->>>>>+<++<<<<]>>>>>[-<<<<<+>>>>>]<->+>>]<<[->>+<<]<<<<<[->>>>>+<<
<<<]+>>>>[-<<<<->>>>]+<<<<[->>>>->>>>>[>>>[-<<<->>>]+<<<[->>>-<[-<<+>>]<<[->>+<<
<<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>[-<<->>]+<<[->>->[-<<<+>>>]<
<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<
<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>[-<->]<[->+
<]>>>>>>>>]<<<<<<<<+<[>[->>>>+<<[->>-<<<<<<<<<<<<<+>>>>>>>>>>[->>>+<<<]>]<[->>>-
<<<<<<<<<<<<<+>>>>>>>>>>]<]>>[->>+<<<[->>>-<<<<<<<<<<<<<+>>>>>>>>>>]>]<[->>>+<<<
]<<<<<<<<<<<]>>>>>[-]>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]]>>>>[-<<<<+>
>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>>>>>>>]<<<<<<<<+<[>[->>>>+<<<[->>>-
<<<<<<<<<<<<<+>>>>>>>>>>>[->>+<<]<]>[->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<<]>[->>>+<<[
->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>+<<]<<<<<<<<<<<<]]>>>>[-]<<<<]>>>>[-<<<<+>>
>>]<<<<[->>>>+>[-]>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]>>>>>>>>>[>>>>>>
>>>]<<<<<<<<<[>[->>>>+<<<[->>>-<<<<<<<<<<<<<+>>>>>>>>>>>[->>+<<]<]>[->>-<<<<<<<<
<<<<<+>>>>>>>>>>>]<<]>[->>>+<<[->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>+<<]<<<<<<<<
<<<<]]>>>>>>>>>[>>[-]>[-]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>[-]>>>>>[>>>>>[-<<<<+
>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[-<<<<<+>>>>>
]<<<<<[->>>>>+<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>
>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>+>>
>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>[-<<+
>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>
[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[-
]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>>>>>
[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<
<<[->>>[-<<<+>>>]<<<[->>>+>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>
>>>]<<<<<<<<<[>>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<<]>>[->>>>>>>>>+<<<<<<<<<]<<+>>>
>>>>>]<<<<<<<<<[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+
<<<<<<<<<]>>>>>>>>>[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>>>>>
>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+>>>>>>>>>>>>>>>>>>>>>+<<<[<<<<<<<<<]
>>>>>>>>>[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<<<<<<
]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-<<<+>>>]<<<[->>>+<
<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>
>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>->>[-<<<<+>>>>]<<<<[->>>>+<<[-]<<]>>]<<+>>>>[-<<<<
->>>>]+<<<<[->>>>-<<<<<<.>>]>>>>[-<<<<<<<.>>>>>>>]<<<[-]>[-]>[-]>[-]>[-]>[-]>>>[
>[-]>[-]>[-]>[-]>[-]>[-]>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-]>>>>]<<<<<<<<<
[<<<<<<<<<]>+++++++++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>+>>>>>>>>>+<<<<<<<<
<<<<<<[<<<<<<<<<]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+[-]>>[>>>>>>>>>]<<<<<
<<<<[>>>>>>>[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<<[<<<<<<<<<]>>>>>>>[-]+>>>]<<<<
<<<<<<]]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+>>[>+>>>>[-<<<<->>>>]<<<<[->>>
>+<<<<]>>>>>>>>]<<+<<<<<<<[>>>>>[->>+<<]<<<<<<<<<<<<<<]>>>>>>>>>[>>>>>>>>>]<<<<<
<<<<[>[-]<->>>>>>>[-<<<<<<<+>[<->-<<<+>>>]<[->+<]>>>>>>>]<<<<<<[->>>>>>+<<<<<<]<
+<<<<<<<<<]>>>>>>>-<<<<[-]+<<<]+>>>>>>>[-<<<<<<<->>>>>>>]+<<<<<<<[->>>>>>>->>[>>
>>>[->>+<<]>>>>]<<<<<<<<<[>[-]<->>>>>>>[-<<<<<<<+>[<->-<<<+>>>]<[->+<]>>>>>>>]<<
<<<<[->>>>>>+<<<<<<]<+<<<<<<<<<]>+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>+<<<
<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-<<<<<->>>>>]+<<<<<[->>>>>->>[-<<<<<<<+>>>>>>>]<<<<
<<<[->>>>>>>+<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>>>>[-<
<<<<<<->>>>>>>]+<<<<<<<[->>>>>>>-<<[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<<<<<<<<<[<<<
<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<
<<[<<<<<<<<<]>>>>[-]<<<+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>-<<<<<[<<<<<<<
<<]]>>>]<<<<.>>>>>>>>>>[>>>>>>[-]>>>]<<<<<<<<<[<<<<<<<<<]>++++++++++[-[->>>>>>>>
>+<<<<<<<<<]>>>>>>>>>]>>>>>+>>>>>>>>>+<<<<<<<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-<<<<<<
<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+[-]>[>>>>>>>>>]<<<<<<<<<[>>>>>>>>[-<<<<<<<+>>>>>>
>]<<<<<<<[->>>>>>>+<<<<<<<<[<<<<<<<<<]>>>>>>>>[-]+>>]<<<<<<<<<<]]>>>>>>>>[-<<<<<
<<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+>[>+>>>>>[-<<<<<->>>>>]<<<<<[->>>>>+<<<<<]>>>>>>
>>]<+<<<<<<<<[>>>>>>[->>+<<]<<<<<<<<<<<<<<<]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>[-]<-
>>>>>>>>[-<<<<<<<<+>[<->-<<+>>]<[->+<]>>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<<]<+<<<<<<
<<<]>>>>>>>>-<<<<<[-]+<<<]+>>>>>>>>[-<<<<<<<<->>>>>>>>]+<<<<<<<<[->>>>>>>>->[>>>
>>>[->>+<<]>>>]<<<<<<<<<[>[-]<->>>>>>>>[-<<<<<<<<+>[<->-<<+>>]<[->+<]>>>>>>>>]<<
<<<<<[->>>>>>>+<<<<<<<]<+<<<<<<<<<]>+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>
+>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[-<<<<<<->>>>>>]+<
<<<<<[->>>>>>->>[-<<<<<<<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+<<<<<<<<<<<<<<<<<[<<<<<<<
<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>>>>>[-<<<<<<<<->>>>>>>>]+<<<<<<<<[->>>>>>>>
-<<[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>
>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>[-]<<<++++
+[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>->>>>>>>>>>>>>>>>>>>>>>>>>>>-<<<<<<[<<<<
<<<<<]]>>>]