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_EQ, IR_NE, IR_LT, IR_GT, IR_LE, IR_GE,
|
||||
IR_NEG,
|
||||
IR_LIT,
|
||||
IR_LIT32, IR_LIT64,
|
||||
};
|
||||
|
||||
struct IRblock {
|
||||
|
||||
}
|
||||
|
||||
struct IRinstruction {
|
||||
int op;
|
||||
union {
|
||||
struct { IRinstruction *left, *right; };
|
||||
int val;
|
||||
struct { int left, right; };
|
||||
int val_i32;
|
||||
int val_i64;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
@ -19,28 +19,32 @@ enum {
|
||||
|
||||
extern const char *ast_opname[31];
|
||||
|
||||
#ifndef ACC_ASTnode_SHARED_FIELDS
|
||||
|
||||
// AST structure field shared by all types
|
||||
// llist_node *n : for linklist
|
||||
// llist_node *n : linklist header
|
||||
// int op : node operation
|
||||
#define ASTnode_SHARED_FIELDS \
|
||||
#define ACC_ASTnode_SHARED_FIELDS \
|
||||
struct llist_node n; \
|
||||
int op;
|
||||
|
||||
#endif
|
||||
|
||||
// AST structure (common)
|
||||
struct ASTnode {
|
||||
ASTnode_SHARED_FIELDS
|
||||
ACC_ASTnode_SHARED_FIELDS
|
||||
};
|
||||
|
||||
// AST binary operation node
|
||||
struct ASTbinnode {
|
||||
ASTnode_SHARED_FIELDS
|
||||
ACC_ASTnode_SHARED_FIELDS
|
||||
struct ASTnode *left;
|
||||
struct ASTnode *right;
|
||||
};
|
||||
|
||||
// AST if statement node
|
||||
struct ASTifnode {
|
||||
ASTnode_SHARED_FIELDS
|
||||
ACC_ASTnode_SHARED_FIELDS
|
||||
struct ASTnode *left; // condition true branch
|
||||
struct ASTnode *right; // condition false branch
|
||||
struct ASTnode *cond;
|
||||
@ -48,41 +52,51 @@ struct ASTifnode {
|
||||
|
||||
// AST unary operation node
|
||||
struct ASTunnode {
|
||||
ASTnode_SHARED_FIELDS
|
||||
ACC_ASTnode_SHARED_FIELDS
|
||||
struct ASTnode *left;
|
||||
};
|
||||
|
||||
// AST block node
|
||||
struct ASTblocknode {
|
||||
ASTnode_SHARED_FIELDS
|
||||
ACC_ASTnode_SHARED_FIELDS
|
||||
struct linklist st; // statements linklist
|
||||
};
|
||||
|
||||
// AST integer literal (32bit) node
|
||||
struct ASTi32node {
|
||||
ASTnode_SHARED_FIELDS
|
||||
ACC_ASTnode_SHARED_FIELDS
|
||||
int32_t val;
|
||||
};
|
||||
|
||||
// AST integer literal (64bit) node
|
||||
struct ASTi64node {
|
||||
ASTnode_SHARED_FIELDS
|
||||
ACC_ASTnode_SHARED_FIELDS
|
||||
int64_t val;
|
||||
};
|
||||
|
||||
// AST assign literal node
|
||||
struct ASTassignnode {
|
||||
ASTnode_SHARED_FIELDS
|
||||
ACC_ASTnode_SHARED_FIELDS
|
||||
struct ASTnode* left;
|
||||
struct ASTnode* right;
|
||||
};
|
||||
|
||||
// AST variable value node
|
||||
struct ASTvarnode {
|
||||
ASTnode_SHARED_FIELDS
|
||||
ACC_ASTnode_SHARED_FIELDS
|
||||
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_lit_i32(int32_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_assign(int op, struct ASTnode *left, struct ASTnode *right);
|
||||
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);
|
||||
|
||||
#endif
|
||||
|
@ -7,6 +7,7 @@
|
||||
void* malloc_or_fail(size_t s, const char *func_name);
|
||||
noreturn void fail_target(const char *target_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_ce_expect(int line, const char *expected, const char *got);
|
||||
noreturn void fail_ce(int line, const char *reason);
|
||||
|
@ -1,6 +1,6 @@
|
||||
#ifndef ACC_PARSE_H
|
||||
#define ACC_PARSE_H
|
||||
|
||||
struct ASTnode* parse(const char *name);
|
||||
struct Afunction* parse_source(const char *filename);
|
||||
|
||||
#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"
|
||||
|
||||
struct linklist scan_tokens(const char *name);
|
||||
struct linklist scan_tokens(const char *filename);
|
||||
|
||||
#endif
|
||||
|
@ -3,7 +3,9 @@
|
||||
|
||||
// Target types
|
||||
enum {
|
||||
TARGET_AST
|
||||
TARGET_AST,
|
||||
TARGET_QUAD,
|
||||
TARGET_NULL,
|
||||
};
|
||||
|
||||
int target_parse(const char *target_string);
|
||||
|
@ -3,7 +3,9 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define ACC_ARRAY_LENGTH(a) (sizeof((a))/sizeof(*(a)))
|
||||
|
||||
bool strequal(const char *s1, const char *s2);
|
||||
char *strclone(const char *s);
|
||||
char* strclone(const char *s);
|
||||
|
||||
#endif
|
||||
|
21
main.c
21
main.c
@ -5,7 +5,7 @@
|
||||
#include "parse.h"
|
||||
#include "ast.h"
|
||||
#include "target.h"
|
||||
#include "print_ast.h"
|
||||
#include "quad.h"
|
||||
|
||||
// Print out a usage if started incorrectly
|
||||
static void usage(char *prog) {
|
||||
@ -14,8 +14,13 @@ static void usage(char *prog) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static FILE *Outfile;
|
||||
|
||||
// Do clean up job
|
||||
void unload(void) {
|
||||
if (Outfile && Outfile != stdout) {
|
||||
fclose(Outfile);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
@ -24,19 +29,21 @@ int main(int argc, char *argv[]) {
|
||||
usage(argv[0]);
|
||||
}
|
||||
|
||||
FILE *Outfile;
|
||||
if (argc >= 4) {
|
||||
Outfile = fopen(argv[3], "w");
|
||||
} else {
|
||||
Outfile = fopen("out.txt", "w");
|
||||
Outfile = stdout;
|
||||
}
|
||||
|
||||
int target = target_parse(argv[1]);
|
||||
struct ASTnode *rt = parse(argv[2]);
|
||||
struct Afunction *afunc = parse_source(argv[2]);
|
||||
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);
|
||||
fclose(Outfile);
|
||||
afunc_free(afunc);
|
||||
return (0);
|
||||
}
|
||||
|
89
src/ast.c
89
src/ast.c
@ -16,7 +16,7 @@ const char *ast_opname[] = {
|
||||
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 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);
|
||||
}
|
||||
|
||||
// Make an AST integer literal (32bit) node
|
||||
// Make an AST integer literal (32bits) node
|
||||
struct ASTnode* ast_make_lit_i32(int32_t v) {
|
||||
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);
|
||||
}
|
||||
|
||||
// Make an AST integer literal (64bit) node
|
||||
// Make an AST integer literal (64bits) node
|
||||
struct ASTnode* ast_make_lit_i64(int64_t v) {
|
||||
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);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if (x == NULL) {
|
||||
return;
|
||||
@ -125,10 +201,13 @@ void ast_free(struct ASTnode *x) {
|
||||
ast_free((struct ASTnode*)p);
|
||||
p = nxt;
|
||||
}
|
||||
llist_free(&t->st);
|
||||
} break;
|
||||
|
||||
case A_LIT_I32: case A_LIT_I64: {
|
||||
} break;
|
||||
|
||||
default: {
|
||||
fail_ast_op(x->op, __FUNCTION__);
|
||||
} break;
|
||||
}
|
||||
free(x);
|
||||
|
21
src/fatals.c
21
src/fatals.c
@ -1,6 +1,8 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "scan.h"
|
||||
#include "ast.h"
|
||||
#include "quad.h"
|
||||
|
||||
void fail_target(const char *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);
|
||||
}
|
||||
|
||||
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) {
|
||||
fprintf(stderr, "%s: unknown ast operator %d.\n", func_name, op);
|
||||
exit(1);
|
||||
if (op < A_SOUL) {
|
||||
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) {
|
||||
|
21
src/parse.c
21
src/parse.c
@ -347,11 +347,13 @@ static struct ASTnode* statement(void) {
|
||||
|
||||
// Parse one top-level function
|
||||
// Sets the func_name param.
|
||||
static struct ASTnode* function(char **func_name) {
|
||||
static struct Afunction* function() {
|
||||
struct Afunction *res = afunc_make();
|
||||
|
||||
match(T_INT);
|
||||
expect(T_ID);
|
||||
*func_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.
|
||||
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().
|
||||
next();
|
||||
|
||||
match(T_LP);
|
||||
@ -359,20 +361,19 @@ static struct ASTnode* function(char **func_name) {
|
||||
next();
|
||||
goto END_PARAM_LIST;
|
||||
}
|
||||
// TODO: param list
|
||||
// TODO: parameter list
|
||||
|
||||
END_PARAM_LIST:
|
||||
match(T_RP);
|
||||
return (block());
|
||||
res->rt = block();
|
||||
return (res);
|
||||
}
|
||||
|
||||
// Parse ans return the full ast
|
||||
struct ASTnode* parse(const char *name) {
|
||||
Tokens = scan_tokens(name);
|
||||
char *func_name;
|
||||
struct ASTnode* res = function(&func_name);
|
||||
struct Afunction* parse_source(const char *filename) {
|
||||
Tokens = scan_tokens(filename);
|
||||
struct Afunction* res = function();
|
||||
|
||||
free(func_name);
|
||||
while (Tokens.length > 0) {
|
||||
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 "util/misc.h"
|
||||
#include "fatals.h"
|
||||
#include "target.h"
|
||||
|
||||
// Parse the target string
|
||||
int target_parse(const char *target_string) {
|
||||
static const char *target_map_k[] = {
|
||||
"ast",
|
||||
"quad",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const int target_map_v[] = {
|
||||
TARGET_AST,
|
||||
TARGET_QUAD,
|
||||
};
|
||||
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
@ -2,13 +2,14 @@
|
||||
#include <stdlib.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) {
|
||||
return (strcmp(s1, s2) == 0);
|
||||
}
|
||||
|
||||
// A impl of C23 strdup()
|
||||
// Clones the given string
|
||||
// A impl of C23 strdup().
|
||||
// Clones the given string and returns a pointer.
|
||||
char* strclone(const char *s) {
|
||||
int n = strlen(s);
|
||||
char *res = malloc(n + 1);
|
||||
@ -16,4 +17,3 @@ char* strclone(const char *s) {
|
||||
res[n] = '\0';
|
||||
return res;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user