add value type in ast
Signed-off-by: szdytom <szdytom@163.com>
This commit is contained in:
parent
ae5f96825e
commit
e1211ebf61
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
39
include/vtype.h
Normal 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
|
67
src/ast.c
67
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) {
|
||||
|
11
src/fatals.c
11
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);
|
||||
|
52
src/parse.c
52
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);
|
||||
|
@ -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,
|
||||
|
@ -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
78
src/vtype.c
Normal 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);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user