add value type in ast

Signed-off-by: szdytom <szdytom@163.com>
This commit is contained in:
方而静 2023-06-15 14:53:14 +08:00
parent ae5f96825e
commit e1211ebf61
10 changed files with 213 additions and 55 deletions

View File

@ -3,6 +3,7 @@
#include <stdio.h>
#include <stdint.h>
#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);

View File

@ -4,6 +4,8 @@
#include <stddef.h>
#include <stdnoreturn.h>
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);

View File

@ -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,

39
include/vtype.h Normal file
View File

@ -0,0 +1,39 @@
#ifndef ACC_VTYPE_H
#define ACC_VTYPE_H
#include <stdbool.h>
// 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

View File

@ -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) {

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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)",

78
src/vtype.c Normal file
View File

@ -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);
}