From e1211ebf619f8079612e2b547ebda6685263424c Mon Sep 17 00:00:00 2001 From: szdytom Date: Thu, 15 Jun 2023 14:53:14 +0800 Subject: [PATCH] add value type in ast Signed-off-by: szdytom --- include/ast.h | 13 ++++---- include/fatals.h | 2 ++ include/token.h | 2 +- include/vtype.h | 39 ++++++++++++++++++++++++ src/ast.c | 67 ++++++++++++++++++++++++----------------- src/fatals.c | 11 +++++++ src/parse.c | 52 ++++++++++++++++++++++---------- src/scan.c | 2 -- src/token.c | 2 +- src/vtype.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 213 insertions(+), 55 deletions(-) create mode 100644 include/vtype.h create mode 100644 src/vtype.c diff --git a/include/ast.h b/include/ast.h index b6569b1..e70e610 100644 --- a/include/ast.h +++ b/include/ast.h @@ -3,6 +3,7 @@ #include #include +#include "vtype.h" #include "util/linklist.h" // AST operation types @@ -22,17 +23,15 @@ enum { extern const char *ast_opname[31]; -#ifndef ACC_ASTnode_SHARED_FIELDS - // AST structure field shared by all types // llist_node *n : linklist header +// struct VType type : value type // int op : node operation -#define ACC_ASTnode_SHARED_FIELDS \ - struct llist_node n; \ +#define ACC_ASTnode_SHARED_FIELDS \ + struct llist_node n; \ + struct VType type; \ int op; -#endif - // AST structure (common) struct ASTnode { ACC_ASTnode_SHARED_FIELDS @@ -103,7 +102,7 @@ struct Afunction* Afunction_new(); struct ASTnode* ASTbinnode_new(int op, struct ASTnode *left, struct ASTnode *right); struct ASTnode* ASTi32node_new(int32_t x); struct ASTnode* ASTi64node_new(int64_t x); -struct ASTnode* ASTunnode_new(int op, struct ASTnode *c); +struct ASTnode* ASTunnode_new(int op, struct ASTnode *c, int line); struct ASTnode* ASTblocknode_new(); struct ASTnode* ASTvarnode_new(int id); struct ASTnode* ASTassignnode_new(int op, struct ASTnode *left, struct ASTnode *right); diff --git a/include/fatals.h b/include/fatals.h index 5e05f91..2d74ed7 100644 --- a/include/fatals.h +++ b/include/fatals.h @@ -4,6 +4,8 @@ #include #include +noreturn void fail_type(int line); +noreturn void fail_todo(const char *func_name); noreturn void fail_target(const char *target_name); noreturn void fail_malloc(const char *func_name); noreturn void fail_ir_op(int op, const char *func_name); diff --git a/include/token.h b/include/token.h index e83bfdf..693fa31 100644 --- a/include/token.h +++ b/include/token.h @@ -29,7 +29,7 @@ enum { T_EQ, T_NE, T_LT, T_GT, T_LE, T_GE, // == != < > <= >= T_INT, T_VOID, T_CHAR, T_LONG, // int void char long T_SHORT, // short - T_PRINT, T_IF, T_ELSE, // print if else + T_IF, T_ELSE, // if else T_WHILE, T_FOR, // while for T_RETURN, // return T_I16_LIT, T_I32_LIT, T_I64_LIT, diff --git a/include/vtype.h b/include/vtype.h new file mode 100644 index 0000000..a1326aa --- /dev/null +++ b/include/vtype.h @@ -0,0 +1,39 @@ +#ifndef ACC_VTYPE_H +#define ACC_VTYPE_H + +#include + +// Defination of first-class types. +enum { + VT_VOID, // void + VT_BOOL, // bool + VT_I32, // int32_t + VT_I64, // int64_t + + // Guard + VT_EXCEED +}; + +// Value type in C. +struct VType { + int bt; // base type(first class) +}; + +// Find out the type after appling the give ast operator(unary arithmetic variant). +// Writes into parameter _res_ +void VType_unary(const struct VType *self, int op, struct VType *res, int line); + +// Initialize a VType. +void VType_init(struct VType *self); + +// Returns the number of bits in a int type. +// Returns 0 if the given value type is not a variant of int type. +int VType_int_size(const struct VType *self); + +// Returns whether the first given value type can be extended to be equal second. +bool VType_ext_eq(const struct VType *x, const struct VType *y); + +// Returns whether the given value types are the same. +bool VType_eq(const struct VType *x, const struct VType *y); + +#endif diff --git a/src/ast.c b/src/ast.c index e2f8aae..60a7bc9 100644 --- a/src/ast.c +++ b/src/ast.c @@ -21,61 +21,71 @@ const char *ast_opname[] = { // Constructs a binary AST node struct ASTnode* ASTbinnode_new(int op, struct ASTnode *left, struct ASTnode *right) { - struct ASTbinnode *x = try_malloc(sizeof(struct ASTbinnode), __FUNCTION__); + struct ASTbinnode *self = try_malloc(sizeof(struct ASTbinnode), __FUNCTION__); - x->op = op; - x->left = left; - x->right = right; - return ((struct ASTnode*)x); + VType_init(&self->type); + self->type.bt = VT_VOID; // FIXME: calculate the correct type. + self->op = op; + self->left = left; + self->right = right; + return ((void*)self); } // Make an AST integer literal (32bits) node struct ASTnode* ASTi32node_new(int32_t v) { - struct ASTi32node *x = try_malloc(sizeof(struct ASTi32node), __FUNCTION__); + struct ASTi32node *self = try_malloc(sizeof(struct ASTi32node), __FUNCTION__); - x->op = A_LIT_I32; - x->val = v; - return ((struct ASTnode*)x); + VType_init(&self->type); + self->type.bt = VT_I32; + self->op = A_LIT_I32; + self->val = v; + return ((void*)self); } // Make an AST integer literal (64bits) node struct ASTnode* ASTi64node_new(int64_t v) { - struct ASTi64node *x = try_malloc(sizeof(struct ASTi64node), __FUNCTION__); + struct ASTi64node *self = try_malloc(sizeof(struct ASTi64node), __FUNCTION__); - x->op = A_LIT_I64; - x->val = v; - return ((struct ASTnode*)x); + VType_init(&self->type); + self->type.bt = VT_I64; + self->op = A_LIT_I64; + self->val = v; + return ((void*)self); } // Make an AST variable value node struct ASTnode* ASTvarnode_new(int id) { - struct ASTvarnode *x = try_malloc(sizeof(struct ASTvarnode), __FUNCTION__); + fail_todo(__FUNCTION__); + struct ASTvarnode *self = try_malloc(sizeof(struct ASTvarnode), __FUNCTION__); - x->op = A_VAR; - x->id = id; - return ((struct ASTnode*)x); + self->op = A_VAR; + self->id = id; + return ((void*)self); } -// Make a unary AST node: only one child -struct ASTnode* ASTunnode_new(int op, struct ASTnode *child) { - struct ASTunnode *x = try_malloc(sizeof(struct ASTunnode), __FUNCTION__); +// Constructs a unary AST node: only one child. +struct ASTnode* ASTunnode_new(int op, struct ASTnode *child, int line) { + struct ASTunnode *self = try_malloc(sizeof(struct ASTunnode), __FUNCTION__); - x->op = op; - x->left = child; - return ((struct ASTnode*)x); + VType_unary(&child->type, op, &self->type, line); + self->op = op; + self->left = child; + return ((void*)self); } // Make a block ast node struct ASTnode* ASTblocknode_new() { - struct ASTblocknode *x = try_malloc(sizeof(struct ASTblocknode), __FUNCTION__); + struct ASTblocknode *self = try_malloc(sizeof(struct ASTblocknode), __FUNCTION__); - x->op = A_BLOCK; - llist_init(&x->st); - return ((struct ASTnode*)x); + VType_init(&self->type); + self->op = A_BLOCK; + llist_init(&self->st); + return ((void*)self); } // Make a assignment ast node struct ASTnode* ASTassignnode_new(int op, struct ASTnode *left, struct ASTnode *right) { + fail_todo(__FUNCTION__); struct ASTassignnode *x = try_malloc(sizeof(struct ASTassignnode), __FUNCTION__); x->op = op; @@ -86,13 +96,14 @@ struct ASTnode* ASTassignnode_new(int op, struct ASTnode *left, struct ASTnode * // Make a if statement ast node struct ASTnode* ASTifnode_new(struct ASTnode *left, struct ASTnode *right, struct ASTnode *cond) { + fail_todo(__FUNCTION__); struct ASTifnode *x = try_malloc(sizeof(struct ASTifnode), __FUNCTION__); x->op = A_IF; x->left = left; x->right = right; x->cond = cond; - return ((struct ASTnode*)x); + return ((void*)x); } static void ast_print_dfs(FILE* Outfile, struct ASTnode *x, int tabs) { diff --git a/src/fatals.c b/src/fatals.c index e096a4b..18c9fc9 100644 --- a/src/fatals.c +++ b/src/fatals.c @@ -3,6 +3,17 @@ #include "scan.h" #include "ast.h" #include "acir.h" +#include "fatals.h" + +void fail_todo(const char *func_name) { + fprintf(stderr, "%s: TODO.", func_name); + exit(1); +} + +void fail_type(int line) { + fprintf(stderr, "sytax error on line %d: incorrect or incomplete type.\n", line); + exit(1); +} void fail_target(const char *target_name) { fprintf(stderr, "unknown target: %s.\n", target_name); diff --git a/src/parse.c b/src/parse.c index 7f15ae0..ee0b6cb 100644 --- a/src/parse.c +++ b/src/parse.c @@ -11,6 +11,7 @@ struct Pcontext { struct linklist tokens; // token list struct llist_node *cur; // current token + struct VType func_type; // current function return type }; // Checks that we have a binary operator and return its precedence. @@ -180,7 +181,7 @@ static struct ASTnode* prefixed_primary(struct Pcontext *ctx) { if (is_prefix_op(t->type)) { next(ctx); struct ASTnode *child = prefixed_primary(ctx); - return (ASTunnode_new(unary_arithop(t), child)); + return (ASTunnode_new(unary_arithop(t), child, t->line)); } return (primary(ctx)); @@ -263,14 +264,6 @@ static struct ASTnode* expression(struct Pcontext *ctx) { return (binexpr(ctx, 0)); } -// parse one print statement -static struct ASTnode* print_statement(struct Pcontext *ctx) { - match(ctx, T_PRINT); - struct ASTnode *res = ASTunnode_new(A_PRINT, expression(ctx)); - match(ctx, T_SEMI); - return (res); -} - /* // parse variable declaration statement static struct ASTnode* var_declaration(void) { @@ -325,7 +318,7 @@ static struct ASTnode* for_statement(struct Pcontext *ctx) { } else { cond = ASTi32node_new(1); } - next(ctx); // skip the ; + match(ctx, T_SEMI); struct ASTnode *inc; if (current(ctx)->type != T_RP) { @@ -361,7 +354,7 @@ static struct ASTnode* return_statement(struct Pcontext *ctx) { match(ctx, T_RETURN); struct ASTnode *res = expression(ctx); match(ctx, T_SEMI); - return (ASTunnode_new(A_RETURN, res)); + return (ASTunnode_new(A_RETURN, res, current(ctx)->line)); } // parse one statement @@ -373,9 +366,6 @@ static struct ASTnode* statement(struct Pcontext *ctx) { case T_SEMI: return (NULL); - case T_PRINT: - return (print_statement(ctx)); - // case T_INT: // return (var_declaration()); case T_IF: @@ -398,15 +388,45 @@ static struct ASTnode* statement(struct Pcontext *ctx) { } } +static bool parse_type(struct VType *self, struct Pcontext *ctx, bool ce) { + struct token *t = current(ctx); + switch (t->type) { + case T_INT: { + self->bt = VT_I32; + next(ctx); + } break; + + case T_VOID: { + self->bt = VT_VOID; + next(ctx); + } break; + + case T_LONG: { + self->bt = VT_I64; + next(ctx); + } break; + + default: { + if (ce) { + fail_ce_expect(t->line, "a typename or type classifier", token_typename[t->type]); + } else { + return (false); + } + } + } + + return (true); +} + // Parse one top-level function // Sets the func_name param. static struct Afunction* function(struct Pcontext *ctx) { struct Afunction *res = Afunction_new(); - match(ctx, T_INT); + parse_type(&ctx->func_type, ctx, true); expect(ctx, T_ID); res->name = current(ctx)->val_s; // transfer ownership of the identifier string to caller - current(ctx)->val_s = NULL; // prevent it from being freed in token_free() called by next(ctx). + current(ctx)->val_s = NULL; // prevent it from being freed in token_free() called by next(ctx). next(ctx); match(ctx, T_LP); diff --git a/src/scan.c b/src/scan.c index 6629243..35ca936 100644 --- a/src/scan.c +++ b/src/scan.c @@ -92,7 +92,6 @@ static char* scan_indentifier(int *n) { // Returns true if found keyword. static bool scan_keyword(struct token *t, char *s) { static const char *map_s[] = { - "print", "int", "void", "long", @@ -105,7 +104,6 @@ static bool scan_keyword(struct token *t, char *s) { }; static const int map_t[] = { - T_PRINT, T_INT, T_VOID, T_LONG, diff --git a/src/token.c b/src/token.c index b094071..31bf797 100644 --- a/src/token.c +++ b/src/token.c @@ -12,7 +12,7 @@ const char *token_typename[63] = { "==", "!=", "<", ">", "<=", ">=", "int", "void", "char", "long", "short", - "print", "if", "else", + "if", "else", "while", "for", "return", "a integer literal (16bit)", "a integer literal (32bit)", "a integer literal (64bit)", diff --git a/src/vtype.c b/src/vtype.c new file mode 100644 index 0000000..75dac36 --- /dev/null +++ b/src/vtype.c @@ -0,0 +1,78 @@ +#include "vtype.h" +#include "ast.h" +#include "fatals.h" + +// Find out the type after appling the give ast operator(unary arithmetic variant). +// Writes into parameter _res_ +void VType_unary(const struct VType *self, int op, struct VType *res, int line) { + if (op == A_RETURN) { + VType_init(res); + return; + } + + *res = *self; + if (self->bt == VT_VOID) { + fail_type(line); + } + + switch (op) { + case A_BNOT: + case A_NEG: { + } break; + + case A_LNOT: { + res->bt = VT_BOOL; + } break; + + default: { + fail_ast_op(op, __FUNCTION__); + } + } +} + +// Initialize a VType into void. +void VType_init(struct VType *self) { + self->bt = VT_VOID; +} + +// Returns the number of bits in a int type. +// Returns 0 if the given value type is not a variant of int type. +int VType_int_size(const struct VType *self) { + static const int map[][2] = { + {VT_BOOL, 1}, + {VT_I32, 32}, + {VT_I64, 64}, + {VT_EXCEED}, + }; + + for (int i = 0; map[i][0] != VT_EXCEED; ++i) { + if (map[i][0] == self->bt) { + return (map[i][1]); + } + } + + return (0); +} + +// Returns whether the first given value type can be extended to be equal second. +bool VType_ext_eq(const struct VType *x, const struct VType *y) { + if (VType_eq(x, y)) { + return (true); + } + + int xsz = VType_int_size(x); + if (xsz == 0) { + return (false); + } + + int ysz = VType_int_size(y); + if (ysz == 0) { + return (false); + } + return (xsz <= ysz); +} + +// Returns whether the given value types are the same. +bool VType_eq(const struct VType *x, const struct VType *y) { + return (x->bt == y->bt); +}