Compare commits
No commits in common. "07f6d57aba440bf3086d87c832ad7d91eb121078" and "9c89bfbdafc08e3a4692043abe5f46e3b13093ac" have entirely different histories.
07f6d57aba
...
9c89bfbdaf
2
Makefile
2
Makefile
@ -9,7 +9,7 @@ PREFIX = /usr/local
|
|||||||
|
|
||||||
ntc: $(SOURCES) $(HEADERS)
|
ntc: $(SOURCES) $(HEADERS)
|
||||||
ifdef OW
|
ifdef OW
|
||||||
wcl386 -ml $(if $(GAS),-DSYNTAX_GAS=1,) $(if $(DEBUG),-DDEBUG=1,) -fe="ntc.exe" -bt=dos -l=dos4g -ml $(if $(DEBUG),,-d0 -os -om -ob -oi -ol -ox) -lr -za99 -i=src $(SOURCES)
|
wcl $(if $(GAS),-DSYNTAX_GAS=1,) $(if $(DEBUG),-DDEBUG=1,) -fe="ntc.exe" -0 -bcl=dos -mt $(if $(DEBUG),,-d0 -os -om -ob -oi -ol -ox) -lr -za99 -i=src $(SOURCES)
|
||||||
else
|
else
|
||||||
cc $(if $(GAS),-DSYNTAX_GAS=1,) $(if $(DEBUG),-DDEBUG=1,) -Wall -o ntc -fno-PIE -no-pie -std=gnu11 $(if $(DEBUG),-O0 -g,-Os -s) -fms-extensions -Isrc $(SOURCES)
|
cc $(if $(GAS),-DSYNTAX_GAS=1,) $(if $(DEBUG),-DDEBUG=1,) -Wall -o ntc -fno-PIE -no-pie -std=gnu11 $(if $(DEBUG),-O0 -g,-Os -s) -fms-extensions -Isrc $(SOURCES)
|
||||||
endif
|
endif
|
||||||
|
12
README.md
12
README.md
@ -1,19 +1,11 @@
|
|||||||
# N19 Reference Compiler
|
# N19 Reference Compiler
|
||||||
|
|
||||||
Made to compile fast and produce acceptable output. Currently only 386 output supported (protected and partially real mode).
|
Made to compile fast and produce not great, but acceptable output. Currently only 386 output supported (protected and partially real mode).
|
||||||
|
|
||||||
Composed of the following passes:
|
|
||||||
|
|
||||||
1. Lexing
|
|
||||||
2. Parsing & loop\_second\_pass
|
|
||||||
3. Dumbification
|
|
||||||
4. Codegen
|
|
||||||
|
|
||||||
UD-chains are generated during parsing. Codegen uses on primitive patterns within the AST, possible thanks to dumbification. This technique is applicable owing to Nectar's already low-level nature
|
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
|
|
||||||
make
|
make
|
||||||
|
|
||||||
sudo make install
|
sudo make install
|
||||||
|
|
||||||
# Command-line usage
|
# Command-line usage
|
||||||
|
20
src/ast.c
20
src/ast.c
@ -4,6 +4,14 @@
|
|||||||
#include<string.h>
|
#include<string.h>
|
||||||
#include<stdlib.h>
|
#include<stdlib.h>
|
||||||
|
|
||||||
|
int BINOP_COMMUTATIVE[] = {
|
||||||
|
[BINOP_ADD] = 1,
|
||||||
|
[BINOP_SUB] = 0,
|
||||||
|
[BINOP_MUL] = 1,
|
||||||
|
[BINOP_DIV] = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
AST *ast_expression_optimize(AST *ast) {
|
AST *ast_expression_optimize(AST *ast) {
|
||||||
return ast;
|
return ast;
|
||||||
}
|
}
|
||||||
@ -29,13 +37,6 @@ int ast_stmt_is_after(const AST *chunk, const AST *s1, const AST *s2) {
|
|||||||
const AST *s = chunk->chunk.statementFirst;
|
const AST *s = chunk->chunk.statementFirst;
|
||||||
|
|
||||||
while(s) {
|
while(s) {
|
||||||
if(s->nodeKind == AST_STMT_LOOP) {
|
|
||||||
int i = ast_stmt_is_after(s->stmtLoop.body, s1, s2);
|
|
||||||
if(i != -1) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(s == s1) {
|
if(s == s1) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -48,6 +49,11 @@ int ast_stmt_is_after(const AST *chunk, const AST *s1, const AST *s2) {
|
|||||||
if(i != -1) {
|
if(i != -1) {
|
||||||
return i;
|
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;
|
s = s->statement.next;
|
||||||
|
22
src/ast.h
22
src/ast.h
@ -5,20 +5,7 @@
|
|||||||
#include"lexer.h"
|
#include"lexer.h"
|
||||||
#include"vartable.h"
|
#include"vartable.h"
|
||||||
|
|
||||||
// VISITORS APPEAR IN varify_change_usedefs,ast_expr_is_equal,ast_stmt_is_after,
|
typedef enum {
|
||||||
// dumben_chunk, cg_go, loop_second_pass AND OTHERS
|
|
||||||
//
|
|
||||||
// THEY ***MUST*** BE CHANGED ACCORDINGLY IF AST IS ALTERED
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
|
||||||
#define ENUMPAK __attribute__((packed))
|
|
||||||
#else
|
|
||||||
#define ENUMPAK
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef enum ENUMPAK {
|
|
||||||
AST_CHUNK,
|
AST_CHUNK,
|
||||||
AST_STMT_DECL,
|
AST_STMT_DECL,
|
||||||
AST_TYPE_IDENTIFIER,
|
AST_TYPE_IDENTIFIER,
|
||||||
@ -42,7 +29,7 @@ typedef enum ENUMPAK {
|
|||||||
AST_STMT_EXT_SECTION,
|
AST_STMT_EXT_SECTION,
|
||||||
} ASTKind;
|
} ASTKind;
|
||||||
|
|
||||||
typedef enum ENUMPAK {
|
typedef enum {
|
||||||
BINOP_ADD = 0,
|
BINOP_ADD = 0,
|
||||||
BINOP_SUB = 1,
|
BINOP_SUB = 1,
|
||||||
BINOP_BITWISE_AND = 2,
|
BINOP_BITWISE_AND = 2,
|
||||||
@ -57,6 +44,7 @@ typedef enum ENUMPAK {
|
|||||||
|
|
||||||
BINOP_WTF = 999,
|
BINOP_WTF = 999,
|
||||||
} BinaryOp;
|
} BinaryOp;
|
||||||
|
extern int BINOP_COMMUTATIVE[];
|
||||||
|
|
||||||
static inline int binop_is_comparison(BinaryOp op) {
|
static inline int binop_is_comparison(BinaryOp op) {
|
||||||
return op == BINOP_EQUAL || op == BINOP_NEQUAL;
|
return op == BINOP_EQUAL || op == BINOP_NEQUAL;
|
||||||
@ -71,7 +59,7 @@ static inline BinaryOp binop_comp_opposite(BinaryOp op) {
|
|||||||
return BINOP_WTF;
|
return BINOP_WTF;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef enum ENUMPAK {
|
typedef enum {
|
||||||
UNOP_DEREF = 0,
|
UNOP_DEREF = 0,
|
||||||
UNOP_NEGATE = 1,
|
UNOP_NEGATE = 1,
|
||||||
UNOP_BITWISE_NOT = 2,
|
UNOP_BITWISE_NOT = 2,
|
||||||
@ -263,8 +251,6 @@ typedef union AST {
|
|||||||
ASTStmtExtSection stmtExtSection;
|
ASTStmtExtSection stmtExtSection;
|
||||||
} AST;
|
} AST;
|
||||||
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
AST *ast_expression_optimize(AST*);
|
AST *ast_expression_optimize(AST*);
|
||||||
int ast_expression_equal(AST*, AST*);
|
int ast_expression_equal(AST*, AST*);
|
||||||
|
|
||||||
|
143
src/cg.c
143
src/cg.c
@ -5,16 +5,14 @@
|
|||||||
#include<string.h>
|
#include<string.h>
|
||||||
#include<assert.h>
|
#include<assert.h>
|
||||||
|
|
||||||
#include"x86.h"
|
|
||||||
|
|
||||||
#define REGS 4
|
#define REGS 4
|
||||||
static const char *regs[REGS][3] = {{"al", "ax", "eax"}, {"bl", "bx", "ebx"}, {"cl", "cx", "ecx"}, {"dl", "dx", "edx"}};
|
static const char *regs[REGS][3] = {{"al", "ax", "eax"}, {"bl", "bx", "ebx"}, {"cl", "cx", "ecx"}, {"dl", "dx", "edx"}, {"sil", "si", "esi"}, {"dil", "di", "edi"}};
|
||||||
|
|
||||||
static const char *BINOP_SIMPLE_INSTRS[] = {[BINOP_ADD] = "add", [BINOP_SUB] = "sub", [BINOP_BITWISE_AND] = "and", [BINOP_BITWISE_OR] = "or", [BINOP_BITWISE_XOR] = "xor"};
|
static const char *BINOP_SIMPLE_INSTRS[] = {[BINOP_ADD] = "add", [BINOP_SUB] = "sub", [BINOP_BITWISE_AND] = "and", [BINOP_BITWISE_OR] = "or", [BINOP_BITWISE_XOR] = "xor"};
|
||||||
|
|
||||||
static size_t nextLocalLabel = 0;
|
static size_t nextLocalLabel = 0;
|
||||||
|
|
||||||
#define LOOPSTACKSIZE 96
|
#define LOOPSTACKSIZE 64
|
||||||
static size_t loopStackStart[LOOPSTACKSIZE];
|
static size_t loopStackStart[LOOPSTACKSIZE];
|
||||||
static size_t loopStackEnd[LOOPSTACKSIZE];
|
static size_t loopStackEnd[LOOPSTACKSIZE];
|
||||||
static size_t loopStackIdx;
|
static size_t loopStackIdx;
|
||||||
@ -39,21 +37,11 @@ static const char *spec(int size) {
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int log_size(int size) {
|
|
||||||
switch(size) {
|
|
||||||
case 1: return 0;
|
|
||||||
case 2: return 1;
|
|
||||||
case 4: return 2;
|
|
||||||
case 8: return 3;
|
|
||||||
}
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *specexpr(AST *e) {
|
static const char *specexpr(AST *e) {
|
||||||
return spec(type_size(e->expression.type));
|
return spec(type_size(e->expression.type));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *xv_sz(VarTableEntry *v, int sz) {
|
static const char *xv(VarTableEntry *v) {
|
||||||
assert(v->kind == VARTABLEENTRY_VAR);
|
assert(v->kind == VARTABLEENTRY_VAR);
|
||||||
|
|
||||||
#define XVBUFS 8
|
#define XVBUFS 8
|
||||||
@ -66,7 +54,7 @@ static const char *xv_sz(VarTableEntry *v, int sz) {
|
|||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
snprintf(ret, XVBUFSZ, "@%i", v->data.var.color);
|
snprintf(ret, XVBUFSZ, "@%i", v->data.var.color);
|
||||||
#else
|
#else
|
||||||
snprintf(ret, XVBUFSZ, "%s", regs[v->data.var.color][log_size(sz)]);
|
snprintf(ret, XVBUFSZ, "%s", regs[v->data.var.color][2]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bufidx = (bufidx + 1) % XVBUFS;
|
bufidx = (bufidx + 1) % XVBUFS;
|
||||||
@ -74,10 +62,6 @@ static const char *xv_sz(VarTableEntry *v, int sz) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *xv(VarTableEntry *v) {
|
|
||||||
return xv_sz(v, type_size(v->type));
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *xj(BinaryOp op) {
|
static const char *xj(BinaryOp op) {
|
||||||
switch(op) {
|
switch(op) {
|
||||||
case BINOP_EQUAL: return "e";
|
case BINOP_EQUAL: return "e";
|
||||||
@ -86,7 +70,7 @@ static const char *xj(BinaryOp op) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *xop_sz(AST *e, int sz) {
|
static const char *xop(AST *e) {
|
||||||
#define XOPBUFS 16
|
#define XOPBUFS 16
|
||||||
#define XOPBUFSZ 24
|
#define XOPBUFSZ 24
|
||||||
static char bufs[XOPBUFS][XOPBUFSZ];
|
static char bufs[XOPBUFS][XOPBUFSZ];
|
||||||
@ -98,32 +82,25 @@ static const char *xop_sz(AST *e, int sz) {
|
|||||||
VarTableEntry *v = e->exprVar.thing;
|
VarTableEntry *v = e->exprVar.thing;
|
||||||
|
|
||||||
if(v->kind == VARTABLEENTRY_VAR) {
|
if(v->kind == VARTABLEENTRY_VAR) {
|
||||||
return xv_sz(v, sz);
|
return xv(v);
|
||||||
} else if(v->kind == VARTABLEENTRY_SYMBOL) {
|
} else if(v->kind == VARTABLEENTRY_SYMBOL) {
|
||||||
snprintf(ret, XOPBUFSZ, "[%s]", v->data.symbol.name);
|
snprintf(ret, XOPBUFSZ, "[%s]", v->data.symbol.name);
|
||||||
} else abort();
|
} else abort();
|
||||||
} else if(e->nodeKind == AST_EXPR_PRIMITIVE) {
|
} else if(e->nodeKind == AST_EXPR_PRIMITIVE) {
|
||||||
snprintf(ret, XOPBUFSZ, "%i", e->exprPrim.val);
|
snprintf(ret, XOPBUFSZ, "%i", e->exprPrim.val);
|
||||||
} else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF && e->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP && e->exprUnOp.operand->exprBinOp.operator == BINOP_ADD && e->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[0]->exprVar.thing->kind == VARTABLEENTRY_VAR && e->exprUnOp.operand->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) {
|
|
||||||
snprintf(ret, XOPBUFSZ, "%s [%s + %s]",
|
|
||||||
spec(sz),
|
|
||||||
xv_sz(e->exprUnOp.operand->exprBinOp.operands[0]->exprVar.thing, 4),
|
|
||||||
xv_sz(e->exprUnOp.operand->exprBinOp.operands[1]->exprVar.thing, 4));
|
|
||||||
} else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF && e->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP && e->exprUnOp.operand->exprBinOp.operator == BINOP_ADD && e->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL && e->exprUnOp.operand->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) {
|
} else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF && e->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP && e->exprUnOp.operand->exprBinOp.operator == BINOP_ADD && e->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL && e->exprUnOp.operand->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) {
|
||||||
snprintf(ret, XOPBUFSZ, "%s [%s + %s]",
|
snprintf(ret, XOPBUFSZ, "[%s + %s]",
|
||||||
spec(sz),
|
|
||||||
e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
|
e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
|
||||||
xv_sz(e->exprUnOp.operand->exprBinOp.operands[1]->exprVar.thing, 4));
|
xv(e->exprUnOp.operand->exprBinOp.operands[1]->exprVar.thing));
|
||||||
} else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF && e->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP && e->exprUnOp.operand->exprBinOp.operator == BINOP_ADD && e->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_BINARY_OP && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL && e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operator == BINOP_MUL && e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[0]->nodeKind == AST_EXPR_PRIMITIVE && e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) {
|
} else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF && e->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP && e->exprUnOp.operand->exprBinOp.operator == BINOP_ADD && e->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_BINARY_OP && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL && e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operator == BINOP_MUL && e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[0]->nodeKind == AST_EXPR_PRIMITIVE && e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) {
|
||||||
snprintf(ret, XOPBUFSZ, "%s [%s + %i * %s]",
|
snprintf(ret, XOPBUFSZ, "[%s + %i * %s]",
|
||||||
spec(sz),
|
|
||||||
e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
|
e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
|
||||||
e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[0]->exprPrim.val,
|
e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[0]->exprPrim.val,
|
||||||
xv_sz(e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing, 4));
|
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) {
|
} 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 [%s]", spec(sz), xv_sz(e->exprUnOp.operand->exprVar.thing, 4));
|
snprintf(ret, XOPBUFSZ, "[%s]", xv(e->exprUnOp.operand->exprVar.thing));
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -133,10 +110,6 @@ static const char *xop_sz(AST *e, int sz) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *xop(AST *e) {
|
|
||||||
return xop_sz(e, type_size(e->expression.type));
|
|
||||||
}
|
|
||||||
|
|
||||||
void cg_chunk(AST *a) {
|
void cg_chunk(AST *a) {
|
||||||
AST *s = a->chunk.statementFirst;
|
AST *s = a->chunk.statementFirst;
|
||||||
|
|
||||||
@ -151,16 +124,6 @@ void cg_chunk(AST *a) {
|
|||||||
|
|
||||||
printf("org %lu\n", s->stmtExtOrg.val);
|
printf("org %lu\n", s->stmtExtOrg.val);
|
||||||
|
|
||||||
} else if(s->nodeKind == AST_STMT_EXT_ALIGN) {
|
|
||||||
|
|
||||||
uint32_t val = s->stmtExtAlign.val;
|
|
||||||
if((val & (val - 1))) {
|
|
||||||
// nasm does not support non-PoT alignments, so pad manually
|
|
||||||
printf("times ($ - $$ + %u) / %u * %u - ($ - $$) db 0\n", val - 1, val, val);
|
|
||||||
} else {
|
|
||||||
printf("align %u\n", val);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if(s->nodeKind == AST_STMT_DECL && s->stmtDecl.thing->kind == VARTABLEENTRY_SYMBOL) {
|
} else if(s->nodeKind == AST_STMT_DECL && s->stmtDecl.thing->kind == VARTABLEENTRY_SYMBOL) {
|
||||||
VarTableEntry *v = s->stmtDecl.thing;
|
VarTableEntry *v = s->stmtDecl.thing;
|
||||||
|
|
||||||
@ -172,72 +135,38 @@ void cg_chunk(AST *a) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(s->stmtDecl.expression) {
|
if(s->stmtDecl.expression) {
|
||||||
printf("%s:", v->data.symbol.name);
|
puts("A");
|
||||||
if(v->type->type == TYPE_TYPE_PRIMITIVE) {
|
|
||||||
|
|
||||||
assert(s->stmtDecl.expression->nodeKind == AST_EXPR_PRIMITIVE);
|
|
||||||
|
|
||||||
printf("%s %i", direct(type_size(v->type)), s->stmtDecl.expression->exprPrim.val);
|
|
||||||
|
|
||||||
} else if(v->type->type == TYPE_TYPE_ARRAY && v->type->array.of->type == TYPE_TYPE_PRIMITIVE) {
|
|
||||||
|
|
||||||
printf("%s ", direct(type_size(v->type->array.of)));
|
|
||||||
for(size_t i = 0; i < v->type->array.length; i++) {
|
|
||||||
printf("%i,", s->stmtDecl.expression->exprArray.items[i]->exprPrim.val);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else printf("A");
|
|
||||||
putchar('\n');
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
printf("%s resb %lu\n", v->data.symbol.name, type_size(s->stmtDecl.thing->type));
|
printf("%s resb %lu\n", v->data.symbol.name, type_size(s->stmtDecl.thing->type));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(s->nodeKind == AST_STMT_ASSIGN) {
|
} else if(s->nodeKind == AST_STMT_ASSIGN) {
|
||||||
|
|
||||||
|
if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to->exprBinOp.operands[0]) && (s->stmtAssign.to->exprBinOp.operator == BINOP_ADD || s->stmtAssign.to->exprBinOp.operator == BINOP_SUB) && s->stmtAssign.to->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE && s->stmtAssign.to->exprBinOp.operands[1]->exprPrim.val == 1) {
|
||||||
|
|
||||||
if(s->stmtAssign.to) {
|
// inc or dec
|
||||||
if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to->exprBinOp.operands[0]) && (s->stmtAssign.to->exprBinOp.operator == BINOP_ADD || s->stmtAssign.to->exprBinOp.operator == BINOP_SUB) && s->stmtAssign.to->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE && s->stmtAssign.to->exprBinOp.operands[1]->exprPrim.val == 1) {
|
|
||||||
|
|
||||||
// inc or dec
|
static const char *instrs[] = {"inc", "dec"};
|
||||||
|
printf("%s %s %s\n", instrs[s->stmtAssign.to->exprBinOp.operator == BINOP_SUB], specexpr(s->stmtAssign.what), xop(s->stmtAssign.what));
|
||||||
static const char *instrs[] = {"inc", "dec"};
|
|
||||||
printf("%s %s %s\n", instrs[s->stmtAssign.to->exprBinOp.operator == BINOP_SUB], specexpr(s->stmtAssign.what), xop(s->stmtAssign.what));
|
|
||||||
|
|
||||||
} else if(s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_ADD && s->stmtAssign.to->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing->kind == VARTABLEENTRY_VAR && s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) {
|
|
||||||
|
|
||||||
printf("lea %s, [%s + %s]\n",
|
|
||||||
xv(s->stmtAssign.what->exprVar.thing),
|
|
||||||
xv(s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing),
|
|
||||||
xv(s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing));
|
|
||||||
|
|
||||||
} else if(s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_ADD && s->stmtAssign.to->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && s->stmtAssign.to->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL && s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) {
|
|
||||||
|
|
||||||
printf("lea %s, [%s + %s]\n",
|
|
||||||
xv(s->stmtAssign.what->exprVar.thing),
|
|
||||||
s->stmtAssign.to->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
|
|
||||||
xv(s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing));
|
|
||||||
|
|
||||||
} else if(s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_ADD && s->stmtAssign.to->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE && s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing->kind == VARTABLEENTRY_VAR) {
|
|
||||||
|
|
||||||
printf("lea %s, [%s + %i]\n",
|
|
||||||
xv_sz(s->stmtAssign.what->exprVar.thing, 4),
|
|
||||||
xv_sz(s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing, 4),
|
|
||||||
s->stmtAssign.to->exprBinOp.operands[1]->exprPrim.val);
|
|
||||||
|
|
||||||
} else if(is_xop(s->stmtAssign.what) != NULL && s->stmtAssign.to->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_NEGATE && ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to->exprUnOp.operand)) {
|
} else if(s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_ADD && s->stmtAssign.to->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing->kind == VARTABLEENTRY_VAR && s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) {
|
||||||
|
|
||||||
printf("neg %s\n", xop(s->stmtAssign.what));
|
printf("lea %s, [%s + %s]\n",
|
||||||
|
xv(s->stmtAssign.what->exprVar.thing),
|
||||||
} else {
|
xv(s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing),
|
||||||
|
xv(s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing));
|
||||||
|
|
||||||
|
} else if(s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_ADD && s->stmtAssign.to->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && s->stmtAssign.to->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL && s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) {
|
||||||
|
|
||||||
|
printf("lea %s, [%s + %s]\n",
|
||||||
|
xv(s->stmtAssign.what->exprVar.thing),
|
||||||
|
s->stmtAssign.to->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
|
||||||
|
xv(s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
printf("mov %s, %s\n", xop(s->stmtAssign.what), xop(s->stmtAssign.to));
|
||||||
|
|
||||||
if(is_xop(s->stmtAssign.to) == XOP_MEM && type_size(s->stmtAssign.what->expression.type) != type_size(s->stmtAssign.to->expression.type)) {
|
|
||||||
printf("movzx %s, %s\n", xop_sz(s->stmtAssign.what, 4), xop_sz(s->stmtAssign.to, type_size(s->stmtAssign.what->expression.type)));
|
|
||||||
} else {
|
|
||||||
printf("mov %s, %s\n", xop(s->stmtAssign.what), xop_sz(s->stmtAssign.to, type_size(s->stmtAssign.what->expression.type)));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if(s->nodeKind == AST_STMT_LOOP) {
|
} else if(s->nodeKind == AST_STMT_LOOP) {
|
||||||
@ -273,7 +202,7 @@ void cg_chunk(AST *a) {
|
|||||||
|
|
||||||
size_t lbl = nextLocalLabel++;
|
size_t lbl = nextLocalLabel++;
|
||||||
|
|
||||||
printf("cmp %s, %s\n", xop(s->stmtIf.expression->exprBinOp.operands[0]), xop(s->stmtIf.expression->exprBinOp.operands[1]));
|
printf("cmp %s %s, %s\n", specexpr(s->stmtIf.expression->exprBinOp.operands[0]), xop(s->stmtIf.expression->exprBinOp.operands[0]), xop(s->stmtIf.expression->exprBinOp.operands[1]));
|
||||||
printf("j%s .L%lu\n", xj(binop_comp_opposite(s->stmtIf.expression->exprBinOp.operator)), lbl);
|
printf("j%s .L%lu\n", xj(binop_comp_opposite(s->stmtIf.expression->exprBinOp.operator)), lbl);
|
||||||
|
|
||||||
cg_chunk(s->stmtIf.then);
|
cg_chunk(s->stmtIf.then);
|
||||||
@ -395,4 +324,4 @@ nextColor:;
|
|||||||
cg_chunk(a);
|
cg_chunk(a);
|
||||||
|
|
||||||
free(vars);
|
free(vars);
|
||||||
}
|
}
|
@ -1,308 +0,0 @@
|
|||||||
#include"dumberdowner.h"
|
|
||||||
|
|
||||||
#include<stdlib.h>
|
|
||||||
#include<assert.h>
|
|
||||||
|
|
||||||
// This is the dumbing down pass.
|
|
||||||
//
|
|
||||||
// Complex expressions are to be "broken down" into simpler ones until the AST
|
|
||||||
// can be trivially translated to the target architecture.
|
|
||||||
//
|
|
||||||
// This pass, along with CG is strictly dependent on x86 and will fail for
|
|
||||||
// any other architecture.
|
|
||||||
|
|
||||||
#include"x86.h"
|
|
||||||
|
|
||||||
static void varify_change_usedefs(AST *e, AST *oldStmt, AST *newStmt) {
|
|
||||||
if(e->nodeKind == AST_EXPR_VAR) {
|
|
||||||
if(e->exprVar.thing->kind != VARTABLEENTRY_VAR) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UseDef *swapWithPrev = NULL;
|
|
||||||
UseDef *swapWith = NULL;
|
|
||||||
|
|
||||||
UseDef *udPrev = NULL;
|
|
||||||
UseDef *ud = e->exprVar.thing->data.var.usedefFirst;
|
|
||||||
while(ud && ud->use != e) {
|
|
||||||
if(ud->stmt == oldStmt && !swapWith) {
|
|
||||||
swapWithPrev = udPrev;
|
|
||||||
swapWith = ud;
|
|
||||||
}
|
|
||||||
|
|
||||||
udPrev = ud;
|
|
||||||
ud = ud->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ud) {
|
|
||||||
assert(ud->stmt == oldStmt);
|
|
||||||
ud->stmt = newStmt;
|
|
||||||
|
|
||||||
// We must make sure all newStmt usedefs are before the oldStmt ones, so swap
|
|
||||||
if(swapWith) {
|
|
||||||
assert(!!swapWithPrev + !!udPrev != 0);
|
|
||||||
|
|
||||||
if(swapWithPrev) {
|
|
||||||
swapWithPrev->next = ud;
|
|
||||||
} else {
|
|
||||||
e->exprVar.thing->data.var.usedefFirst = ud;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(udPrev) {
|
|
||||||
udPrev->next = swapWith;
|
|
||||||
} else {
|
|
||||||
e->exprVar.thing->data.var.usedefFirst = swapWith;
|
|
||||||
}
|
|
||||||
|
|
||||||
UseDef *temp = ud->next;
|
|
||||||
ud->next = swapWith->next;
|
|
||||||
swapWith->next = temp;
|
|
||||||
|
|
||||||
assert(!!ud->next + !!swapWith->next != 0);
|
|
||||||
if(!swapWith->next) {
|
|
||||||
e->exprVar.thing->data.var.usedefLast = swapWith;
|
|
||||||
}
|
|
||||||
if(!ud->next) {
|
|
||||||
e->exprVar.thing->data.var.usedefLast = ud;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if(e->nodeKind == AST_EXPR_BINARY_OP) {
|
|
||||||
varify_change_usedefs(e->exprBinOp.operands[0], oldStmt, newStmt);
|
|
||||||
varify_change_usedefs(e->exprBinOp.operands[1], oldStmt, newStmt);
|
|
||||||
} else if(e->nodeKind == AST_EXPR_UNARY_OP) {
|
|
||||||
varify_change_usedefs(e->exprUnOp.operand, oldStmt, newStmt);
|
|
||||||
} else if(e->nodeKind == AST_EXPR_CALL) {
|
|
||||||
varify_change_usedefs(e->exprCall.what, oldStmt, newStmt);
|
|
||||||
|
|
||||||
int argCount = e->exprCall.what->expression.type->function.argCount;
|
|
||||||
for(int i = 0; i < argCount; i++) {
|
|
||||||
varify_change_usedefs(e->exprCall.args[i], oldStmt, newStmt);
|
|
||||||
}
|
|
||||||
} else if(e->nodeKind == AST_EXPR_ARRAY) {
|
|
||||||
int sz = e->exprArray.type->array.length;
|
|
||||||
for(int i = 0; i < sz; i++) {
|
|
||||||
varify_change_usedefs(e->exprArray.items[i], oldStmt, newStmt);
|
|
||||||
}
|
|
||||||
} else if(e->nodeKind == AST_EXPR_CAST) {
|
|
||||||
varify_change_usedefs(e->exprCast.what, oldStmt, newStmt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Split away complex expression into a new local variable */
|
|
||||||
static AST *varify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) {
|
|
||||||
VarTableEntry *vte = malloc(sizeof(*vte));
|
|
||||||
vte->kind = VARTABLEENTRY_VAR;
|
|
||||||
vte->type = e->expression.type;
|
|
||||||
vte->data.var.color = 0;
|
|
||||||
vte->data.var.degree = 0;
|
|
||||||
vte->data.var.priority = 0;
|
|
||||||
vte->data.var.reachingDefs = NULL;
|
|
||||||
|
|
||||||
// Add to var array
|
|
||||||
tlc->chunk.vars = realloc(tlc->chunk.vars, sizeof(*tlc->chunk.vars) * (++tlc->chunk.varCount));
|
|
||||||
tlc->chunk.vars[tlc->chunk.varCount - 1] = vte;
|
|
||||||
|
|
||||||
// Alter AST
|
|
||||||
|
|
||||||
ASTExprVar *ev[2];
|
|
||||||
for(int i = 0; i < 2; i++) {
|
|
||||||
ev[i] = malloc(sizeof(ASTExprVar));
|
|
||||||
ev[i]->nodeKind = AST_EXPR_VAR;
|
|
||||||
ev[i]->type = e->expression.type;
|
|
||||||
ev[i]->thing = vte;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASTStmtAssign *assign = malloc(sizeof(*assign));
|
|
||||||
assign->nodeKind = AST_STMT_ASSIGN;
|
|
||||||
assign->what = (AST*) ev[0];
|
|
||||||
assign->to = e;
|
|
||||||
|
|
||||||
if(stmtPrev) {
|
|
||||||
stmtPrev->statement.next = (AST*) assign;
|
|
||||||
} else {
|
|
||||||
chunk->chunk.statementFirst = (AST*) assign;
|
|
||||||
}
|
|
||||||
assign->next = stmt;
|
|
||||||
|
|
||||||
// Assemble ud-chain
|
|
||||||
|
|
||||||
UseDef *ud[2];
|
|
||||||
ud[0] = malloc(sizeof(UseDef));
|
|
||||||
ud[1] = malloc(sizeof(UseDef));
|
|
||||||
|
|
||||||
ud[0]->stmt = (AST*) assign;
|
|
||||||
ud[0]->use = assign->what;
|
|
||||||
ud[0]->def = (AST*) assign;
|
|
||||||
ud[0]->next = ud[1];
|
|
||||||
|
|
||||||
ud[1]->stmt = stmt;
|
|
||||||
ud[1]->use = (AST*) ev[1];
|
|
||||||
ud[1]->def = (AST*) assign;
|
|
||||||
ud[1]->next = NULL;
|
|
||||||
|
|
||||||
vte->data.var.usedefFirst = ud[0];
|
|
||||||
vte->data.var.usedefLast = ud[1];
|
|
||||||
|
|
||||||
// Correct the ud-chain of variables used in varified expression `e`
|
|
||||||
|
|
||||||
varify_change_usedefs(e, stmt, (AST*) assign);
|
|
||||||
|
|
||||||
return (AST*) ev[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
static AST *xopify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) {
|
|
||||||
return varify(tlc, chunk, stmtPrev, stmt, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
static UseDef *get_last_usedef_before_stmt(AST *tlc, VarTableEntry *v, AST *stmt) {
|
|
||||||
assert(v->kind == VARTABLEENTRY_VAR);
|
|
||||||
|
|
||||||
UseDef *ud = v->data.var.usedefFirst;
|
|
||||||
|
|
||||||
if(!ud) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
UseDef *udPrev = NULL;
|
|
||||||
|
|
||||||
while(ud) {
|
|
||||||
if(ast_stmt_is_after(tlc, ud->stmt, stmt)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
udPrev = ud;
|
|
||||||
ud = ud->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return udPrev;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dumben_chunk(AST *tlc, AST *chu) {
|
|
||||||
AST *sPrev = NULL;
|
|
||||||
AST *s = chu->chunk.statementFirst;
|
|
||||||
|
|
||||||
int effective = 0;
|
|
||||||
|
|
||||||
while(s) {
|
|
||||||
|
|
||||||
if(s->nodeKind == AST_STMT_IF) {
|
|
||||||
|
|
||||||
AST *e = s->stmtIf.expression;
|
|
||||||
|
|
||||||
if(e->nodeKind == AST_EXPR_BINARY_OP && binop_is_comparison(e->exprBinOp.operator)) {
|
|
||||||
|
|
||||||
if(is_xop(e->exprBinOp.operands[0]) == XOP_NOT_XOP) {
|
|
||||||
e->exprBinOp.operands[0] = xopify(tlc, chu, sPrev, s, e->exprBinOp.operands[0]);
|
|
||||||
effective = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_xop(e->exprBinOp.operands[1]) == XOP_NOT_XOP) {
|
|
||||||
e->exprBinOp.operands[1] = xopify(tlc, chu, sPrev, s, e->exprBinOp.operands[1]);
|
|
||||||
effective = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_xop(e->exprBinOp.operands[0]) == XOP_MEM && is_xop(e->exprBinOp.operands[1]) == XOP_MEM) {
|
|
||||||
// Can't have two mems; put one in var
|
|
||||||
|
|
||||||
e->exprBinOp.operands[1] = varify(tlc, chu, sPrev, s, e->exprBinOp.operands[1]);
|
|
||||||
effective = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
s->stmtIf.expression = varify(tlc, chu, sPrev, s, e);
|
|
||||||
effective = 1;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
effective |= dumben_chunk(tlc, s->stmtIf.then);
|
|
||||||
|
|
||||||
} else if(s->nodeKind == AST_STMT_LOOP) {
|
|
||||||
|
|
||||||
effective |= dumben_chunk(tlc, s->stmtLoop.body);
|
|
||||||
|
|
||||||
} else if(s->nodeKind == AST_STMT_ASSIGN) {
|
|
||||||
|
|
||||||
if(s->stmtAssign.what->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.what->exprUnOp.operator == UNOP_DEREF
|
|
||||||
&& s->stmtAssign.to->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_DEREF) {
|
|
||||||
|
|
||||||
s->stmtAssign.to = varify(tlc, chu, sPrev, s, s->stmtAssign.to);
|
|
||||||
effective = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_NEGATE && (s->stmtAssign.to->exprUnOp.operand->nodeKind != AST_EXPR_VAR || s->stmtAssign.what->exprVar.thing != s->stmtAssign.to->exprUnOp.operand->exprVar.thing)) {
|
|
||||||
// Turn this:
|
|
||||||
// a = -b
|
|
||||||
// into
|
|
||||||
// a = b
|
|
||||||
// a = -a
|
|
||||||
// While keeping UD-chain valid.
|
|
||||||
|
|
||||||
// Currently only for variables. While this could work for any XOP, it requires the ability to deep-copy `a`, which is not trivial when taking into account UD-chains.
|
|
||||||
// TODO: Scrap incremental UD-chain modifications. Simply rebuild them after each pass.
|
|
||||||
|
|
||||||
ASTExprVar *ev[2];
|
|
||||||
for(int i = 0; i < 2; i++) {
|
|
||||||
ev[i] = malloc(sizeof(ASTExprVar));
|
|
||||||
ev[i]->nodeKind = AST_EXPR_VAR;
|
|
||||||
ev[i]->type = s->stmtAssign.what->expression.type;
|
|
||||||
ev[i]->thing = s->stmtAssign.what->exprVar.thing;
|
|
||||||
}
|
|
||||||
|
|
||||||
AST *negation = s->stmtAssign.to;
|
|
||||||
|
|
||||||
s->stmtAssign.to = negation->exprUnOp.operand;
|
|
||||||
negation->exprUnOp.operand = ev[0];
|
|
||||||
|
|
||||||
AST *assign2 = malloc(sizeof(ASTStmtAssign));
|
|
||||||
assign2->nodeKind = AST_STMT_ASSIGN;
|
|
||||||
assign2->stmtAssign.what = ev[1];
|
|
||||||
assign2->stmtAssign.to = negation;
|
|
||||||
|
|
||||||
assign2->statement.next = s->statement.next;
|
|
||||||
s->statement.next = assign2;
|
|
||||||
|
|
||||||
UseDef *link = get_last_usedef_before_stmt(tlc, ev[0]->thing, assign2->statement.next);
|
|
||||||
|
|
||||||
UseDef *ud[2];
|
|
||||||
ud[0] = malloc(sizeof(UseDef));
|
|
||||||
ud[1] = malloc(sizeof(UseDef));
|
|
||||||
|
|
||||||
ud[0]->stmt = assign2;
|
|
||||||
ud[0]->use = (AST*) ev[1];
|
|
||||||
ud[0]->def = s;
|
|
||||||
ud[0]->next = ud[1];
|
|
||||||
|
|
||||||
ud[1]->stmt = assign2;
|
|
||||||
ud[1]->use = (AST*) ev[0];
|
|
||||||
ud[1]->def = s;
|
|
||||||
ud[1]->next = link->next;
|
|
||||||
|
|
||||||
link->next = ud[0];
|
|
||||||
|
|
||||||
effective = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if(s->nodeKind == AST_STMT_EXPR && s->stmtExpr.expr->nodeKind == AST_EXPR_CALL) {
|
|
||||||
|
|
||||||
int argCount = s->stmtExpr.expr->exprCall.what->expression.type->function.argCount;
|
|
||||||
|
|
||||||
for(int i = 0; i < argCount; i++) {
|
|
||||||
if(is_xop(s->stmtExpr.expr->exprCall.args[i]) == XOP_NOT_XOP) {
|
|
||||||
s->stmtExpr.expr->exprCall.args[i] = xopify(tlc, chu, sPrev, s, s->stmtExpr.expr->exprCall.args[i]);
|
|
||||||
effective = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sPrev = s;
|
|
||||||
s = s->statement.next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return effective;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dumben_go(AST* tlc) {
|
|
||||||
while(dumben_chunk(tlc, tlc));
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include"ast.h"
|
|
||||||
|
|
||||||
void dumben_go(AST* a);
|
|
@ -318,10 +318,3 @@ Token *nct_lex(FILE *f) {
|
|||||||
|
|
||||||
return NULL; /* Doesn't reach here. */
|
return NULL; /* Doesn't reach here. */
|
||||||
}
|
}
|
||||||
|
|
||||||
void nct_lex_free(Token *tokens) {
|
|
||||||
for(Token *t = tokens; t->type != TOKEN_EOF; t++) {
|
|
||||||
if(t->content) free(t->content);
|
|
||||||
}
|
|
||||||
free(tokens);
|
|
||||||
}
|
|
||||||
|
@ -50,6 +50,5 @@ typedef struct {
|
|||||||
|
|
||||||
Token nct_tokenize(FILE*);
|
Token nct_tokenize(FILE*);
|
||||||
Token *nct_lex(FILE*);
|
Token *nct_lex(FILE*);
|
||||||
void nct_lex_free(Token *);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
#include"ntc.h"
|
#include"ntc.h"
|
||||||
#include"reporting.h"
|
#include"reporting.h"
|
||||||
#include"cg.h"
|
#include"cg.h"
|
||||||
#include"dumberdowner.h"
|
|
||||||
|
|
||||||
static int argc;
|
static int argc;
|
||||||
static char **argv;
|
static char **argv;
|
||||||
@ -37,8 +36,6 @@ int main(int argc_, char **argv_) {
|
|||||||
|
|
||||||
free(tokens);
|
free(tokens);
|
||||||
|
|
||||||
dumben_go(chunk);
|
|
||||||
|
|
||||||
cg_go(chunk);
|
cg_go(chunk);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
205
src/parse.c
205
src/parse.c
@ -9,21 +9,6 @@
|
|||||||
#include<stdint.h>
|
#include<stdint.h>
|
||||||
#include<signal.h>
|
#include<signal.h>
|
||||||
|
|
||||||
#ifndef __GNUC__
|
|
||||||
static inline int __builtin_clzl(unsigned long x) {
|
|
||||||
unsigned long n = 32;
|
|
||||||
unsigned long y;
|
|
||||||
|
|
||||||
y = x >>16; if (y != 0) { n = n -16; x = y; }
|
|
||||||
y = x >> 8; if (y != 0) { n = n - 8; x = y; }
|
|
||||||
y = x >> 4; if (y != 0) { n = n - 4; x = y; }
|
|
||||||
y = x >> 2; if (y != 0) { n = n - 2; x = y; }
|
|
||||||
y = x >> 1; if (y != 0) return n - 2;
|
|
||||||
|
|
||||||
return n - x;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
UseDef ud;
|
UseDef ud;
|
||||||
VarTableEntry *to;
|
VarTableEntry *to;
|
||||||
@ -31,7 +16,7 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Token *tokens;
|
Token *tokens;
|
||||||
intmax_t i;
|
ssize_t i;
|
||||||
|
|
||||||
VarTable *scope;
|
VarTable *scope;
|
||||||
|
|
||||||
@ -44,11 +29,6 @@ typedef struct {
|
|||||||
// Used by pushstmt to assemble use-def chain
|
// Used by pushstmt to assemble use-def chain
|
||||||
size_t udsToAddCount;
|
size_t udsToAddCount;
|
||||||
UseDefToAdd *udsToAdd;
|
UseDefToAdd *udsToAdd;
|
||||||
|
|
||||||
// Used to place guard variable uses after loops to stop reg allocation from fucking up
|
|
||||||
VarTable *loopScope;
|
|
||||||
size_t guardedVarCount;
|
|
||||||
ASTExprVar **guardedVars;
|
|
||||||
} Parser;
|
} Parser;
|
||||||
|
|
||||||
static Token get(Parser *P) {
|
static Token get(Parser *P) {
|
||||||
@ -95,11 +75,6 @@ static void pushstat(Parser *P, void *a) {
|
|||||||
memcpy(ud, &P->udsToAdd[i].ud, sizeof(*ud));
|
memcpy(ud, &P->udsToAdd[i].ud, sizeof(*ud));
|
||||||
ud->stmt = a;
|
ud->stmt = a;
|
||||||
|
|
||||||
/*if(ud->stmt->nodeKind == AST_STMT_ASSIGN && ud->stmt->stmtAssign.what == ud->use) {
|
|
||||||
// Forget. The x in `x = y` is not a use of x.
|
|
||||||
continue;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if(to->data.var.usedefFirst) {
|
if(to->data.var.usedefFirst) {
|
||||||
to->data.var.usedefLast->next = ud;
|
to->data.var.usedefLast->next = ud;
|
||||||
to->data.var.usedefLast = ud;
|
to->data.var.usedefLast = ud;
|
||||||
@ -121,6 +96,7 @@ static void pushstat(Parser *P, void *a) {
|
|||||||
static ASTExprPrimitive *parse_prim(Parser *P) {
|
static ASTExprPrimitive *parse_prim(Parser *P) {
|
||||||
ASTExprPrimitive *ret = malloc(sizeof(*ret));
|
ASTExprPrimitive *ret = malloc(sizeof(*ret));
|
||||||
ret->nodeKind = AST_EXPR_PRIMITIVE;
|
ret->nodeKind = AST_EXPR_PRIMITIVE;
|
||||||
|
ret->type = (Type*) primitive_parse("s16");
|
||||||
|
|
||||||
Token tok = get(P);
|
Token tok = get(P);
|
||||||
|
|
||||||
@ -133,32 +109,21 @@ static ASTExprPrimitive *parse_prim(Parser *P) {
|
|||||||
|
|
||||||
ret->val = strtol(str, NULL, base);
|
ret->val = strtol(str, NULL, base);
|
||||||
|
|
||||||
// Smallest integer type to store number
|
|
||||||
char buf[8];
|
|
||||||
snprintf(buf, sizeof(buf), "s%i", ret->val ? (64 - __builtin_clzl(ret->val - 1)) : 1);
|
|
||||||
ret->type = (Type*) primitive_parse(buf);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void newusedef(Parser *P, VarTableEntry *v, AST *expr) {
|
static void newusedef(Parser *P, VarTableEntry *v, AST *expr) {
|
||||||
ReachingDefs *defs = v->data.var.reachingDefs;
|
for(size_t i = 0; i < v->data.var.reachingDefs->defCount; i++) {
|
||||||
|
P->udsToAdd = realloc(P->udsToAdd, sizeof(*P->udsToAdd) * (++P->udsToAddCount));
|
||||||
while(defs) {
|
P->udsToAdd[P->udsToAddCount - 1] = (UseDefToAdd) {
|
||||||
for(size_t i = 0; i < defs->defCount; i++) {
|
.ud = {
|
||||||
P->udsToAdd = realloc(P->udsToAdd, sizeof(*P->udsToAdd) * (++P->udsToAddCount));
|
.def = v->data.var.reachingDefs->defs[i],
|
||||||
P->udsToAdd[P->udsToAddCount - 1].ud.def = defs->defs[i];
|
.use = expr,
|
||||||
P->udsToAdd[P->udsToAddCount - 1].ud.use = expr;
|
.stmt = NULL, // set by pushstmt
|
||||||
P->udsToAdd[P->udsToAddCount - 1].ud.stmt = NULL; // set by pushstmt
|
.next = NULL,
|
||||||
P->udsToAdd[P->udsToAddCount - 1].ud.next = NULL;
|
},
|
||||||
P->udsToAdd[P->udsToAddCount - 1].to = v;
|
.to = v
|
||||||
}
|
};
|
||||||
|
|
||||||
if(defs->excludeParent) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
defs = defs->parent;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,36 +137,6 @@ static AST *exprvar(Parser *P, VarTableEntry *v) {
|
|||||||
newusedef(P, v, a);
|
newusedef(P, v, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(P->loopScope) {
|
|
||||||
// XXX: O(n)!!!!!!!!!
|
|
||||||
|
|
||||||
int inloop = 0;
|
|
||||||
for(VarTable *vt = v->owner; vt; vt = vt->parent) {
|
|
||||||
if(vt->parent == P->loopScope) {
|
|
||||||
inloop = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!inloop) {
|
|
||||||
int alreadyAdded = 0;
|
|
||||||
for(size_t i = 0; i < P->guardedVarCount; i++) {
|
|
||||||
if(P->guardedVars[i]->thing == v) {
|
|
||||||
alreadyAdded = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!alreadyAdded) {
|
|
||||||
ASTExprVar *ev = malloc(sizeof(*ev));
|
|
||||||
memcpy(ev, a, sizeof(*ev));
|
|
||||||
|
|
||||||
P->guardedVars = realloc(P->guardedVars, sizeof(*P->guardedVars) * (P->guardedVarCount + 1));
|
|
||||||
P->guardedVars[P->guardedVarCount++] = ev;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,14 +163,10 @@ AST *nct_cast_expr(AST *what, Type *to) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (AST*) ret;
|
return (AST*) ret;
|
||||||
} else if(to->type == TYPE_TYPE_PRIMITIVE) {
|
} else if(to->type == TYPE_TYPE_PRIMITIVE && to->primitive.width == 32) {
|
||||||
if(to->primitive.width != what->exprStrLit.length * 8) {
|
|
||||||
stahp(0, 0, "Size mismatch between string literal and target type");
|
|
||||||
}
|
|
||||||
|
|
||||||
ASTExprPrimitive *ret = malloc(sizeof(*ret));
|
ASTExprPrimitive *ret = malloc(sizeof(*ret));
|
||||||
ret->nodeKind = AST_EXPR_PRIMITIVE;
|
ret->nodeKind = AST_EXPR_PRIMITIVE;
|
||||||
ret->type = to;
|
ret->type = primitive_parse("u32");
|
||||||
memcpy(&ret->val, what->exprStrLit.data, sizeof(ret->val));
|
memcpy(&ret->val, what->exprStrLit.data, sizeof(ret->val));
|
||||||
return (AST*) ret;
|
return (AST*) ret;
|
||||||
} else abort();
|
} else abort();
|
||||||
@ -254,9 +185,6 @@ AST *nct_cast_expr(AST *what, Type *to) {
|
|||||||
ret->val = what->exprPrim.val & (((int64_t) 1 << to->primitive.width) - 1);
|
ret->val = what->exprPrim.val & (((int64_t) 1 << to->primitive.width) - 1);
|
||||||
return (AST*) ret;
|
return (AST*) ret;
|
||||||
} else {
|
} else {
|
||||||
// Silently fail :)
|
|
||||||
return what;
|
|
||||||
|
|
||||||
ASTExprCast *ret = malloc(sizeof(*ret));
|
ASTExprCast *ret = malloc(sizeof(*ret));
|
||||||
ret->nodeKind = AST_EXPR_CAST;
|
ret->nodeKind = AST_EXPR_CAST;
|
||||||
ret->type = to;
|
ret->type = to;
|
||||||
@ -285,10 +213,6 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
|||||||
ret->length = tok.length;
|
ret->length = tok.length;
|
||||||
|
|
||||||
return (AST*) ret;
|
return (AST*) ret;
|
||||||
} else if(maybe(P, TOKEN_PAREN_L)) {
|
|
||||||
AST *e = nct_parse_expression(P, 0);
|
|
||||||
expect(P, TOKEN_PAREN_R);
|
|
||||||
return e;
|
|
||||||
}
|
}
|
||||||
} else if(lOP == 4) {
|
} else if(lOP == 4) {
|
||||||
if(maybe(P, TOKEN_STAR)) {
|
if(maybe(P, TOKEN_STAR)) {
|
||||||
@ -653,7 +577,6 @@ static AST *parse_declaration(Parser *P) {
|
|||||||
|
|
||||||
ASTStmtAssign *assign = malloc(sizeof(*assign));
|
ASTStmtAssign *assign = malloc(sizeof(*assign));
|
||||||
assign->nodeKind = AST_STMT_ASSIGN;
|
assign->nodeKind = AST_STMT_ASSIGN;
|
||||||
assign->next = NULL;
|
|
||||||
|
|
||||||
entry->data.var.reachingDefs = reachingdefs_push(NULL);
|
entry->data.var.reachingDefs = reachingdefs_push(NULL);
|
||||||
reachingdefs_set(entry->data.var.reachingDefs, (AST*) assign);
|
reachingdefs_set(entry->data.var.reachingDefs, (AST*) assign);
|
||||||
@ -710,77 +633,6 @@ backtrack:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Imagine the following pseudocode:
|
|
||||||
x = ...
|
|
||||||
while ... {
|
|
||||||
(do something with x)
|
|
||||||
x = ...
|
|
||||||
}
|
|
||||||
The second definition of x reaches the code *before* it.
|
|
||||||
Therefore we must go over the loop body a second time with known reaching definitions and add the necessary usedefs.*/
|
|
||||||
static void loop_second_pass(AST *a) {
|
|
||||||
if(a->nodeKind == AST_CHUNK) {
|
|
||||||
for(AST *s = a->chunk.statementFirst; s; s = s->statement.next) {
|
|
||||||
loop_second_pass(s);
|
|
||||||
}
|
|
||||||
} else if(a->nodeKind == AST_STMT_IF) {
|
|
||||||
loop_second_pass(a->stmtIf.expression);
|
|
||||||
loop_second_pass(a->stmtIf.then);
|
|
||||||
} else if(a->nodeKind == AST_STMT_LOOP) {
|
|
||||||
loop_second_pass(a->stmtLoop.body);
|
|
||||||
} else if(a->nodeKind == AST_STMT_ASSIGN) {
|
|
||||||
loop_second_pass(a->stmtAssign.what);
|
|
||||||
loop_second_pass(a->stmtAssign.to);
|
|
||||||
|
|
||||||
/* TODO: Per-variable flag.to cease additional usedefs after assignment?
|
|
||||||
It is okay to have too many usedefs, so this isn't high priority.*/
|
|
||||||
} else if(a->nodeKind == AST_STMT_EXPR) {
|
|
||||||
loop_second_pass(a->stmtExpr.expr);
|
|
||||||
} else if(a->nodeKind == AST_EXPR_VAR) {
|
|
||||||
UseDef *udPrev = NULL;
|
|
||||||
UseDef *ud = a->exprVar.thing->data.var.usedefFirst;
|
|
||||||
while(ud && ud->use != a) {
|
|
||||||
udPrev = ud;
|
|
||||||
ud = ud->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ud) {
|
|
||||||
ReachingDefs *defs = a->exprVar.thing->data.var.reachingDefs;
|
|
||||||
while(defs) {
|
|
||||||
for(size_t i = 0; i < defs->defCount; i++) {
|
|
||||||
UseDef *newud = calloc(1, sizeof(*newud));
|
|
||||||
memcpy(newud, ud, sizeof(*ud));
|
|
||||||
newud->def = defs->defs[i];
|
|
||||||
|
|
||||||
udPrev->next = newud;
|
|
||||||
newud->next = ud;
|
|
||||||
ud = newud;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(defs->excludeParent) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
defs = defs->parent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if(a->nodeKind == AST_EXPR_BINARY_OP) {
|
|
||||||
loop_second_pass(a->exprBinOp.operands[0]);
|
|
||||||
loop_second_pass(a->exprBinOp.operands[1]);
|
|
||||||
} else if(a->nodeKind == AST_EXPR_UNARY_OP) {
|
|
||||||
loop_second_pass(a->exprUnOp.operand);
|
|
||||||
} else if(a->nodeKind == AST_EXPR_CAST) {
|
|
||||||
loop_second_pass(a->exprCast.what);
|
|
||||||
} else if(a->nodeKind == AST_EXPR_CALL) {
|
|
||||||
loop_second_pass(a->exprCall.what);
|
|
||||||
|
|
||||||
size_t argCount = a->exprCall.what->expression.type->function.argCount;
|
|
||||||
for(size_t i = 0; i < argCount; i++) {
|
|
||||||
loop_second_pass(a->exprCall.args[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
||||||
if(maybe(P, TOKEN_IF)) {
|
if(maybe(P, TOKEN_IF)) {
|
||||||
@ -805,31 +657,10 @@ void nct_parse_statement(Parser *P) {
|
|||||||
ret->nodeKind = AST_STMT_LOOP;
|
ret->nodeKind = AST_STMT_LOOP;
|
||||||
ret->next = NULL;
|
ret->next = NULL;
|
||||||
|
|
||||||
int isFirstLoop = P->loopScope == NULL;
|
|
||||||
|
|
||||||
if(isFirstLoop) {
|
|
||||||
P->loopScope = P->scope;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(P, TOKEN_SQUIGGLY_L);
|
expect(P, TOKEN_SQUIGGLY_L);
|
||||||
ret->body = (AST*) 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);
|
||||||
|
|
||||||
if(isFirstLoop) {
|
|
||||||
P->loopScope = NULL;
|
|
||||||
|
|
||||||
for(size_t i = 0; i < P->guardedVarCount; i++) {
|
|
||||||
ASTExprVar *ev = P->guardedVars[i];
|
|
||||||
|
|
||||||
newusedef(P, ev->thing, ev);
|
|
||||||
}
|
|
||||||
P->guardedVarCount = 0;
|
|
||||||
free(P->guardedVars);
|
|
||||||
P->guardedVars = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
loop_second_pass(ret->body);
|
|
||||||
|
|
||||||
pushstat(P, ret);
|
pushstat(P, ret);
|
||||||
return;
|
return;
|
||||||
} else if(maybe(P, TOKEN_BREAK)) {
|
} else if(maybe(P, TOKEN_BREAK)) {
|
||||||
@ -918,7 +749,7 @@ void nct_parse_statement(Parser *P) {
|
|||||||
ret->nodeKind = AST_STMT_ASSIGN;
|
ret->nodeKind = AST_STMT_ASSIGN;
|
||||||
ret->next = NULL;
|
ret->next = NULL;
|
||||||
ret->what = e;
|
ret->what = e;
|
||||||
ret->to = 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) {
|
if(ret->what->nodeKind == AST_EXPR_VAR) {
|
||||||
reachingdefs_set(ret->what->exprVar.thing->data.var.reachingDefs, (AST*) ret);
|
reachingdefs_set(ret->what->exprVar.thing->data.var.reachingDefs, (AST*) ret);
|
||||||
@ -942,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;
|
||||||
@ -1017,7 +851,6 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize) {
|
|||||||
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) {
|
||||||
P->topLevel->vars[P->topLevel->varCount++] = P->scope->data[i];
|
P->topLevel->vars[P->topLevel->varCount++] = P->scope->data[i];
|
||||||
P->scope->data[i]->owner = P->topLevel;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ Type *primitive_parse(const char *src) {
|
|||||||
|
|
||||||
TypePrimitive *ret = malloc(sizeof(*ret));
|
TypePrimitive *ret = malloc(sizeof(*ret));
|
||||||
ret->type = TYPE_TYPE_PRIMITIVE;
|
ret->type = TYPE_TYPE_PRIMITIVE;
|
||||||
ret->src = strdup(src);
|
ret->src = src;
|
||||||
|
|
||||||
if(*src == 'n') {
|
if(*src == 'n') {
|
||||||
src++;
|
src++;
|
||||||
|
@ -62,7 +62,6 @@ typedef union Type {
|
|||||||
extern Type TYPE_ERROR;
|
extern Type TYPE_ERROR;
|
||||||
|
|
||||||
Type *primitive_parse(const char*);
|
Type *primitive_parse(const char*);
|
||||||
Type *primitive_make(uint16_t width);
|
|
||||||
|
|
||||||
size_t type_size(Type*);
|
size_t type_size(Type*);
|
||||||
int type_equal(Type*, Type*);
|
int type_equal(Type*, Type*);
|
||||||
|
@ -26,7 +26,6 @@ void reachingdefs_set(struct ReachingDefs *this, union AST *def) {
|
|||||||
this->defCount = 1;
|
this->defCount = 1;
|
||||||
this->defs = realloc(this->defs, sizeof(*this->defs) * this->defCount);
|
this->defs = realloc(this->defs, sizeof(*this->defs) * this->defCount);
|
||||||
this->defs[0] = def;
|
this->defs[0] = def;
|
||||||
this->excludeParent = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VarTable *vartable_new(VarTable *parent) {
|
VarTable *vartable_new(VarTable *parent) {
|
||||||
@ -65,7 +64,6 @@ VarTableEntry *vartable_set(VarTable *this, const char *name, VarTableEntry *e)
|
|||||||
this->data[this->count] = e;
|
this->data[this->count] = e;
|
||||||
this->count++;
|
this->count++;
|
||||||
if(e->kind == VARTABLEENTRY_VAR) e->data.var.name = name;
|
if(e->kind == VARTABLEENTRY_VAR) e->data.var.name = name;
|
||||||
e->owner = this;
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,19 +20,15 @@ typedef struct ReachingDefs {
|
|||||||
size_t defCount;
|
size_t defCount;
|
||||||
union AST **defs;
|
union AST **defs;
|
||||||
|
|
||||||
int excludeParent;
|
|
||||||
struct ReachingDefs *parent;
|
struct ReachingDefs *parent;
|
||||||
} ReachingDefs;
|
} ReachingDefs;
|
||||||
struct ReachingDefs *reachingdefs_push(struct ReachingDefs*);
|
struct ReachingDefs *reachingdefs_push(struct ReachingDefs*);
|
||||||
struct ReachingDefs *reachingdefs_coalesce(struct ReachingDefs*);
|
struct ReachingDefs *reachingdefs_coalesce(struct ReachingDefs*);
|
||||||
void reachingdefs_set(struct ReachingDefs*, union AST*);
|
void reachingdefs_set(struct ReachingDefs*, union AST*);
|
||||||
|
|
||||||
struct VarTable;
|
|
||||||
typedef struct VarTableEntry {
|
typedef struct VarTableEntry {
|
||||||
Type *type;
|
Type *type;
|
||||||
|
|
||||||
struct VarTable *owner;
|
|
||||||
|
|
||||||
VarTableEntryKind kind;
|
VarTableEntryKind kind;
|
||||||
struct {
|
struct {
|
||||||
union {
|
union {
|
||||||
|
35
src/x86.h
35
src/x86.h
@ -1,35 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
// Can expression be expressed as a single x86 operand?
|
|
||||||
#define XOP_NOT_XOP 0
|
|
||||||
#define XOP_NOT_MEM 1
|
|
||||||
#define XOP_MEM 2
|
|
||||||
static inline int is_xop(AST *e) {
|
|
||||||
if(e->nodeKind == AST_EXPR_PRIMITIVE) {
|
|
||||||
return XOP_NOT_MEM;
|
|
||||||
} else if(e->nodeKind == AST_EXPR_VAR) {
|
|
||||||
return e->exprVar.thing->kind == VARTABLEENTRY_VAR ? XOP_NOT_MEM : XOP_MEM;
|
|
||||||
} else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF && e->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP && e->exprUnOp.operand->exprBinOp.operator == BINOP_ADD && e->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[0]->exprVar.thing->kind == VARTABLEENTRY_VAR && e->exprUnOp.operand->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) {
|
|
||||||
return XOP_MEM;
|
|
||||||
} 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) {
|
|
||||||
return XOP_NOT_MEM;
|
|
||||||
} else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF) {
|
|
||||||
AST *c = e->exprUnOp.operand;
|
|
||||||
|
|
||||||
if(c->nodeKind == AST_EXPR_VAR && c->exprVar.thing->kind == VARTABLEENTRY_VAR) {
|
|
||||||
return XOP_MEM;
|
|
||||||
} else if(c->nodeKind == AST_EXPR_BINARY_OP && c->exprBinOp.operator == BINOP_ADD && c->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && c->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && c->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR) {
|
|
||||||
if(c->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR) {
|
|
||||||
return XOP_MEM;
|
|
||||||
} else if(c->exprBinOp.operands[1]->nodeKind == AST_EXPR_BINARY_OP && c->exprBinOp.operands[1]->exprBinOp.operator == BINOP_MUL && c->exprBinOp.operands[1]->exprBinOp.operands[0]->nodeKind == AST_EXPR_PRIMITIVE && c->exprBinOp.operands[1]->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR) {
|
|
||||||
int scale = c->exprBinOp.operands[1]->exprBinOp.operands[0]->exprPrim.val;
|
|
||||||
|
|
||||||
if(scale == 1 || scale == 2 || scale == 4 || scale == 8) {
|
|
||||||
return XOP_MEM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return XOP_NOT_XOP;
|
|
||||||
}
|
|
12
tests/bf.nct
12
tests/bf.nct
@ -30,10 +30,12 @@ loop {
|
|||||||
data[dataPtr] = data[dataPtr] - 1;
|
data[dataPtr] = data[dataPtr] - 1;
|
||||||
}
|
}
|
||||||
if(code[codePtr] == 46) {
|
if(code[codePtr] == 46) {
|
||||||
write(1, &data + dataPtr, 1);
|
u32 z = &data + dataPtr;
|
||||||
|
write(1, z, 1);
|
||||||
}
|
}
|
||||||
if(code[codePtr] == 44) {
|
if(code[codePtr] == 44) {
|
||||||
read(0, &data + dataPtr, 1);
|
u32 z = &data + dataPtr;
|
||||||
|
read(0, z, 1);
|
||||||
}
|
}
|
||||||
if(code[codePtr] == 91) {
|
if(code[codePtr] == 91) {
|
||||||
if(data[dataPtr] == 0) {
|
if(data[dataPtr] == 0) {
|
||||||
@ -72,4 +74,8 @@ loop {
|
|||||||
}
|
}
|
||||||
|
|
||||||
codePtr = codePtr + 1;
|
codePtr = codePtr + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
codePtr;
|
||||||
|
dataPtr;
|
||||||
|
stckPtr;
|
@ -1,6 +1,2 @@
|
|||||||
u32 x: 123;
|
u32 x: 123;
|
||||||
u33 y: 5;
|
u33 y: 5;
|
||||||
|
|
||||||
u3 *o = 5000;
|
|
||||||
u3 z = *o;
|
|
||||||
u3 p = *(o + z);
|
|
@ -2,11 +2,10 @@ u16 x: 5;
|
|||||||
loop {
|
loop {
|
||||||
u16* y = 257;
|
u16* y = 257;
|
||||||
u9 w = -4;
|
u9 w = -4;
|
||||||
u16 p = *y;
|
u4 z = 3 + *y;
|
||||||
u4 z = p + 3;
|
|
||||||
u2 o = -w;
|
u2 o = -w;
|
||||||
|
|
||||||
if(x != 0) {
|
if(x != 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,9 +0,0 @@
|
|||||||
u8 a;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
a = 3;
|
|
||||||
|
|
||||||
u8 b = 1;
|
|
||||||
|
|
||||||
u8 c = 2;
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
u8 a = 5;
|
u8 a = 5;
|
||||||
if(a != 0) {
|
if(a) {
|
||||||
u8 a = 10; /* Should not cause scoping errors. */
|
u8 a = 10; /* Should not cause scoping errors. */
|
||||||
}
|
}
|
||||||
u8 b = 15; /* `a` in the if statement scope should be free'd. */
|
u8 b = 15; /* `a` in the if statement scope should be free'd. */
|
Loading…
Reference in New Issue
Block a user