From 121c37c16ae17b98bf288a8171658712f84e7dc4 Mon Sep 17 00:00:00 2001 From: szdytom Date: Mon, 12 Jun 2023 16:02:43 +0800 Subject: [PATCH] main function(AST) Signed-off-by: szdytom --- README.md | 32 +---- include/ast.h | 59 ++++----- include/cg.h | 29 ----- include/fatals.h | 1 + include/print_ast.h | 7 ++ include/scan.h | 2 +- include/symbol.h | 2 + include/target.h | 11 ++ include/token.h | 32 +++-- include/util/hashmap.h | 4 +- include/util/linklist.h | 3 - main.c | 43 ++----- src/ast.c | 120 ++++++++---------- src/cg.c | 38 ------ src/cg_ast.c | 119 ------------------ src/cg_llvm.c | 216 --------------------------------- src/fatals.c | 5 + src/parse.c | 104 +++++++++++----- src/print_ast.c | 65 ++++++++++ src/scan.c | 36 +++--- src/symbol.c | 3 +- src/target.c | 22 ++++ src/token.c | 21 ++-- src/util/linklist.c | 80 ++++-------- tests/input01 | 4 - tests/input01.ans | 3 - tests/input02 | 7 -- tests/input02.ans | 1 - tests/input03 | 8 -- tests/input03.ans | 5 - tests/input04 | 12 -- tests/input04.ans | 9 -- tests/input05 | 9 -- tests/input05.ans | 1 - tests/input06 | 7 -- tests/input06.ans | 10 -- tests/input07 | 6 - tests/input07.ans | 10 -- tests/input08 | 6 - tests/input08.ans | 1 - tests/invalid/missing_paren.c | 3 + tests/invalid/missing_retval.c | 3 + tests/invalid/no_brace.c | 2 + tests/invalid/no_semicolon.c | 3 + tests/invalid/no_space.c | 3 + tests/invalid/wrong_case.c | 3 + tests/test_llvm.lua | 50 -------- tests/valid/multi_digit.c | 3 + tests/valid/newlines.c | 10 ++ tests/valid/no_newlines.c | 1 + tests/valid/return_0.c | 3 + tests/valid/return_2.c | 3 + tests/valid/spaces.c | 1 + 53 files changed, 399 insertions(+), 842 deletions(-) delete mode 100644 include/cg.h create mode 100644 include/print_ast.h create mode 100644 include/target.h delete mode 100644 src/cg.c delete mode 100644 src/cg_ast.c delete mode 100644 src/cg_llvm.c create mode 100644 src/print_ast.c create mode 100644 src/target.c delete mode 100644 tests/input01 delete mode 100644 tests/input01.ans delete mode 100644 tests/input02 delete mode 100644 tests/input02.ans delete mode 100644 tests/input03 delete mode 100644 tests/input03.ans delete mode 100644 tests/input04 delete mode 100644 tests/input04.ans delete mode 100644 tests/input05 delete mode 100644 tests/input05.ans delete mode 100644 tests/input06 delete mode 100644 tests/input06.ans delete mode 100644 tests/input07 delete mode 100644 tests/input07.ans delete mode 100644 tests/input08 delete mode 100644 tests/input08.ans create mode 100644 tests/invalid/missing_paren.c create mode 100644 tests/invalid/missing_retval.c create mode 100644 tests/invalid/no_brace.c create mode 100644 tests/invalid/no_semicolon.c create mode 100644 tests/invalid/no_space.c create mode 100644 tests/invalid/wrong_case.c delete mode 100644 tests/test_llvm.lua create mode 100644 tests/valid/multi_digit.c create mode 100644 tests/valid/newlines.c create mode 100644 tests/valid/no_newlines.c create mode 100644 tests/valid/return_0.c create mode 100644 tests/valid/return_2.c create mode 100644 tests/valid/spaces.c diff --git a/README.md b/README.md index 30a6949..f358d1e 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,3 @@ # acc -A zero-dependence (sub) C compiler working in progress written in pure ISO C11. +A (WIP) zero-dependence (sub) C compiler written in pure ISO C11, minimal but aims to implement all 4 passes(lex, parse, build ir, code generation) and a set of machine-independent optimizations. -## Build from source - -Make sure you have `gcc` and `make` on your PATH. -If you don't, here's command for ubuntu: - -``` -sudo apt install build-essential -``` - -To build, run: -``` -make -``` - -## Usage - -``` -acc target inputfile (outputfile) -``` - -Output targets now includes: -- `x86_64`: Intel's x84-64 ASM -- `llvm`: LLVM's IR -- `ast`: (used for debugging) Abstruct Syntax Tree - -Example: - -``` -acc x86_64 test.c -``` diff --git a/include/ast.h b/include/ast.h index 5a0595d..fbd3c59 100644 --- a/include/ast.h +++ b/include/ast.h @@ -9,41 +9,38 @@ enum { A_ASSIGN, A_ADD, A_SUB, A_MUL, A_DIV, A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, - A_LIT, A_VAR, + A_LIT_I32, A_LIT_I64, + A_VAR, A_BLOCK, A_PRINT, A_IF, A_WHILE, + A_RETURN, A_SOUL // what? }; -// value type -enum { - V_I32, V_I64, V_BOOL -}; +extern const char *ast_opname[31]; -struct value_type { - int vt; // base value type -}; - -// AST nodde types -enum { - N_BIN, N_UN, N_MULTI, N_LEAF, N_ASSIGN -}; +// AST structure field shared by all types +// llist_node *n : for linklist +// int op : node operation +#define ASTnode_SHARED_FIELDS \ + struct llist_node n; \ + int op; // AST structure (common) struct ASTnode { - int op; //operator + ASTnode_SHARED_FIELDS }; // AST binary operation node struct ASTbinnode { - int op; + ASTnode_SHARED_FIELDS struct ASTnode *left; struct ASTnode *right; }; // AST if statement node struct ASTifnode { - int op; + ASTnode_SHARED_FIELDS struct ASTnode *left; // condition true branch struct ASTnode *right; // condition false branch struct ASTnode *cond; @@ -51,33 +48,38 @@ struct ASTifnode { // AST unary operation node struct ASTunnode { - int op; - struct ASTnode *c; + ASTnode_SHARED_FIELDS + struct ASTnode *left; }; // AST block node struct ASTblocknode { - int op; + ASTnode_SHARED_FIELDS struct linklist st; // statements linklist }; -// AST literal node -struct ASTlitnode { - int op; - struct value_type type; - void *val; +// AST integer literal (32bit) node +struct ASTi32node { + ASTnode_SHARED_FIELDS + int32_t val; +}; + +// AST integer literal (64bit) node +struct ASTi64node { + ASTnode_SHARED_FIELDS + int64_t val; }; // AST assign literal node struct ASTassignnode { - int op; - int left; + ASTnode_SHARED_FIELDS + struct ASTnode* left; struct ASTnode* right; }; // AST variable value node struct ASTvarnode { - int op; + ASTnode_SHARED_FIELDS int id; }; @@ -87,9 +89,8 @@ struct ASTnode* ast_make_lit_i64(int64_t x); struct ASTnode* ast_make_unary(int op, struct ASTnode *c); struct ASTnode* ast_make_block(); struct ASTnode* ast_make_var(int id); -struct ASTnode* ast_make_assign(int op, int 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); -int ast_type(int t); void ast_free(struct ASTnode *x); #endif diff --git a/include/cg.h b/include/cg.h deleted file mode 100644 index bf6bd64..0000000 --- a/include/cg.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef ACC_CG_H -#define ACC_CG_H - -#include "ast.h" - -extern FILE *Outfile; - -// cg.c -void cg_main(int target, struct ASTnode *rt); -void open_outputfile(char *filename); -void cg_unload(void); - -// cg_x64.c -//void cgx64_generate(struct ASTnode *rt); - -// cg_llvm.c -//void cgllvm_generate(struct ASTnode *rt); - -// cg_ast.c -void cgast_generate(struct ASTnode *rt); - -// targets -enum { - CG_X64, // Intel x86_64 - CG_LLVM, // LLVM IR - CG_AST, // Abstruct Syntax Tree -}; - -#endif diff --git a/include/fatals.h b/include/fatals.h index 2230462..1ed2542 100644 --- a/include/fatals.h +++ b/include/fatals.h @@ -5,6 +5,7 @@ #include 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_ast_op(int op, const char *func_name); noreturn void fail_ce_expect(const char *expected, const char *got); diff --git a/include/print_ast.h b/include/print_ast.h new file mode 100644 index 0000000..02b0382 --- /dev/null +++ b/include/print_ast.h @@ -0,0 +1,7 @@ +#ifndef ACC_DEBUG_PRINT_AST +#define ACC_DEBUG_PRINT_AST + +void debug_ast_print(FILE *Outfile, struct ASTnode *rt); + +#endif + diff --git a/include/scan.h b/include/scan.h index be4468d..99fe6f3 100644 --- a/include/scan.h +++ b/include/scan.h @@ -1,7 +1,7 @@ #ifndef ACC_SCAN_H #define ACC_SCAN_H -#include "token.h" +#include "util/linklist.h" extern int Line; struct linklist scan_tokens(const char *name); diff --git a/include/symbol.h b/include/symbol.h index edc5cb3..a0d8af2 100644 --- a/include/symbol.h +++ b/include/symbol.h @@ -1,3 +1,4 @@ +/* #ifndef ACC_SYMBOL_H #define ACC_SYMBOL_H @@ -11,3 +12,4 @@ int findglob(char *s); int addglob(char *s); #endif +*/ diff --git a/include/target.h b/include/target.h new file mode 100644 index 0000000..660f1e8 --- /dev/null +++ b/include/target.h @@ -0,0 +1,11 @@ +#ifndef ACC_TARGET_H +#define ACC_TARGET_H + +// Target types +enum { + TARGET_AST +}; + +int target_parse(const char *target_string); + +#endif diff --git a/include/token.h b/include/token.h index d4fc1cc..14069c5 100644 --- a/include/token.h +++ b/include/token.h @@ -1,29 +1,41 @@ #ifndef ACC_TOKEN_H #define ACC_TOKEN_H +#include #include "util/linklist.h" // Token structure struct token { + struct llist_node n; int type; // token type - void* val; // hold the value of the literal that we scanned in + union { // hold the value of the literal that we scanned in + int16_t val_i16; + int32_t val_i32; + int64_t val_i64; + char *val_s; + }; }; // Tokens enum { T_EOF, - T_SEMI, - T_LB, T_RB, T_LP, T_RP, - T_ASSIGN, - T_PLUS, T_MINUS, T_STAR, T_SLASH, - T_EQ, T_NE, T_LT, T_GT, T_LE, T_GE, - T_INT, T_VOID, T_CHAR, T_LONG, - T_PRINT, T_IF, T_ELSE, T_WHILE, T_FOR, - T_I32_LIT, T_I64_LIT, T_INDENT, + T_SEMI, // ; + T_LB, T_RB, T_LP, T_RP, // { } ( ) + T_ASSIGN, // = + T_PLUS, T_MINUS, T_STAR, T_SLASH, // + - * / + 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_WHILE, T_FOR, // while for + T_RETURN, // return + T_I16_LIT, T_I32_LIT, T_I64_LIT, + T_ID, + T_EXCEED, }; extern const char *token_typename[63]; void token_free(struct token *t); -struct token token_make_eof(void); #endif + diff --git a/include/util/hashmap.h b/include/util/hashmap.h index 57045c1..45e8e47 100644 --- a/include/util/hashmap.h +++ b/include/util/hashmap.h @@ -1,3 +1,4 @@ +/* #ifndef ACC_UTIL_HASHMAP #define ACC_UTIL_HASHMAP @@ -9,4 +10,5 @@ struct hashmap { void hashmap_init(); -#endif \ No newline at end of file +#endif +*/ diff --git a/include/util/linklist.h b/include/util/linklist.h index c65d000..e2e3e00 100644 --- a/include/util/linklist.h +++ b/include/util/linklist.h @@ -2,7 +2,6 @@ #define ACC_UTIL_LINKLIST_H struct llist_node { - void *val; struct llist_node *nxt; }; @@ -12,8 +11,6 @@ struct linklist { struct llist_node *tail; }; -struct llist_node* llist_createnode(void *val); - void llist_init(struct linklist *l); void llist_free(struct linklist *l); void llist_free_full(struct linklist *l); diff --git a/main.c b/main.c index e72f12d..3b8aa61 100644 --- a/main.c +++ b/main.c @@ -3,9 +3,9 @@ #include #include "scan.h" #include "parse.h" -#include "cg.h" #include "ast.h" -#include "symbol.h" +#include "target.h" +#include "print_ast.h" // Print out a usage if started incorrectly static void usage(char *prog) { @@ -14,48 +14,29 @@ static void usage(char *prog) { exit(1); } -//Do clean up job +// Do clean up job void unload(void) { - cg_unload(); - symbol_unload(); } int main(int argc, char *argv[]) { - atexit(unload); +// atexit(unload); if (argc < 3) { usage(argv[0]); } - int outfile_opened = 0; + FILE *Outfile; if (argc >= 4) { - open_outputfile(argv[3]); - outfile_opened = 1; - } - - int target; - if (!strcmp(argv[1], "x86_64")) { - target = CG_X64; - if (!outfile_opened) { - open_outputfile("out.s"); - } - } else if (!strcmp(argv[1], "llvm")) { - target = CG_LLVM; - if (!outfile_opened) { - open_outputfile("out.ll"); - } - } else if (!strcmp(argv[1], "ast")) { - target = CG_AST; - if (!outfile_opened) { - open_outputfile("out.txt"); - } + Outfile = fopen(argv[3], "w"); } else { - fprintf(stderr, "Unknow target %s.\n", argv[1]); - exit(1); + Outfile = fopen("out.txt", "w"); } - symbol_init(); + int target = target_parse(argv[1]); struct ASTnode *rt = parse(argv[2]); - cg_main(target, rt); + if (target == TARGET_AST) { + debug_ast_print(Outfile, rt); + } ast_free(rt); + fclose(Outfile); return (0); } diff --git a/src/ast.c b/src/ast.c index 8ad5b2c..df4e09d 100644 --- a/src/ast.c +++ b/src/ast.c @@ -4,6 +4,18 @@ #include "fatals.h" #include "util/linklist.h" +const char *ast_opname[] = { + "=", + "+", "-", "*", "/", + "==", "!=", "<", ">", "<=", ">=", + "int32", "int64", + "var", + "block", + "print", "if", "while", + "return", + NULL +}; + // Build and return 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__); @@ -14,25 +26,21 @@ struct ASTnode* ast_make_binary(int op, struct ASTnode *left, struct ASTnode *ri return ((struct ASTnode*)x); } -// Make an AST int32 literal node +// Make an AST integer literal (32bit) node struct ASTnode* ast_make_lit_i32(int32_t v) { - struct ASTlitnode *x = malloc_or_fail(sizeof(struct ASTlitnode), __FUNCTION__); + struct ASTi32node *x = malloc_or_fail(sizeof(struct ASTi32node), __FUNCTION__); - x->op = A_LIT; - x->type.vt = V_I32; - x->val = malloc_or_fail(sizeof(int32_t), __FUNCTION__); - *(int64_t*)x->val = v; + x->op = A_LIT_I32; + x->val = v; return ((struct ASTnode*)x); } -// Make an AST int32 literal node +// Make an AST integer literal (64bit) node struct ASTnode* ast_make_lit_i64(int64_t v) { - struct ASTlitnode *x = malloc_or_fail(sizeof(struct ASTlitnode), __FUNCTION__); + struct ASTi64node *x = malloc_or_fail(sizeof(struct ASTi64node), __FUNCTION__); - x->op = A_LIT; - x->type.vt = V_I64; - x->val = malloc_or_fail(sizeof(int64_t), __FUNCTION__); - *(int64_t*)x->val = v; + x->op = A_LIT_I64; + x->val = v; return ((struct ASTnode*)x); } @@ -46,11 +54,11 @@ struct ASTnode* ast_make_var(int id) { } // Make a unary AST node: only one child -struct ASTnode* ast_make_unary(int op, struct ASTnode *c) { +struct ASTnode* ast_make_unary(int op, struct ASTnode *child) { struct ASTunnode *x = malloc_or_fail(sizeof(struct ASTunnode), __FUNCTION__); x->op = op; - x->c = c; + x->left = child; return ((struct ASTnode*)x); } @@ -64,7 +72,7 @@ struct ASTnode* ast_make_block() { } // Make a assignment ast node -struct ASTnode* ast_make_assign(int op, int left, struct ASTnode *right) { +struct ASTnode* ast_make_assign(int op, struct ASTnode *left, struct ASTnode *right) { struct ASTassignnode *x = malloc_or_fail(sizeof(struct ASTassignnode), __FUNCTION__); x->op = op; @@ -84,66 +92,44 @@ struct ASTnode* ast_make_if(struct ASTnode *left, struct ASTnode *right, struct return ((struct ASTnode*)x); } -// Translate ast operation type to ast node type -int ast_type(int t) { - switch (t) { - case A_ADD: case A_SUB: case A_MUL: case A_DIV: - case A_EQ: case A_NE: case A_GT: case A_LT: case A_GE: case A_LE: - case A_IF: case A_WHILE: - return (N_BIN); - case A_ASSIGN: - return (N_ASSIGN); - case A_LIT: case A_VAR: - return (N_LEAF); - case A_BLOCK: - return (N_MULTI); - case A_PRINT: - return (N_UN); - default: - fail_ast_op(t, __FUNCTION__); - } -} - // free an AST's memory void ast_free(struct ASTnode *x) { if (x == NULL) { return; } - switch (ast_type(x->op)) { - case N_ASSIGN: { - struct ASTassignnode *t = (struct ASTassignnode*)x; - ast_free(t->right); - } break; - case N_BIN: { - struct ASTbinnode *t = (struct ASTbinnode*)x; - ast_free(t->left); - ast_free(t->right); - if (x->op == A_IF) { + switch (x->op) { + case A_IF: { ast_free(((struct ASTifnode*)x)->cond); - } - } break; - case N_UN: { - struct ASTunnode *t = (struct ASTunnode*)x; - ast_free(t->c); - } break; - case N_MULTI: { - struct ASTblocknode *t = (struct ASTblocknode*)x; - struct llist_node *p = t->st.head; - while (p) { - ast_free(p->val); - p = p->nxt; - } - llist_free(&t->st); - } break; - case N_LEAF: { - struct ASTlitnode *t = (struct ASTlitnode*)x; - if (t->op == A_LIT) { - if (t->val) { - free(t->val); + } // dont break + + case A_ASSIGN: + case A_ADD: case A_SUB: case A_MUL: case A_DIV: + case A_EQ: case A_NE: case A_GT: case A_LT: case A_GE: case A_LE: + case A_WHILE: { + struct ASTbinnode *t = (struct ASTbinnode*)x; + ast_free(t->left); + ast_free(t->right); + } break; + + case A_PRINT: case A_RETURN: { + struct ASTunnode *t = (struct ASTunnode*)x; + ast_free(t->left); + } break; + + case A_BLOCK: { + struct ASTblocknode *t = (struct ASTblocknode*)x; + struct llist_node *p = t->st.head, *nxt; + while (p) { + nxt = p->nxt; + ast_free(p); + p = nxt; } - } - } break; + llist_free(&t->st); + } break; + + default: { + } break; } free(x); } diff --git a/src/cg.c b/src/cg.c deleted file mode 100644 index d82cadc..0000000 --- a/src/cg.c +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include -#include -#include -#include "cg.h" - -FILE *Outfile; - -// open output file of generated code -void open_outputfile(char *filename) { - Outfile = fopen(filename, "w"); - if (Outfile == NULL) { - fprintf(stderr, "Unable to open %s: %s\n", filename, strerror(errno)); - exit(1); - } -} - -// close Outfile at exit. -void cg_unload(void) { - if (Outfile) { - fclose(Outfile); - } -} - -// generates code -void cg_main(int target, struct ASTnode *rt) { - if (target == CG_X64) { - //cgx64_generate(rt); - } else if (target == CG_LLVM) { - //cgllvm_generate(rt); - } else if (target == CG_AST) { - cgast_generate(rt); - } else { - fprintf(stderr, "Unknow target %d.\n", target); - exit(1); - } -} - diff --git a/src/cg_ast.c b/src/cg_ast.c deleted file mode 100644 index 6f7ed16..0000000 --- a/src/cg_ast.c +++ /dev/null @@ -1,119 +0,0 @@ -#include -#include -#include "ast.h" -#include "cg.h" -#include "symbol.h" -#include "fatals.h" -#include "util/array.h" - -static const char *ast_opname[] = { - "=", - "+", "-", "*", "/", - "==", "!=", "<", ">", "<=", ">=", - "int", "var", - "block", - "print", "if", "while" -}; - -static int tabs; - -static void cgprint_tabs() { - for (int i = 0; i < tabs; ++i) { - fprintf(Outfile, "\t"); - } -} - -static void cgenerate_dfs(struct ASTnode *x) { - if (x == NULL) { - cgprint_tabs(); - fprintf(Outfile, "--->NULL.\n"); - return; - } - - int nt = ast_type(x->op); - if (nt == N_LEAF) { - if (x->op == A_LIT) { - struct ASTlitnode *t = (struct ASTlitnode*)x; - cgprint_tabs(); - switch (t->type.vt) { - case V_I32: - fprintf(Outfile, "--->INT %d.\n", *(int32_t*)t->val); - break; - case V_I64: - fprintf(Outfile, "--->INT64 %lld.\n", *(int64_t*)t->val); - break; - default: - fprintf(stderr, "%s: Unknow literal type %d.\n", __FUNCTION__, t->type.vt); - exit(1); - } - } else if (x->op == A_VAR) { - struct ASTvarnode *t = (struct ASTvarnode*)x; - cgprint_tabs(); - fprintf(Outfile, "--->VAR @%s.\n", (char*)array_get(&Gsym, t->id)); - } else { - fail_ast_op(x->op, __FUNCTION__); - } - } else if (nt == N_ASSIGN) { - struct ASTassignnode *t = (struct ASTassignnode*)x; - cgprint_tabs(); - fprintf(Outfile, "--->ASSIGN(%s) to @%s (right)\n", ast_opname[t->op], (char*)array_get(&Gsym, t->left)); - tabs += 1; - cgenerate_dfs(t->right); - tabs -= 1; - } else if (nt == N_BIN) { - if (x->op == A_IF) { - struct ASTifnode *t = (struct ASTifnode*)x; - cgprint_tabs(); - fprintf(Outfile, "--->IF (cond left right)\n"); - tabs += 1; - cgenerate_dfs(t->cond); - cgenerate_dfs(t->left); - cgenerate_dfs(t->right); - tabs -= 1; - } else if (x->op == A_WHILE) { - struct ASTbinnode *t = (struct ASTbinnode*)x; - cgprint_tabs(); - fprintf(Outfile, "--->WHILE(%s) (cond body)\n", ast_opname[t->op]); - tabs += 1; - cgenerate_dfs(t->left); - cgenerate_dfs(t->right); - tabs -= 1; - } else { - struct ASTbinnode *t = (struct ASTbinnode*)x; - cgprint_tabs(); - fprintf(Outfile, "--->BINOP(%s) (left right)\n", ast_opname[t->op]); - tabs += 1; - cgenerate_dfs(t->left); - cgenerate_dfs(t->right); - tabs -= 1; - } - } else if (nt == N_UN) { - if (x->op == A_PRINT) { - struct ASTunnode *t = (struct ASTunnode*)x; - cgprint_tabs(); - fprintf(Outfile, "--->PRINT (value)\n"); - tabs += 1; - cgenerate_dfs(t->c); - tabs -= 1; - } else { - fail_ast_op(x->op, __FUNCTION__); - } - } else if (nt == N_MULTI) { - struct ASTblocknode *t = (struct ASTblocknode*)x; - cgprint_tabs(); - fprintf(Outfile, "--->BLOCK (%d childs)\n", t->st.length); - tabs += 1; - struct llist_node *p = t->st.head; - while (p) { - cgenerate_dfs(p->val); - p = p->nxt; - } - tabs -= 1; - } -} - -void cgast_generate(struct ASTnode *rt) { - tabs = 0; - cgenerate_dfs(rt); -} - diff --git a/src/cg_llvm.c b/src/cg_llvm.c deleted file mode 100644 index f569caa..0000000 --- a/src/cg_llvm.c +++ /dev/null @@ -1,216 +0,0 @@ -#include -#include -#include "ast.h" -#include "cg.h" -#include "symbol.h" -#include "fatals.h" -#include "util/array.h" -#include "util/linklist.h" - -static int alloc_tag(void) { - static int id = 0; - return (id++); -} - -static int alloc_label(void) { - static int id = 0; - return (id++); -} - -// Print out the ir preamble -static void cgpreamble(void) { - fputs( "@.printint.format = constant [4 x i8] c\"%d\\0A\\00\", align 1\n" - "declare dso_local i32 @printf(i8* readonly nocapture, ...)\n" - "define dso_local void @printint(i32 %0) {\n" - "\t%2 = getelementptr inbounds [4 x i8], [4 x i8]* @.printint.format, i32 0, i32 0\n" - "\t%3 = call i32 (i8*, ...) @printf(i8* %2, i32 %0)\n" - "\tret void\n" - "}\n" - "\n" - "define dso_local i32 @main() {\n" - "entry:\n", Outfile); -} - -// Print out the ir postamble -static void cgpostamble(void) { - fputs("\tret i32 0\n}\n", Outfile); -} - -// init as global value -static void cginit_glob(char *name) { - fprintf(Outfile, "@%s = dso_local global i32 0, align 4\n", name); -} - -// Preform arithmetic operation between two i32 -static int cgarith_i32(int x, int y, char *op) { - int r = alloc_tag(); - fprintf(Outfile, "\t%%%d = %s i32 %%%d, %%%d\n", r, op, x, y); - return (r); -} - -// Preform comparision between integers -static int cgcomp_i(int x, int y, char *op, char *ty) { - int r1 = alloc_tag(); - fprintf(Outfile, "\t%%%d = icmp %s %s %%%d, %%%d\n", r1, op, ty, x, y); - int r2 = alloc_tag(); - if (strcmp(ty, "i1") != 0) { // special case for bool - fprintf(Outfile, "\t%%%d = zext i1 %%%d to %s\n", r2, r1, ty); - } - return (r2); -} - -// Preform comparision between two i32 -static int cgcomp_i32(int x, int y, char *op) { - return (cgcomp_i(x, y, op, "i32")); -} - -// Load an int literal -static int cgload_lit_i32(int val) { - int r = alloc_tag(); - fprintf(Outfile, "\t%%%d = select i1 true, i32 %d, i32 undef\n", r, val); - return (r); -} - -// Load an int from a global variable -static int cgload_glob_i32(char *name) { - int r = alloc_tag(); - fprintf(Outfile, "\t%%%d = load i32, i32* @%s, align 4\n", r, name); - return (r); -} - -// Store an int into a global variable -static int cgstore_glob_i32(int x, char *name) { - fprintf(Outfile, "\tstore i32 %%%d, i32* @%s, align 4\n", x, name); - return (x); -} - -// Print a i32 -static void cgprint(int x) { - fprintf(Outfile, "\tcall void (i32) @printint(i32 %%%d)\n", x); -} - -// Jump to a label no matter what -static void cgjmp_always(int x) { - fprintf(Outfile, "\tbr label %%L%d\n", x); -} - -// Conditional jump -static void cgjmp_if_i32(int cond, int Lthen, int Lelse) { - int rc = alloc_tag(); - fprintf(Outfile, "\t%%%d = icmp ne i32 0, %%%d\n", rc, cond); - fprintf(Outfile, "\tbr i1 %%%d, label %%L%d, label %%L%d\n", rc, Lthen, Lelse); -} - -static void cgprint_label(int L) { - fprintf(Outfile, "L%d:\n", L); -} - -// generates llvm ir from ast -static int cgenerate_ast(struct ASTnode *rt) { - int nt = ast_type(rt->op); - if (nt == N_LEAF) { - if (rt->op == A_INTLIT) { - return (cgload_lit_i32(((struct ASTintnode*)rt)->val)); - } else if (rt->op == A_VAR) { - return (cgload_glob_i32(array_get(&Gsym, ((struct ASTvarnode*)rt)->id))); - } - fail_ast_op(rt->op, __FUNCTION__); - } else if (nt == N_BIN) { - if (rt->op == A_IF) { - struct ASTifnode *x = (struct ASTifnode*)rt; - int Lthen = alloc_label(), Lelse = alloc_label(), Lend = alloc_label(); - int condv = cgenerate_ast(x->cond); - cgjmp_if_i32(condv, Lthen, Lelse); - - cgprint_label(Lthen); - cgenerate_ast(x->left); - cgjmp_always(Lend); - - cgprint_label(Lelse); - cgenerate_ast(x->right); - cgjmp_always(Lend); - - cgprint_label(Lend); - return (-1); - } else if (rt->op == A_WHILE) { - struct ASTbinnode *x = (struct ASTbinnode*)rt; - int Lstart = alloc_label(), Lbody = alloc_label(), Lend = alloc_label(); - cgjmp_always(Lstart); - - cgprint_label(Lstart); - int condv = cgenerate_ast(x->left); - cgjmp_if_i32(condv, Lbody, Lend); - - cgprint_label(Lbody); - cgenerate_ast(x->right); - cgjmp_always(Lstart); - - cgprint_label(Lend); - return (-1); - } - - struct ASTbinnode *x = (struct ASTbinnode*)rt; - int lc = cgenerate_ast(x->left); - int rc = cgenerate_ast(x->right); - - if (rt->op == A_ADD) { - return (cgarith_i32(lc, rc, "add nsw")); - } else if (rt->op == A_SUB) { - return (cgarith_i32(lc, rc, "sub nsw")); - } else if (rt->op == A_MUL) { - return (cgarith_i32(lc, rc, "mul nsw")); - } else if (rt->op == A_DIV) { - return (cgarith_i32(lc, rc, "sdiv")); - } else if (rt->op == A_EQ) { - return (cgcomp_i32(lc, rc, "eq")); - } else if (rt->op == A_NE) { - return (cgcomp_i32(lc, rc, "ne")); - } else if (rt->op == A_GT) { - return (cgcomp_i32(lc, rc, "sgt")); - } else if (rt->op == A_GE) { - return (cgcomp_i32(lc, rc, "sge")); - } else if (rt->op == A_LT) { - return (cgcomp_i32(lc, rc, "slt")); - } else if (rt->op == A_LE) { - return (cgcomp_i32(lc, rc, "sle")); - } - fail_ast_op(rt->op, __FUNCTION__); - } else if (nt == N_UN) { - struct ASTunnode *x = (struct ASTunnode*)rt; - int cv = cgenerate_ast(x->c); - - if (rt->op == A_PRINT) { - cgprint(cv); - return (-1); - } - fail_ast_op(rt->op, __FUNCTION__); - } else if (nt == N_ASSIGN) { - struct ASTassignnode *x = (struct ASTassignnode*)rt; - int cv = cgenerate_ast(x->right); - - if (rt->op == A_ASSIGN) { - return (cgstore_glob_i32(cv, array_get(&Gsym, x->left))); - } - fail_ast_op(rt->op, __FUNCTION__); - } else if (nt == N_MULTI) { - struct ASTblocknode *x = (struct ASTblocknode*)rt; - int val = -1; - struct llist_node *p = x->st.head; - while (p) { - val = cgenerate_ast(p->val); - p = p->nxt; - } - return val; - } - fail_ast_op(rt->op, __FUNCTION__); -} - -// generate and write ir to Outfile -void cgllvm_generate(struct ASTnode* rt) { - for (int i = 0; i < Gsym.length; ++i) { - cginit_glob(array_get(&Gsym, i)); - } - cgpreamble(); - cgenerate_ast(rt); - cgpostamble(); -} diff --git a/src/fatals.c b/src/fatals.c index 4816afe..8458ada 100644 --- a/src/fatals.c +++ b/src/fatals.c @@ -2,6 +2,11 @@ #include #include "scan.h" +void fail_target(const char *target_name) { + fprintf(stderr, "unknown target: %s.\n", target_name); + exit(1); +} + void fail_malloc(const char *func_name) { fprintf(stderr, "%s: unable to malloc.\n", func_name); exit(1); diff --git a/src/parse.c b/src/parse.c index efd27cf..5aed65e 100644 --- a/src/parse.c +++ b/src/parse.c @@ -5,11 +5,9 @@ #include "scan.h" #include "token.h" #include "ast.h" -#include "symbol.h" #include "fatals.h" static struct linklist Tokens; // current token for parsing -static int skip_semi = 0; // can skip statement semi (after block) // Check that we have a binary operator and return its precedence. // operators with larger precedence value will be evaluated first @@ -57,7 +55,7 @@ static int arithop(int t) { // operator ssociativity direction // Returns false if left to right, e.g. + -// true if right to left, e.g. = +// true if right to left, e.g. = static bool direction_rtl(int t) { switch(t) { case T_ASSIGN: @@ -77,10 +75,12 @@ static void next(void) { // preview next kth token from input stream static struct token* preview(int k) { if (Tokens.length <= k) { - static struct token token_eof; - token_eof = token_make_eof(); + static struct token token_eof = { + .type = T_EOF + }; return (&token_eof); } + struct token* res = llist_get(&Tokens, k); return (res); } @@ -92,9 +92,7 @@ static struct token* current(void) { // match a token or report syntax error static void match(int t) { - if (t == T_SEMI && skip_semi) { - skip_semi = 0; - } else if (current()->type == t) { + if (current()->type == t) { next(); } else { fail_ce_expect(token_typename[current()->type], token_typename[t]); @@ -102,7 +100,7 @@ static void match(int t) { } // check current token's type or report syntax error. -static void check(int t) { +static void expect(int t) { if (current()->type != t) { fail_ce_expect(token_typename[current()->type], token_typename[t]); } @@ -122,11 +120,14 @@ static struct ASTnode* primary(void) { res = expression(); match(T_RP); } else if (current()->type == T_I32_LIT) { - res = ast_make_lit_i32(*(int32_t*)current()->val); + res = ast_make_lit_i32(current()->val_i32); next(); } else if (current()->type == T_I64_LIT) { - res = ast_make_lit_i64(*(int64_t*)current()->val); - } else if (current()->type == T_INDENT) { + res = ast_make_lit_i64(current()->val_i64); + next(); + } else if (current()->type == T_ID) { + // TODO: identifier. + /* int id = findglob((char*)current()->val); if (id == -1) { fprintf(stderr, "syntax error on line %d: unknown indentifier %s.\n", Line, (char*)current()->val); @@ -134,6 +135,9 @@ static struct ASTnode* primary(void) { } next(); return (ast_make_var(id)); + */ + res = NULL; + next(); } else { fprintf(stderr, "syntax error on line %d: primary expression excpeted.\n", Line); exit(1); @@ -178,7 +182,7 @@ static struct ASTnode* binexpr(int precedence) { } // parse one block of code, e.g. { a; b; } -static struct ASTnode* parse_block(void) { +static struct ASTnode* block(void) { match(T_LB); if (current()->type == T_RB) { next(); @@ -196,15 +200,15 @@ static struct ASTnode* parse_block(void) { } } match(T_RB); - skip_semi = 1; return ((struct ASTnode*)res); } // parse an expression static struct ASTnode* expression(void) { - if (current()->type == T_LB) { - return (parse_block()); + if (current()->type == T_SEMI) { + return (NULL); } + return (binexpr(0)); } @@ -216,10 +220,11 @@ static struct ASTnode* print_statement(void) { return (res); } +/* // parse variable declaration statement static struct ASTnode* var_declaration(void) { match(T_INT); - check(T_INDENT); + expect(T_IDENT); if (findglob((char*)current()->val) != -1) { fail_ce("variable declared twice."); } @@ -228,6 +233,7 @@ static struct ASTnode* var_declaration(void) { match(T_SEMI); return (NULL); } +*/ // parse an if statement static struct ASTnode* if_statement(void) { @@ -284,6 +290,10 @@ static struct ASTnode* for_statement(void) { if (body == NULL && inc == NULL) { wbody = NULL; + } else if (body == NULL) { + wbody = inc; + } else if (inc == NULL) { + wbody = body; } else { struct ASTblocknode* wt = (struct ASTblocknode*)ast_make_block(); llist_pushback_notnull(&wt->st, body); @@ -293,40 +303,80 @@ static struct ASTnode* for_statement(void) { llist_pushback_notnull(&container->st, init); llist_pushback(&container->st, ast_make_binary(A_WHILE, cond, wbody)); - return (struct ASTnode*)container; + return ((struct ASTnode*)container); +} + +static struct ASTnode* return_statement() { + match(T_RETURN); + struct ASTnode *res = expression(); + match(T_SEMI); + return (ast_make_unary(A_RETURN, res)); } // parse one statement static struct ASTnode* statement(void) { switch (current()->type) { + case T_LB: + return (block()); + case T_SEMI: return (NULL); + case T_PRINT: return (print_statement()); - case T_INT: - return (var_declaration()); + +// case T_INT: +// return (var_declaration()); case T_IF: return (if_statement()); + case T_WHILE: return (while_statement()); + case T_FOR: return (for_statement()); - default: - skip_semi = 0; + + case T_RETURN: + return (return_statement()); + + default: { struct ASTnode* res = expression(); match(T_SEMI); return (res); + } } } +// Parse one top-level function +// Sets the func_name param. +static struct ASTnode* function(char **func_name) { + 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. + next(); + + match(T_LP); + if (current()->type == T_VOID) { + next(); + goto END_PARAM_LIST; + } + // TODO: param list + +END_PARAM_LIST: + match(T_RP); + return (block()); +} + // Parse ans return the full ast struct ASTnode* parse(const char *name) { Tokens = scan_tokens(name); - struct ASTnode* res = statement(); - struct llist_node *p = Tokens.head; - while (p != Tokens.tail) { - free(p->val); - p = p->nxt; + char *func_name; + struct ASTnode* res = function(&func_name); + + free(func_name); + while (Tokens.length > 0) { + token_free(llist_popfront(&Tokens)); } llist_free(&Tokens); return (res); diff --git a/src/print_ast.c b/src/print_ast.c new file mode 100644 index 0000000..ce30d96 --- /dev/null +++ b/src/print_ast.c @@ -0,0 +1,65 @@ +#include +#include +#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 = 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 = x; + fprintf(Outfile, "--->INT32(%d)\n", t->val); + } break; + + case A_LIT_I64: { + struct ASTi64node *t = x; + fprintf(Outfile, "--->INT64(%lld)\n", t->val); + } break; + + case A_BLOCK: { + struct ASTblocknode *t = x; + fprintf(Outfile, "--->BLOCK(%d statements)\n", t->st.length); + tabs += 1; + struct llist_node *p = t->st.head; + while (p) { + ast_dfs(Outfile, 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); +} + diff --git a/src/scan.c b/src/scan.c index d7a2c3a..208755a 100644 --- a/src/scan.c +++ b/src/scan.c @@ -41,7 +41,7 @@ static void skip_whitespaces(void) { // Scan and return an integer literal value from the input file. static void scan_int(struct token *t) { - long long res = 0; + int64_t res = 0; int c = preview(); while ('0' <= c && c <= '9') { res = res * 10 + (c - '0'); @@ -51,12 +51,10 @@ static void scan_int(struct token *t) { if (INT32_MIN <= res && res <= INT32_MAX) { t->type = T_I32_LIT; - t->val = malloc_or_fail(sizeof(int32_t), __FUNCTION__); - *((int32_t *)t->val) = (int)res; + t->val_i32 = (int32_t)res; } else { t->type = T_I64_LIT; - t->val = malloc_or_fail(sizeof(int64_t), __FUNCTION__); - *((int64_t *)t->val) = res; + t->val_i64 = (int64_t)res; } } @@ -102,6 +100,7 @@ static bool scan_keyword(struct token *t, char *s) { "else", "while", "for", + "return", NULL }; @@ -114,7 +113,8 @@ static bool scan_keyword(struct token *t, char *s) { T_ELSE, T_WHILE, T_FOR, - -1 + T_RETURN, + T_EXCEED, }; for (int i = 0; map_s[i] != NULL; ++i) { @@ -139,7 +139,7 @@ static bool scan_1c(struct token *t) { {'(', T_LP}, {')', T_RP}, {';', T_SEMI}, - {'\0', -1} + {'\0', T_EXCEED} }; int c = preview(); @@ -156,7 +156,6 @@ static bool scan_1c(struct token *t) { // Scan and return the next token found in the input. static struct token* scan(void) { struct token *t = malloc_or_fail(sizeof(struct token), __FUNCTION__); - t->val = NULL; skip_whitespaces(); int c = preview(); @@ -203,20 +202,16 @@ static struct token* scan(void) { next(); } } else { - // If it's a digit, scan the integer literal value in - if (isdigit(c)) { + if (isdigit(c)) { // If it's a digit, scan the integer literal value in scan_int(t); } else if (isalpha(c) || c == '_') { - t->val = scan_indentifier(NULL); - if (scan_keyword(t, t->val)) { - // got a keyword - free(t->val); - t->val = NULL; - } else { - // not a keyword, so it should be an indentifier. - t->type = T_INDENT; + t->val_s = scan_indentifier(NULL); + if (scan_keyword(t, t->val_s)) { // got a keyword + free(t->val_s); + } else { // not a keyword, so it should be an indentifier. + t->type = T_ID; } - } else { + } else { // cannot match to anything we know, report error. fail_char(c); } } @@ -242,4 +237,5 @@ struct linklist scan_tokens(const char *name) { fclose(Infile); return (res); -} \ No newline at end of file +} + diff --git a/src/symbol.c b/src/symbol.c index 9c46b87..2a8e572 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -1,3 +1,4 @@ +/* #include #include #include @@ -119,4 +120,4 @@ int addglob(char *s) { trie_set(ss, res); return (res); } - +*/ diff --git a/src/target.c b/src/target.c new file mode 100644 index 0000000..c089567 --- /dev/null +++ b/src/target.c @@ -0,0 +1,22 @@ +#include +#include "fatals.h" +#include "target.h" + +int target_parse(const char *target_string) { + static const char *target_map_k[] = { + "ast", + NULL + }; + + static const int target_map_v[] = { + TARGET_AST, + }; + + for (int i = 0; target_map_k[i]; ++i) { + if (strcmp(target_map_k[i], target_string) == 0) { + return (target_map_v[i]); + } + } + + fail_target(target_string); +} diff --git a/src/token.c b/src/token.c index 4e3f4da..61f754e 100644 --- a/src/token.c +++ b/src/token.c @@ -1,5 +1,4 @@ #include -#include #include "token.h" const char *token_typename[63] = { @@ -10,20 +9,18 @@ const char *token_typename[63] = { "+", "-", "*", "/", "==", "!=", "<", ">", "<=", ">=", "int", "void", "char", "long", - "print", "if", "else", "while", "for", - "a signed integer literal (size 32)", "a signed integer literal (size 64)", "an indentifier" + "short", + "print", "if", "else", + "while", "for", + "return", + "a integer literal (16bit)", "a integer literal (32bit)", "a integer literal (64bit)", + "an identifier", + NULL }; void token_free(struct token *t) { - if (t->val) { - free(t->val); + if (t->type == T_ID && t->val_s) { + free(t->val_s); } free(t); } - -struct token token_make_eof(void) { - struct token res; - res.type = T_EOF; - res.val = NULL; - return (res); -} \ No newline at end of file diff --git a/src/util/linklist.c b/src/util/linklist.c index 1a920a7..87ec4a1 100644 --- a/src/util/linklist.c +++ b/src/util/linklist.c @@ -1,28 +1,21 @@ #include #include +#include #include "fatals.h" #include "util/linklist.h" -// Create a linklist node using given value. -struct llist_node* llist_createnode(void *val) { - struct llist_node *res = malloc(sizeof(struct llist_node)); - if (res == NULL) { - fail_malloc(__FUNCTION__); - } - res->nxt = NULL; - res->val = val; - return (res); -} - // Appends an element in the linklist. void llist_pushback(struct linklist *l, void *val) { + struct llist_node *x = (struct llist_node*)val; + x->nxt = NULL; l->length += 1; if (!l->tail) { - l->head = l->tail = llist_createnode(val); + l->head = l->tail = val; return; } - l->tail->nxt = llist_createnode(val); - l->tail = l->tail->nxt; + + l->tail->nxt = x; + l->tail = x; } // A variant of pushback @@ -33,7 +26,7 @@ void llist_pushback_notnull(struct linklist *l, void *val) { } } -// Returns the _index_ thh element. +// Returns the _index_ th element. void* llist_get(struct linklist *l, int index) { if (index >= l->length) { fprintf(stderr, "linklist out of range.\n"); @@ -44,21 +37,12 @@ void* llist_get(struct linklist *l, int index) { for (int i = 0; i < index; ++i) { p = p->nxt; } - return (p->val); + return (p); } -// Modify the _index_ thh element. -void llist_set(struct linklist *l, int index, void *val) { - if (index >= l->length) { - fprintf(stderr, "linklist out of range.\n"); - abort(); - } - - struct llist_node *p = l->head; - for (int i = 0; i < index; ++i) { - p = p->nxt; - } - p->val = val; +// Check if the given linklist is empty +bool llist_isempty(struct linklist *l) { + return (l->length == 0); } // Init a empty linklist. @@ -68,8 +52,8 @@ void llist_init(struct linklist *l) { l->tail = NULL; } -// Frees the linklist. -// Caller must make sure all elements in the linklist has already been freed. +// Frees all elements in the link list. +// Memory leaks if linklist element is still containing some pointer. void llist_free(struct linklist *l) { struct llist_node *p = l->head; struct llist_node *nxt; @@ -81,22 +65,6 @@ void llist_free(struct linklist *l) { llist_init(l); } -// Frees the linklist. -// Callee will free all elements in the link list. -void llist_free_full(struct linklist *l) { - struct llist_node *p = l->head; - struct llist_node *nxt; - while (p) { - nxt = p->nxt; - if (p->val) { - free(p->val); - } - free(p); - p = nxt; - } - llist_init(l); -} - // Insert _val_ into the linklist as the _index_ th element. // If _index_ is too large, pushback only! void llist_insert(struct linklist *l, int index, void *val) { @@ -105,8 +73,8 @@ void llist_insert(struct linklist *l, int index, void *val) { return; } + struct llist_node *x = (struct llist_node*)val; l->length += 1; - struct llist_node *x = llist_createnode(val); if (index == 0) { x->nxt = l->head; l->head = x; @@ -129,16 +97,13 @@ void* llist_popfront(struct linklist *l) { } l->length -= 1; - void *res = l->head->val; + struct llist_node *res = l->head; + l->head = res->nxt; + res->nxt = NULL; if (l->length == 0) { - free(l->head); l->head = l->tail = NULL; - return (res); } - struct llist_node *p = l->head; - l->head = p->nxt; - free(p); return (res); } @@ -148,11 +113,11 @@ void* llist_remove(struct linklist *l, int index) { if (index >= l->length) { return (NULL); } - + if (index == 0) { return (llist_popfront(l)); } - + l->length -= 1; struct llist_node *p = l->head; for (int i = 0; i < index - 2; ++i) { @@ -160,7 +125,6 @@ void* llist_remove(struct linklist *l, int index) { } struct llist_node *q = p->nxt; p->nxt = q->nxt; - void *res = q->val; - free(q); - return res; + q->nxt = NULL; + return (q); } diff --git a/tests/input01 b/tests/input01 deleted file mode 100644 index ed710cf..0000000 --- a/tests/input01 +++ /dev/null @@ -1,4 +0,0 @@ -{ print 12 * 3; - print 18 - 2 * 4; - print 1 + 2 + 9 - 5/2 + 3*5; -} diff --git a/tests/input01.ans b/tests/input01.ans deleted file mode 100644 index 4502630..0000000 --- a/tests/input01.ans +++ /dev/null @@ -1,3 +0,0 @@ -36 -10 -25 diff --git a/tests/input02 b/tests/input02 deleted file mode 100644 index 8627485..0000000 --- a/tests/input02 +++ /dev/null @@ -1,7 +0,0 @@ -{ - int fred; - int jim; - fred= 5; - jim= 12; - print fred + jim; -} diff --git a/tests/input02.ans b/tests/input02.ans deleted file mode 100644 index 98d9bcb..0000000 --- a/tests/input02.ans +++ /dev/null @@ -1 +0,0 @@ -17 diff --git a/tests/input03 b/tests/input03 deleted file mode 100644 index 9882a08..0000000 --- a/tests/input03 +++ /dev/null @@ -1,8 +0,0 @@ -{ - int x; - x= 1; print x; - x= x + 1; print x; - x= x + 1; print x; - x= x + 1; print x; - x= x + 1; print x; -} diff --git a/tests/input03.ans b/tests/input03.ans deleted file mode 100644 index 8a1218a..0000000 --- a/tests/input03.ans +++ /dev/null @@ -1,5 +0,0 @@ -1 -2 -3 -4 -5 diff --git a/tests/input04 b/tests/input04 deleted file mode 100644 index d5edc09..0000000 --- a/tests/input04 +++ /dev/null @@ -1,12 +0,0 @@ -{ - int x; - x= 7 < 9; print x; - x= 7 <= 9; print x; - x= 7 != 9; print x; - x= 7 == 7; print x; - x= 7 >= 7; print x; - x= 7 <= 7; print x; - x= 9 > 7; print x; - x= 9 >= 7; print x; - x= 9 != 7; print x; -} diff --git a/tests/input04.ans b/tests/input04.ans deleted file mode 100644 index bb08505..0000000 --- a/tests/input04.ans +++ /dev/null @@ -1,9 +0,0 @@ -1 -1 -1 -1 -1 -1 -1 -1 -1 diff --git a/tests/input05 b/tests/input05 deleted file mode 100644 index e6fab21..0000000 --- a/tests/input05 +++ /dev/null @@ -1,9 +0,0 @@ -{ - int i; int j; - i=6; j=12; - if (i < j) { - print i; - } else { - print j; - } -} diff --git a/tests/input05.ans b/tests/input05.ans deleted file mode 100644 index 1e8b314..0000000 --- a/tests/input05.ans +++ /dev/null @@ -1 +0,0 @@ -6 diff --git a/tests/input06 b/tests/input06 deleted file mode 100644 index 173722d..0000000 --- a/tests/input06 +++ /dev/null @@ -1,7 +0,0 @@ -{ int i; - i=1; - while (i <= 10) { - print i; - i= i + 1; - } -} diff --git a/tests/input06.ans b/tests/input06.ans deleted file mode 100644 index f00c965..0000000 --- a/tests/input06.ans +++ /dev/null @@ -1,10 +0,0 @@ -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 diff --git a/tests/input07 b/tests/input07 deleted file mode 100644 index dfa01ad..0000000 --- a/tests/input07 +++ /dev/null @@ -1,6 +0,0 @@ -{ - int i; - for (i= 1; i <= 10; i= i + 1) { - print i; - } -} diff --git a/tests/input07.ans b/tests/input07.ans deleted file mode 100644 index f00c965..0000000 --- a/tests/input07.ans +++ /dev/null @@ -1,10 +0,0 @@ -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 diff --git a/tests/input08 b/tests/input08 deleted file mode 100644 index e93b3e9..0000000 --- a/tests/input08 +++ /dev/null @@ -1,6 +0,0 @@ -{ - long a = 5; - long b = a + 5; - int c = b - 1; - print c; -} \ No newline at end of file diff --git a/tests/input08.ans b/tests/input08.ans deleted file mode 100644 index f11c82a..0000000 --- a/tests/input08.ans +++ /dev/null @@ -1 +0,0 @@ -9 \ No newline at end of file diff --git a/tests/invalid/missing_paren.c b/tests/invalid/missing_paren.c new file mode 100644 index 0000000..8e72a5c --- /dev/null +++ b/tests/invalid/missing_paren.c @@ -0,0 +1,3 @@ +int main( { + return 0; +} \ No newline at end of file diff --git a/tests/invalid/missing_retval.c b/tests/invalid/missing_retval.c new file mode 100644 index 0000000..2f8d9bf --- /dev/null +++ b/tests/invalid/missing_retval.c @@ -0,0 +1,3 @@ +int main() { + return; +} \ No newline at end of file diff --git a/tests/invalid/no_brace.c b/tests/invalid/no_brace.c new file mode 100644 index 0000000..96aac66 --- /dev/null +++ b/tests/invalid/no_brace.c @@ -0,0 +1,2 @@ +int main() { + return 0; diff --git a/tests/invalid/no_semicolon.c b/tests/invalid/no_semicolon.c new file mode 100644 index 0000000..584f789 --- /dev/null +++ b/tests/invalid/no_semicolon.c @@ -0,0 +1,3 @@ +int main() { + return 0 +} diff --git a/tests/invalid/no_space.c b/tests/invalid/no_space.c new file mode 100644 index 0000000..14a289b --- /dev/null +++ b/tests/invalid/no_space.c @@ -0,0 +1,3 @@ +int main() { + return0; +} \ No newline at end of file diff --git a/tests/invalid/wrong_case.c b/tests/invalid/wrong_case.c new file mode 100644 index 0000000..bbae350 --- /dev/null +++ b/tests/invalid/wrong_case.c @@ -0,0 +1,3 @@ +int main() { + RETURN 0; +} \ No newline at end of file diff --git a/tests/test_llvm.lua b/tests/test_llvm.lua deleted file mode 100644 index 036b4fa..0000000 --- a/tests/test_llvm.lua +++ /dev/null @@ -1,50 +0,0 @@ -local acc_path = nil -for _, path in ipairs({ "../acc", "../acc.exe", "../acc.out" }) do - if os.exists(path) then - acc_path = path - end -end - -if acc_path == nil then - error("acc executable not found.") -end - -local function compare_file(p1, p2) - local f1 = io.open(p1, "r"); - local f2 = io.open(p2, "r"); - repeat - local l1 = f1:read() - local l2 = f2:read() - if l1 ~= l2 then - f1:close() - f2:close() - return false - end - until l1 == nil - f1:close() - f2:close() - return true -end - -for _, input in ipairs(os.files("tests/input*")) do - if input:endswith(".ans") then - goto continue - end - - local ans = input .. ".ans" - if not os.exists(ans) then - cprint("${orange} [WARN] not found answer for case %s.", input) - goto continue - end - os.run("acc llvm %s out.ll", input) - os.run("clang out.ll -o test.exe") - local output = os.iorun("test.exe") - local output_path = os.tmpfile() - io.writefile(output_path, output) - if compare_file(output_path, ans) then - cprint("${green} [INFO] case %s: OK.", input) - else - cprint("${red} [INFO] case %s: FAILED.", input) - end - ::continue:: -end diff --git a/tests/valid/multi_digit.c b/tests/valid/multi_digit.c new file mode 100644 index 0000000..13f3123 --- /dev/null +++ b/tests/valid/multi_digit.c @@ -0,0 +1,3 @@ +int main() { + return 100; +} \ No newline at end of file diff --git a/tests/valid/newlines.c b/tests/valid/newlines.c new file mode 100644 index 0000000..7d8ba2e --- /dev/null +++ b/tests/valid/newlines.c @@ -0,0 +1,10 @@ + +int +main +( +) +{ +return +0 +; +} \ No newline at end of file diff --git a/tests/valid/no_newlines.c b/tests/valid/no_newlines.c new file mode 100644 index 0000000..6a86477 --- /dev/null +++ b/tests/valid/no_newlines.c @@ -0,0 +1 @@ +int main(){return 0;} \ No newline at end of file diff --git a/tests/valid/return_0.c b/tests/valid/return_0.c new file mode 100644 index 0000000..e9cdae1 --- /dev/null +++ b/tests/valid/return_0.c @@ -0,0 +1,3 @@ +int main() { + return 0; +} \ No newline at end of file diff --git a/tests/valid/return_2.c b/tests/valid/return_2.c new file mode 100644 index 0000000..5c52fee --- /dev/null +++ b/tests/valid/return_2.c @@ -0,0 +1,3 @@ +int main() { + return 2; +} \ No newline at end of file diff --git a/tests/valid/spaces.c b/tests/valid/spaces.c new file mode 100644 index 0000000..e77bfef --- /dev/null +++ b/tests/valid/spaces.c @@ -0,0 +1 @@ + int main ( ) { return 0 ; } \ No newline at end of file