add quad repersentation
Signed-off-by: szdytom <szdytom@163.com>
This commit is contained in:
parent
24ab2a70f7
commit
38fd3c8911
@ -6,16 +6,21 @@ enum {
|
|||||||
IR_ADD, IR_SUB, IR_MUL, IR_DIV,
|
IR_ADD, IR_SUB, IR_MUL, IR_DIV,
|
||||||
IR_EQ, IR_NE, IR_LT, IR_GT, IR_LE, IR_GE,
|
IR_EQ, IR_NE, IR_LT, IR_GT, IR_LE, IR_GE,
|
||||||
IR_NEG,
|
IR_NEG,
|
||||||
IR_LIT,
|
IR_LIT32, IR_LIT64,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct IRblock {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
struct IRinstruction {
|
struct IRinstruction {
|
||||||
int op;
|
int op;
|
||||||
union {
|
union {
|
||||||
struct { IRinstruction *left, *right; };
|
struct { int left, right; };
|
||||||
int val;
|
int val_i32;
|
||||||
|
int val_i64;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -19,28 +19,32 @@ enum {
|
|||||||
|
|
||||||
extern const char *ast_opname[31];
|
extern const char *ast_opname[31];
|
||||||
|
|
||||||
|
#ifndef ACC_ASTnode_SHARED_FIELDS
|
||||||
|
|
||||||
// AST structure field shared by all types
|
// AST structure field shared by all types
|
||||||
// llist_node *n : for linklist
|
// llist_node *n : linklist header
|
||||||
// int op : node operation
|
// int op : node operation
|
||||||
#define ASTnode_SHARED_FIELDS \
|
#define ACC_ASTnode_SHARED_FIELDS \
|
||||||
struct llist_node n; \
|
struct llist_node n; \
|
||||||
int op;
|
int op;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
// AST structure (common)
|
// AST structure (common)
|
||||||
struct ASTnode {
|
struct ASTnode {
|
||||||
ASTnode_SHARED_FIELDS
|
ACC_ASTnode_SHARED_FIELDS
|
||||||
};
|
};
|
||||||
|
|
||||||
// AST binary operation node
|
// AST binary operation node
|
||||||
struct ASTbinnode {
|
struct ASTbinnode {
|
||||||
ASTnode_SHARED_FIELDS
|
ACC_ASTnode_SHARED_FIELDS
|
||||||
struct ASTnode *left;
|
struct ASTnode *left;
|
||||||
struct ASTnode *right;
|
struct ASTnode *right;
|
||||||
};
|
};
|
||||||
|
|
||||||
// AST if statement node
|
// AST if statement node
|
||||||
struct ASTifnode {
|
struct ASTifnode {
|
||||||
ASTnode_SHARED_FIELDS
|
ACC_ASTnode_SHARED_FIELDS
|
||||||
struct ASTnode *left; // condition true branch
|
struct ASTnode *left; // condition true branch
|
||||||
struct ASTnode *right; // condition false branch
|
struct ASTnode *right; // condition false branch
|
||||||
struct ASTnode *cond;
|
struct ASTnode *cond;
|
||||||
@ -48,41 +52,51 @@ struct ASTifnode {
|
|||||||
|
|
||||||
// AST unary operation node
|
// AST unary operation node
|
||||||
struct ASTunnode {
|
struct ASTunnode {
|
||||||
ASTnode_SHARED_FIELDS
|
ACC_ASTnode_SHARED_FIELDS
|
||||||
struct ASTnode *left;
|
struct ASTnode *left;
|
||||||
};
|
};
|
||||||
|
|
||||||
// AST block node
|
// AST block node
|
||||||
struct ASTblocknode {
|
struct ASTblocknode {
|
||||||
ASTnode_SHARED_FIELDS
|
ACC_ASTnode_SHARED_FIELDS
|
||||||
struct linklist st; // statements linklist
|
struct linklist st; // statements linklist
|
||||||
};
|
};
|
||||||
|
|
||||||
// AST integer literal (32bit) node
|
// AST integer literal (32bit) node
|
||||||
struct ASTi32node {
|
struct ASTi32node {
|
||||||
ASTnode_SHARED_FIELDS
|
ACC_ASTnode_SHARED_FIELDS
|
||||||
int32_t val;
|
int32_t val;
|
||||||
};
|
};
|
||||||
|
|
||||||
// AST integer literal (64bit) node
|
// AST integer literal (64bit) node
|
||||||
struct ASTi64node {
|
struct ASTi64node {
|
||||||
ASTnode_SHARED_FIELDS
|
ACC_ASTnode_SHARED_FIELDS
|
||||||
int64_t val;
|
int64_t val;
|
||||||
};
|
};
|
||||||
|
|
||||||
// AST assign literal node
|
// AST assign literal node
|
||||||
struct ASTassignnode {
|
struct ASTassignnode {
|
||||||
ASTnode_SHARED_FIELDS
|
ACC_ASTnode_SHARED_FIELDS
|
||||||
struct ASTnode* left;
|
struct ASTnode* left;
|
||||||
struct ASTnode* right;
|
struct ASTnode* right;
|
||||||
};
|
};
|
||||||
|
|
||||||
// AST variable value node
|
// AST variable value node
|
||||||
struct ASTvarnode {
|
struct ASTvarnode {
|
||||||
ASTnode_SHARED_FIELDS
|
ACC_ASTnode_SHARED_FIELDS
|
||||||
int id;
|
int id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// A function with its AST root.
|
||||||
|
// TODO: parameters
|
||||||
|
struct Afunction {
|
||||||
|
struct llist_node n; // linklist header
|
||||||
|
char *name; // function name
|
||||||
|
struct ASTnode *rt; // AST root
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Afunction* afunc_make();
|
||||||
|
|
||||||
struct ASTnode* ast_make_binary(int op, struct ASTnode *left, struct ASTnode *right);
|
struct ASTnode* ast_make_binary(int op, struct ASTnode *left, struct ASTnode *right);
|
||||||
struct ASTnode* ast_make_lit_i32(int32_t x);
|
struct ASTnode* ast_make_lit_i32(int32_t x);
|
||||||
struct ASTnode* ast_make_lit_i64(int64_t x);
|
struct ASTnode* ast_make_lit_i64(int64_t x);
|
||||||
@ -91,6 +105,11 @@ struct ASTnode* ast_make_block();
|
|||||||
struct ASTnode* ast_make_var(int id);
|
struct ASTnode* ast_make_var(int id);
|
||||||
struct ASTnode* ast_make_assign(int op, struct ASTnode *left, struct ASTnode *right);
|
struct ASTnode* ast_make_assign(int op, struct ASTnode *left, struct ASTnode *right);
|
||||||
struct ASTnode* ast_make_if(struct ASTnode *left, struct ASTnode *right, struct ASTnode *cond);
|
struct ASTnode* ast_make_if(struct ASTnode *left, struct ASTnode *right, struct ASTnode *cond);
|
||||||
|
|
||||||
|
void ast_debug_print(FILE *Outfile, struct ASTnode *rt);
|
||||||
|
void afunc_debug_print(FILE *Outfile, struct Afunction *f);
|
||||||
|
|
||||||
|
void afunc_free(struct Afunction *f);
|
||||||
void ast_free(struct ASTnode *x);
|
void ast_free(struct ASTnode *x);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
void* malloc_or_fail(size_t s, const char *func_name);
|
void* malloc_or_fail(size_t s, const char *func_name);
|
||||||
noreturn void fail_target(const char *target_name);
|
noreturn void fail_target(const char *target_name);
|
||||||
noreturn void fail_malloc(const char *func_name);
|
noreturn void fail_malloc(const char *func_name);
|
||||||
|
noreturn void fail_quad_op(int op, const char *func_name);
|
||||||
noreturn void fail_ast_op(int op, const char *func_name);
|
noreturn void fail_ast_op(int op, const char *func_name);
|
||||||
noreturn void fail_ce_expect(int line, const char *expected, const char *got);
|
noreturn void fail_ce_expect(int line, const char *expected, const char *got);
|
||||||
noreturn void fail_ce(int line, const char *reason);
|
noreturn void fail_ce(int line, const char *reason);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#ifndef ACC_PARSE_H
|
#ifndef ACC_PARSE_H
|
||||||
#define ACC_PARSE_H
|
#define ACC_PARSE_H
|
||||||
|
|
||||||
struct ASTnode* parse(const char *name);
|
struct Afunction* parse_source(const char *filename);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
#ifndef ACC_DEBUG_PRINT_AST
|
|
||||||
#define ACC_DEBUG_PRINT_AST
|
|
||||||
|
|
||||||
void debug_ast_print(FILE *Outfile, struct ASTnode *rt);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
96
include/quad.h
Normal file
96
include/quad.h
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
#ifndef ACC_QUAD_H
|
||||||
|
#define ACC_QUAD_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "ast.h"
|
||||||
|
#include "util/linklist.h"
|
||||||
|
|
||||||
|
// Operation code definations
|
||||||
|
enum {
|
||||||
|
// Loading immediates
|
||||||
|
Q_IMM_I32, // integer (32bits)
|
||||||
|
|
||||||
|
// Terminates
|
||||||
|
Q_RET, // return
|
||||||
|
Q_BR_ALWAYS, // conditional goto: always goto true branch.
|
||||||
|
|
||||||
|
// Guard
|
||||||
|
Q_NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Local(in function) variable.
|
||||||
|
struct Qvar {
|
||||||
|
struct llist_node n; // linklist header
|
||||||
|
int id; // variable id
|
||||||
|
};
|
||||||
|
|
||||||
|
// Quad instruction.
|
||||||
|
struct Quad {
|
||||||
|
struct llist_node n; // linklist header
|
||||||
|
int op; // operation code
|
||||||
|
struct Qvar *dest; // operation destination
|
||||||
|
union {
|
||||||
|
struct { struct Qvar *left, *right; }; // left/right operands for calculations
|
||||||
|
struct { struct Qblock *bt, *bf; }; // true branch & false branch for conditional goto
|
||||||
|
int32_t val_i32; // immediate: integer (32bits)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Basic block consist of Quad instructions.
|
||||||
|
struct Qblock {
|
||||||
|
struct llist_node n; // linklist header
|
||||||
|
int id; // block id
|
||||||
|
struct linklist ins; // instruction Quads
|
||||||
|
bool is_complete; // whether the block is properly ended with a terminate
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function containing Quad instructions.
|
||||||
|
// TODO: paramaters
|
||||||
|
struct Qfunction {
|
||||||
|
struct llist_node n; // linklist header
|
||||||
|
char *name; // function name
|
||||||
|
struct linklist bs; // basic blocks
|
||||||
|
struct linklist vars; // local variables
|
||||||
|
};
|
||||||
|
|
||||||
|
// Constructs a Quad with an operator, a destination and two operands.
|
||||||
|
struct Quad* quad_make(int op, struct Qvar *dest, struct Qvar *left, struct Qvar *right);
|
||||||
|
|
||||||
|
// Constructs a Quad with a loads an integer immediate (32bits).
|
||||||
|
struct Quad* quad_make_i32(struct Qvar *dest, int32_t v);
|
||||||
|
|
||||||
|
// Constructs a Quad with instruction Q_BR_XXX (conditional goto).
|
||||||
|
struct Quad* quad_make_br(int op, struct Qblock *bt, struct Qblock *bf);
|
||||||
|
|
||||||
|
// Returns whether the given opcode is a opcode from a terminate.
|
||||||
|
bool quad_is_terminate(int op);
|
||||||
|
|
||||||
|
// Constructs a Qblock.
|
||||||
|
struct Qblock* qblock_make();
|
||||||
|
|
||||||
|
// Allocates a new basic block in the give function.
|
||||||
|
struct Qblock* qfunc_new_block(struct Qfunction *f);
|
||||||
|
|
||||||
|
// Appends an instruction to a block.
|
||||||
|
void qblock_add_ins(struct Qblock *b, struct Quad *x);
|
||||||
|
|
||||||
|
// Constructs a new Qvar.
|
||||||
|
struct Qvar* qvar_make(int id);
|
||||||
|
|
||||||
|
// Allocates a new variable in the given function.
|
||||||
|
struct Qvar* qfunc_new_var(struct Qfunction *f);
|
||||||
|
|
||||||
|
// Generates Quad Repersentation from an AST
|
||||||
|
struct Qfunction* qfunc_cgenerate(struct Afunction *afunc);
|
||||||
|
|
||||||
|
// Frees a Qblock and all its components.
|
||||||
|
void qblock_free(struct Qblock *b);
|
||||||
|
|
||||||
|
// Frees a Qfunction and all its components.
|
||||||
|
void qfunc_free(struct Qfunction *f);
|
||||||
|
|
||||||
|
// Prints the contents of a Qfunction for debugging.
|
||||||
|
void qfunc_debug_print(struct Qfunction *self, FILE *Outfile);
|
||||||
|
|
||||||
|
#endif
|
@ -3,6 +3,6 @@
|
|||||||
|
|
||||||
#include "util/linklist.h"
|
#include "util/linklist.h"
|
||||||
|
|
||||||
struct linklist scan_tokens(const char *name);
|
struct linklist scan_tokens(const char *filename);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
|
|
||||||
// Target types
|
// Target types
|
||||||
enum {
|
enum {
|
||||||
TARGET_AST
|
TARGET_AST,
|
||||||
|
TARGET_QUAD,
|
||||||
|
TARGET_NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
int target_parse(const char *target_string);
|
int target_parse(const char *target_string);
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define ACC_ARRAY_LENGTH(a) (sizeof((a))/sizeof(*(a)))
|
||||||
|
|
||||||
bool strequal(const char *s1, const char *s2);
|
bool strequal(const char *s1, const char *s2);
|
||||||
char *strclone(const char *s);
|
char* strclone(const char *s);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
21
main.c
21
main.c
@ -5,7 +5,7 @@
|
|||||||
#include "parse.h"
|
#include "parse.h"
|
||||||
#include "ast.h"
|
#include "ast.h"
|
||||||
#include "target.h"
|
#include "target.h"
|
||||||
#include "print_ast.h"
|
#include "quad.h"
|
||||||
|
|
||||||
// Print out a usage if started incorrectly
|
// Print out a usage if started incorrectly
|
||||||
static void usage(char *prog) {
|
static void usage(char *prog) {
|
||||||
@ -14,8 +14,13 @@ static void usage(char *prog) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static FILE *Outfile;
|
||||||
|
|
||||||
// Do clean up job
|
// Do clean up job
|
||||||
void unload(void) {
|
void unload(void) {
|
||||||
|
if (Outfile && Outfile != stdout) {
|
||||||
|
fclose(Outfile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
@ -24,19 +29,21 @@ int main(int argc, char *argv[]) {
|
|||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *Outfile;
|
|
||||||
if (argc >= 4) {
|
if (argc >= 4) {
|
||||||
Outfile = fopen(argv[3], "w");
|
Outfile = fopen(argv[3], "w");
|
||||||
} else {
|
} else {
|
||||||
Outfile = fopen("out.txt", "w");
|
Outfile = stdout;
|
||||||
}
|
}
|
||||||
|
|
||||||
int target = target_parse(argv[1]);
|
int target = target_parse(argv[1]);
|
||||||
struct ASTnode *rt = parse(argv[2]);
|
struct Afunction *afunc = parse_source(argv[2]);
|
||||||
if (target == TARGET_AST) {
|
if (target == TARGET_AST) {
|
||||||
debug_ast_print(Outfile, rt);
|
afunc_debug_print(Outfile, afunc);
|
||||||
|
} else if (target == TARGET_QUAD) {
|
||||||
|
struct Qfunction *qfunc = qfunc_cgenerate(afunc);
|
||||||
|
qfunc_debug_print(qfunc, Outfile);
|
||||||
|
qfunc_free(qfunc);
|
||||||
}
|
}
|
||||||
ast_free(rt);
|
afunc_free(afunc);
|
||||||
fclose(Outfile);
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
89
src/ast.c
89
src/ast.c
@ -16,7 +16,7 @@ const char *ast_opname[] = {
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
// Build and return a binary AST node
|
// Constructs a binary AST node
|
||||||
struct ASTnode* ast_make_binary(int op, struct ASTnode *left, struct ASTnode *right) {
|
struct ASTnode* ast_make_binary(int op, struct ASTnode *left, struct ASTnode *right) {
|
||||||
struct ASTbinnode *x = malloc_or_fail(sizeof(struct ASTbinnode), __FUNCTION__);
|
struct ASTbinnode *x = malloc_or_fail(sizeof(struct ASTbinnode), __FUNCTION__);
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ struct ASTnode* ast_make_binary(int op, struct ASTnode *left, struct ASTnode *ri
|
|||||||
return ((struct ASTnode*)x);
|
return ((struct ASTnode*)x);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make an AST integer literal (32bit) node
|
// Make an AST integer literal (32bits) node
|
||||||
struct ASTnode* ast_make_lit_i32(int32_t v) {
|
struct ASTnode* ast_make_lit_i32(int32_t v) {
|
||||||
struct ASTi32node *x = malloc_or_fail(sizeof(struct ASTi32node), __FUNCTION__);
|
struct ASTi32node *x = malloc_or_fail(sizeof(struct ASTi32node), __FUNCTION__);
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ struct ASTnode* ast_make_lit_i32(int32_t v) {
|
|||||||
return ((struct ASTnode*)x);
|
return ((struct ASTnode*)x);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make an AST integer literal (64bit) node
|
// Make an AST integer literal (64bits) node
|
||||||
struct ASTnode* ast_make_lit_i64(int64_t v) {
|
struct ASTnode* ast_make_lit_i64(int64_t v) {
|
||||||
struct ASTi64node *x = malloc_or_fail(sizeof(struct ASTi64node), __FUNCTION__);
|
struct ASTi64node *x = malloc_or_fail(sizeof(struct ASTi64node), __FUNCTION__);
|
||||||
|
|
||||||
@ -92,7 +92,83 @@ struct ASTnode* ast_make_if(struct ASTnode *left, struct ASTnode *right, struct
|
|||||||
return ((struct ASTnode*)x);
|
return ((struct ASTnode*)x);
|
||||||
}
|
}
|
||||||
|
|
||||||
// free an AST's memory
|
static void ast_print_dfs(FILE* Outfile, struct ASTnode *x, int tabs) {
|
||||||
|
for (int i = 0; i < tabs; ++i) {
|
||||||
|
fprintf(Outfile, "\t");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x == NULL) {
|
||||||
|
fprintf(Outfile, "--->NULL.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(x->op) {
|
||||||
|
case A_RETURN: case A_PRINT: {
|
||||||
|
struct ASTunnode *t = (struct ASTunnode*)x;
|
||||||
|
fprintf(Outfile, "--->UNOP(%s)\n", ast_opname[x->op]);
|
||||||
|
ast_print_dfs(Outfile, t->left, tabs + 1);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case A_LIT_I32: {
|
||||||
|
struct ASTi32node *t = (struct ASTi32node*)x;
|
||||||
|
fprintf(Outfile, "--->INT32(%d)\n", t->val);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case A_LIT_I64: {
|
||||||
|
struct ASTi64node *t = (struct ASTi64node*)x;
|
||||||
|
fprintf(Outfile, "--->INT64(%lld)\n", t->val);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case A_BLOCK: {
|
||||||
|
struct ASTblocknode *t = (struct ASTblocknode*)x;
|
||||||
|
fprintf(Outfile, "--->BLOCK(%d statements)\n", t->st.length);
|
||||||
|
struct llist_node *p = t->st.head;
|
||||||
|
while (p) {
|
||||||
|
ast_print_dfs(Outfile, (struct ASTnode*)p, tabs + 1);
|
||||||
|
p = p->nxt;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
fail_ast_op(x->op, __FUNCTION__);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints the structure of a AST into Outfile.
|
||||||
|
void ast_debug_print(FILE *Outfile, struct ASTnode *rt) {
|
||||||
|
ast_print_dfs(Outfile, rt, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints the structure of a Afunction into Outfile.
|
||||||
|
void afunc_debug_print(FILE *Outfile, struct Afunction *f) {
|
||||||
|
fprintf(Outfile, "FUNCTION %s: \n", f->name);
|
||||||
|
ast_print_dfs(Outfile, f->rt, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructs a Afunction.
|
||||||
|
struct Afunction* afunc_make() {
|
||||||
|
struct Afunction *res = (struct Afunction*)malloc_or_fail(sizeof(struct Afunction), __FUNCTION__);
|
||||||
|
|
||||||
|
res->rt = NULL;
|
||||||
|
res->name = NULL;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Frees a Afunction and all its components.
|
||||||
|
void afunc_free(struct Afunction *f) {
|
||||||
|
if (f->name) {
|
||||||
|
free(f->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f->rt) {
|
||||||
|
ast_free(f->rt);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Frees an AST's memory, including its childs.
|
||||||
void ast_free(struct ASTnode *x) {
|
void ast_free(struct ASTnode *x) {
|
||||||
if (x == NULL) {
|
if (x == NULL) {
|
||||||
return;
|
return;
|
||||||
@ -125,10 +201,13 @@ void ast_free(struct ASTnode *x) {
|
|||||||
ast_free((struct ASTnode*)p);
|
ast_free((struct ASTnode*)p);
|
||||||
p = nxt;
|
p = nxt;
|
||||||
}
|
}
|
||||||
llist_free(&t->st);
|
} break;
|
||||||
|
|
||||||
|
case A_LIT_I32: case A_LIT_I64: {
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
|
fail_ast_op(x->op, __FUNCTION__);
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
free(x);
|
free(x);
|
||||||
|
21
src/fatals.c
21
src/fatals.c
@ -1,6 +1,8 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "scan.h"
|
#include "scan.h"
|
||||||
|
#include "ast.h"
|
||||||
|
#include "quad.h"
|
||||||
|
|
||||||
void fail_target(const char *target_name) {
|
void fail_target(const char *target_name) {
|
||||||
fprintf(stderr, "unknown target: %s.\n", target_name);
|
fprintf(stderr, "unknown target: %s.\n", target_name);
|
||||||
@ -20,9 +22,24 @@ void* malloc_or_fail(size_t s, const char *func_name) {
|
|||||||
return (res);
|
return (res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void fail_quad_op(int op, const char *func_name) {
|
||||||
|
if (op < Q_NULL) {
|
||||||
|
fprintf(stderr, "%s: unsupported Quad operator %s.\n", func_name, ast_opname[op]);
|
||||||
|
exit(1);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "%s: unknown Quad operator %d.\n", func_name, op);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void fail_ast_op(int op, const char *func_name) {
|
void fail_ast_op(int op, const char *func_name) {
|
||||||
fprintf(stderr, "%s: unknown ast operator %d.\n", func_name, op);
|
if (op < A_SOUL) {
|
||||||
exit(1);
|
fprintf(stderr, "%s: unsupported AST operator %s.\n", func_name, ast_opname[op]);
|
||||||
|
exit(1);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "%s: unknown AST operator %d.\n", func_name, op);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void fail_ce_expect(int line, const char *expected, const char *got) {
|
void fail_ce_expect(int line, const char *expected, const char *got) {
|
||||||
|
21
src/parse.c
21
src/parse.c
@ -347,11 +347,13 @@ static struct ASTnode* statement(void) {
|
|||||||
|
|
||||||
// Parse one top-level function
|
// Parse one top-level function
|
||||||
// Sets the func_name param.
|
// Sets the func_name param.
|
||||||
static struct ASTnode* function(char **func_name) {
|
static struct Afunction* function() {
|
||||||
|
struct Afunction *res = afunc_make();
|
||||||
|
|
||||||
match(T_INT);
|
match(T_INT);
|
||||||
expect(T_ID);
|
expect(T_ID);
|
||||||
*func_name = current()->val_s; // transfer ownership of the identifier string to caller
|
res->name = current()->val_s; // transfer ownership of the identifier string to caller
|
||||||
current()->val_s = NULL; // prevent it from being freed in token_free() called by next.
|
current()->val_s = NULL; // prevent it from being freed in token_free() called by next().
|
||||||
next();
|
next();
|
||||||
|
|
||||||
match(T_LP);
|
match(T_LP);
|
||||||
@ -359,20 +361,19 @@ static struct ASTnode* function(char **func_name) {
|
|||||||
next();
|
next();
|
||||||
goto END_PARAM_LIST;
|
goto END_PARAM_LIST;
|
||||||
}
|
}
|
||||||
// TODO: param list
|
// TODO: parameter list
|
||||||
|
|
||||||
END_PARAM_LIST:
|
END_PARAM_LIST:
|
||||||
match(T_RP);
|
match(T_RP);
|
||||||
return (block());
|
res->rt = block();
|
||||||
|
return (res);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse ans return the full ast
|
// Parse ans return the full ast
|
||||||
struct ASTnode* parse(const char *name) {
|
struct Afunction* parse_source(const char *filename) {
|
||||||
Tokens = scan_tokens(name);
|
Tokens = scan_tokens(filename);
|
||||||
char *func_name;
|
struct Afunction* res = function();
|
||||||
struct ASTnode* res = function(&func_name);
|
|
||||||
|
|
||||||
free(func_name);
|
|
||||||
while (Tokens.length > 0) {
|
while (Tokens.length > 0) {
|
||||||
token_free(llist_popfront(&Tokens));
|
token_free(llist_popfront(&Tokens));
|
||||||
}
|
}
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "ast.h"
|
|
||||||
#include "print_ast.h"
|
|
||||||
#include "symbol.h"
|
|
||||||
#include "fatals.h"
|
|
||||||
#include "util/array.h"
|
|
||||||
|
|
||||||
static int tabs;
|
|
||||||
|
|
||||||
static void print_tabs(FILE* Outfile) {
|
|
||||||
for (int i = 0; i < tabs; ++i) {
|
|
||||||
fprintf(Outfile, "\t");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ast_dfs(FILE* Outfile, struct ASTnode *x) {
|
|
||||||
print_tabs(Outfile);
|
|
||||||
if (x == NULL) {
|
|
||||||
fprintf(Outfile, "--->NULL.\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(x->op) {
|
|
||||||
case A_RETURN: case A_PRINT: {
|
|
||||||
struct ASTunnode *t = (struct ASTunnode*)x;
|
|
||||||
fprintf(Outfile, "--->UNOP(%s)\n", ast_opname[x->op]);
|
|
||||||
tabs += 1;
|
|
||||||
ast_dfs(Outfile, t->left);
|
|
||||||
tabs -= 1;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case A_LIT_I32: {
|
|
||||||
struct ASTi32node *t = (struct ASTi32node*)x;
|
|
||||||
fprintf(Outfile, "--->INT32(%d)\n", t->val);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case A_LIT_I64: {
|
|
||||||
struct ASTi64node *t = (struct ASTi64node*)x;
|
|
||||||
fprintf(Outfile, "--->INT64(%lld)\n", t->val);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case A_BLOCK: {
|
|
||||||
struct ASTblocknode *t = (struct ASTblocknode*)x;
|
|
||||||
fprintf(Outfile, "--->BLOCK(%d statements)\n", t->st.length);
|
|
||||||
tabs += 1;
|
|
||||||
struct llist_node *p = t->st.head;
|
|
||||||
while (p) {
|
|
||||||
ast_dfs(Outfile, (struct ASTnode*)p);
|
|
||||||
p = p->nxt;
|
|
||||||
}
|
|
||||||
tabs -= 1;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default: {
|
|
||||||
fprintf(Outfile, "--->%s...\n", ast_opname[x->op]);
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void debug_ast_print(FILE *Outfile, struct ASTnode *rt) {
|
|
||||||
tabs = 0;
|
|
||||||
ast_dfs(Outfile, rt);
|
|
||||||
}
|
|
||||||
|
|
193
src/quad.c
Normal file
193
src/quad.c
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "quad.h"
|
||||||
|
#include "fatals.h"
|
||||||
|
|
||||||
|
// Constructs a Quad with an operator, a destination and two operands.
|
||||||
|
struct Quad* quad_make(int op, struct Qvar *dest, struct Qvar *left, struct Qvar *right) {
|
||||||
|
struct Quad *x = malloc_or_fail(sizeof(struct Quad), __FUNCTION__);
|
||||||
|
|
||||||
|
x->op = op;
|
||||||
|
x->dest = dest;
|
||||||
|
x->left = left;
|
||||||
|
x->right = right;
|
||||||
|
return (x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructs a Quad with a loads an integer immediate (32bits).
|
||||||
|
struct Quad* quad_make_i32(struct Qvar *dest, int32_t v) {
|
||||||
|
struct Quad *x = malloc_or_fail(sizeof(struct Quad), __FUNCTION__);
|
||||||
|
|
||||||
|
x->op = Q_IMM_I32;
|
||||||
|
x->dest = dest;
|
||||||
|
x->val_i32 = v;
|
||||||
|
return (x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructs a Quad with instruction Q_BR_XXX (conditional goto).
|
||||||
|
struct Quad* quad_make_br(int op, struct Qblock *bt, struct Qblock *bf) {
|
||||||
|
struct Quad *x = malloc_or_fail(sizeof(struct Quad), __FUNCTION__);
|
||||||
|
|
||||||
|
x->op = op;
|
||||||
|
x->bt = bt;
|
||||||
|
x->bf = bf;
|
||||||
|
return (x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns whether the given opcode is a opcode from a terminate.
|
||||||
|
bool quad_is_terminate(int op) {
|
||||||
|
switch (op) {
|
||||||
|
case Q_RET:
|
||||||
|
case Q_BR_ALWAYS:
|
||||||
|
return (true);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructs a Qblock.
|
||||||
|
struct Qblock* qblock_make(int id) {
|
||||||
|
struct Qblock *x = malloc_or_fail(sizeof(struct Qblock), __FUNCTION__);
|
||||||
|
llist_init(&x->ins);
|
||||||
|
x->id = id;
|
||||||
|
x->is_complete = false;
|
||||||
|
return (x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocates a new basic block in the give function.
|
||||||
|
struct Qblock* qfunc_new_block(struct Qfunction *f) {
|
||||||
|
struct Qblock *x = qblock_make(f->bs.length);
|
||||||
|
llist_pushback(&f->bs, x);
|
||||||
|
return (x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Appends an instruction to a block.
|
||||||
|
void qblock_add_ins(struct Qblock *b, struct Quad *x) {
|
||||||
|
if (b->is_complete) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
llist_pushback(&b->ins, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructs a new Qvar.
|
||||||
|
struct Qvar* qvar_make(int id) {
|
||||||
|
struct Qvar *res = malloc_or_fail(sizeof(struct Qvar), __FUNCTION__);
|
||||||
|
res->id = id;
|
||||||
|
return (res);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocates a new variable in the given function.
|
||||||
|
struct Qvar* qfunc_new_var(struct Qfunction *f) {
|
||||||
|
struct Qvar *res = qvar_make(f->vars.length);
|
||||||
|
llist_pushback(&f->vars, res);
|
||||||
|
return (res);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct Qvar* qcg_dfs(struct ASTnode *x, struct Qfunction *f, struct Qblock *b) {
|
||||||
|
switch (x->op) {
|
||||||
|
case A_RETURN: {
|
||||||
|
struct ASTunnode *t = (void*)x;
|
||||||
|
struct Qvar *value = qcg_dfs(t->left, f, b);
|
||||||
|
qblock_add_ins(b, quad_make(Q_RET, NULL, value, NULL));
|
||||||
|
b->is_complete = true;
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
case A_LIT_I32: {
|
||||||
|
struct ASTi32node *t = (void*)x;
|
||||||
|
struct Qvar *res = qfunc_new_var(f);
|
||||||
|
qblock_add_ins(b, quad_make_i32(res, t->val));
|
||||||
|
return (res);
|
||||||
|
}
|
||||||
|
|
||||||
|
case A_BLOCK: {
|
||||||
|
struct ASTblocknode *t = (void*)x;
|
||||||
|
struct llist_node *p = t->st.head;
|
||||||
|
while (p) {
|
||||||
|
qcg_dfs((struct ASTnode*)p, f, b);
|
||||||
|
p = p->nxt;
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
fail_ast_op(x->op, __FUNCTION__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generates Quad Repersentation from an AST
|
||||||
|
struct Qfunction* qfunc_cgenerate(struct Afunction *afunc) {
|
||||||
|
struct Qfunction *self = malloc_or_fail(sizeof(struct Qfunction), __FUNCTION__);
|
||||||
|
|
||||||
|
self->name = afunc->name; // transfer ownership of function name string
|
||||||
|
afunc->name = NULL; // prevents the pointer being freed when freeing the Afunction
|
||||||
|
|
||||||
|
llist_init(&self->bs);
|
||||||
|
llist_init(&self->vars);
|
||||||
|
|
||||||
|
struct Qblock *entry = qfunc_new_block(self);
|
||||||
|
qcg_dfs(afunc->rt, self, entry);
|
||||||
|
return (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Frees a Qblock and all its components.
|
||||||
|
void qblock_free(struct Qblock *b) {
|
||||||
|
llist_free(&b->ins);
|
||||||
|
free(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Frees a Qfunction and all its components.
|
||||||
|
void qfunc_free(struct Qfunction *f) {
|
||||||
|
if (f->name) {
|
||||||
|
free(f->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct llist_node *p = f->bs.head, *nxt;
|
||||||
|
while (p) {
|
||||||
|
nxt = p->nxt;
|
||||||
|
qblock_free((struct Qblock*)p);
|
||||||
|
p = nxt;
|
||||||
|
}
|
||||||
|
|
||||||
|
llist_free(&f->vars);
|
||||||
|
free(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints the given instruction for debugging.
|
||||||
|
static void quad_debug_print(struct Quad *self, FILE *Outfile) {
|
||||||
|
switch(self->op) {
|
||||||
|
case Q_IMM_I32: {
|
||||||
|
fprintf(Outfile, "\t$%d = i32 %d;\n", self->dest->id, self->val_i32);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Q_RET: {
|
||||||
|
fprintf(Outfile, "\tret $%d.\n", self->left->id);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
fail_quad_op(self->op, __FUNCTION__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints the contents of a Qblock for debugging.
|
||||||
|
static void qblock_debug_print(struct Qblock *self, FILE *Outfile) {
|
||||||
|
fprintf(Outfile, "L%d:\n", self->id);
|
||||||
|
struct llist_node *p = self->ins.head;
|
||||||
|
while (p) {
|
||||||
|
quad_debug_print((struct Quad*)p, Outfile);
|
||||||
|
p = p->nxt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints the contents of a Qfunction for debugging.
|
||||||
|
void qfunc_debug_print(struct Qfunction *self, FILE *Outfile) {
|
||||||
|
fprintf(Outfile, "%s:\n", self->name);
|
||||||
|
struct llist_node *p = self->bs.head;
|
||||||
|
while (p) {
|
||||||
|
qblock_debug_print((struct Qblock*)p, Outfile);
|
||||||
|
p = p->nxt;
|
||||||
|
}
|
||||||
|
}
|
@ -1,19 +1,23 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "util/misc.h"
|
||||||
#include "fatals.h"
|
#include "fatals.h"
|
||||||
#include "target.h"
|
#include "target.h"
|
||||||
|
|
||||||
|
// Parse the target string
|
||||||
int target_parse(const char *target_string) {
|
int target_parse(const char *target_string) {
|
||||||
static const char *target_map_k[] = {
|
static const char *target_map_k[] = {
|
||||||
"ast",
|
"ast",
|
||||||
|
"quad",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int target_map_v[] = {
|
static const int target_map_v[] = {
|
||||||
TARGET_AST,
|
TARGET_AST,
|
||||||
|
TARGET_QUAD,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; target_map_k[i]; ++i) {
|
for (int i = 0; target_map_k[i]; ++i) {
|
||||||
if (strcmp(target_map_k[i], target_string) == 0) {
|
if (strequal(target_map_k[i], target_string)) {
|
||||||
return (target_map_v[i]);
|
return (target_map_v[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,14 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "util/misc.h"
|
#include "util/misc.h"
|
||||||
|
|
||||||
// check if two string are the same
|
// This function does what you think it does :)
|
||||||
|
// Returns whether the given strings are the same.
|
||||||
bool strequal(const char *s1, const char *s2) {
|
bool strequal(const char *s1, const char *s2) {
|
||||||
return (strcmp(s1, s2) == 0);
|
return (strcmp(s1, s2) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// A impl of C23 strdup()
|
// A impl of C23 strdup().
|
||||||
// Clones the given string
|
// Clones the given string and returns a pointer.
|
||||||
char* strclone(const char *s) {
|
char* strclone(const char *s) {
|
||||||
int n = strlen(s);
|
int n = strlen(s);
|
||||||
char *res = malloc(n + 1);
|
char *res = malloc(n + 1);
|
||||||
@ -16,4 +17,3 @@ char* strclone(const char *s) {
|
|||||||
res[n] = '\0';
|
res[n] = '\0';
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user