main function(AST)

Signed-off-by: szdytom <szdytom@163.com>
This commit is contained in:
方而静 2023-06-12 16:02:43 +08:00
parent 6950807161
commit 121c37c16a
53 changed files with 399 additions and 842 deletions

View File

@ -1,33 +1,3 @@
# acc # 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
```

View File

@ -9,41 +9,38 @@ enum {
A_ASSIGN, A_ASSIGN,
A_ADD, A_SUB, A_MUL, A_DIV, A_ADD, A_SUB, A_MUL, A_DIV,
A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, 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_BLOCK,
A_PRINT, A_IF, A_WHILE, A_PRINT, A_IF, A_WHILE,
A_RETURN,
A_SOUL // what? A_SOUL // what?
}; };
// value type extern const char *ast_opname[31];
enum {
V_I32, V_I64, V_BOOL
};
struct value_type { // AST structure field shared by all types
int vt; // base value type // llist_node *n : for linklist
}; // int op : node operation
#define ASTnode_SHARED_FIELDS \
// AST nodde types struct llist_node n; \
enum { int op;
N_BIN, N_UN, N_MULTI, N_LEAF, N_ASSIGN
};
// AST structure (common) // AST structure (common)
struct ASTnode { struct ASTnode {
int op; //operator ASTnode_SHARED_FIELDS
}; };
// AST binary operation node // AST binary operation node
struct ASTbinnode { struct ASTbinnode {
int op; ASTnode_SHARED_FIELDS
struct ASTnode *left; struct ASTnode *left;
struct ASTnode *right; struct ASTnode *right;
}; };
// AST if statement node // AST if statement node
struct ASTifnode { struct ASTifnode {
int op; ASTnode_SHARED_FIELDS
struct ASTnode *left; // condition true branch struct ASTnode *left; // condition true branch
struct ASTnode *right; // condition false branch struct ASTnode *right; // condition false branch
struct ASTnode *cond; struct ASTnode *cond;
@ -51,33 +48,38 @@ struct ASTifnode {
// AST unary operation node // AST unary operation node
struct ASTunnode { struct ASTunnode {
int op; ASTnode_SHARED_FIELDS
struct ASTnode *c; struct ASTnode *left;
}; };
// AST block node // AST block node
struct ASTblocknode { struct ASTblocknode {
int op; ASTnode_SHARED_FIELDS
struct linklist st; // statements linklist struct linklist st; // statements linklist
}; };
// AST literal node // AST integer literal (32bit) node
struct ASTlitnode { struct ASTi32node {
int op; ASTnode_SHARED_FIELDS
struct value_type type; int32_t val;
void *val; };
// AST integer literal (64bit) node
struct ASTi64node {
ASTnode_SHARED_FIELDS
int64_t val;
}; };
// AST assign literal node // AST assign literal node
struct ASTassignnode { struct ASTassignnode {
int op; ASTnode_SHARED_FIELDS
int left; struct ASTnode* left;
struct ASTnode* right; struct ASTnode* right;
}; };
// AST variable value node // AST variable value node
struct ASTvarnode { struct ASTvarnode {
int op; ASTnode_SHARED_FIELDS
int id; 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_unary(int op, struct ASTnode *c);
struct ASTnode* ast_make_block(); struct ASTnode* ast_make_block();
struct ASTnode* ast_make_var(int id); 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); 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); void ast_free(struct ASTnode *x);
#endif #endif

View File

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

View File

@ -5,6 +5,7 @@
#include <stdnoreturn.h> #include <stdnoreturn.h>
void* malloc_or_fail(size_t s, const char *func_name); 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_malloc(const char *func_name);
noreturn void fail_ast_op(int op, 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); noreturn void fail_ce_expect(const char *expected, const char *got);

7
include/print_ast.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef ACC_DEBUG_PRINT_AST
#define ACC_DEBUG_PRINT_AST
void debug_ast_print(FILE *Outfile, struct ASTnode *rt);
#endif

View File

@ -1,7 +1,7 @@
#ifndef ACC_SCAN_H #ifndef ACC_SCAN_H
#define ACC_SCAN_H #define ACC_SCAN_H
#include "token.h" #include "util/linklist.h"
extern int Line; extern int Line;
struct linklist scan_tokens(const char *name); struct linklist scan_tokens(const char *name);

View File

@ -1,3 +1,4 @@
/*
#ifndef ACC_SYMBOL_H #ifndef ACC_SYMBOL_H
#define ACC_SYMBOL_H #define ACC_SYMBOL_H
@ -11,3 +12,4 @@ int findglob(char *s);
int addglob(char *s); int addglob(char *s);
#endif #endif
*/

11
include/target.h Normal file
View File

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

View File

@ -1,29 +1,41 @@
#ifndef ACC_TOKEN_H #ifndef ACC_TOKEN_H
#define ACC_TOKEN_H #define ACC_TOKEN_H
#include <stdint.h>
#include "util/linklist.h" #include "util/linklist.h"
// Token structure // Token structure
struct token { struct token {
struct llist_node n;
int type; // token type 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 // Tokens
enum { enum {
T_EOF, T_EOF,
T_SEMI, T_SEMI, // ;
T_LB, T_RB, T_LP, T_RP, T_LB, T_RB, T_LP, T_RP, // { } ( )
T_ASSIGN, T_ASSIGN, // =
T_PLUS, T_MINUS, T_STAR, T_SLASH, T_PLUS, T_MINUS, T_STAR, T_SLASH, // + - * /
T_EQ, T_NE, T_LT, T_GT, T_LE, T_GE, T_EQ, T_NE, T_LT, T_GT, T_LE, T_GE, // == != < > <= >=
T_INT, T_VOID, T_CHAR, T_LONG, T_INT, T_VOID, T_CHAR, T_LONG, // int void char long
T_PRINT, T_IF, T_ELSE, T_WHILE, T_FOR, T_SHORT, // short
T_I32_LIT, T_I64_LIT, T_INDENT, 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]; extern const char *token_typename[63];
void token_free(struct token *t); void token_free(struct token *t);
struct token token_make_eof(void);
#endif #endif

View File

@ -1,3 +1,4 @@
/*
#ifndef ACC_UTIL_HASHMAP #ifndef ACC_UTIL_HASHMAP
#define ACC_UTIL_HASHMAP #define ACC_UTIL_HASHMAP
@ -9,4 +10,5 @@ struct hashmap {
void hashmap_init(); void hashmap_init();
#endif #endif
*/

View File

@ -2,7 +2,6 @@
#define ACC_UTIL_LINKLIST_H #define ACC_UTIL_LINKLIST_H
struct llist_node { struct llist_node {
void *val;
struct llist_node *nxt; struct llist_node *nxt;
}; };
@ -12,8 +11,6 @@ struct linklist {
struct llist_node *tail; struct llist_node *tail;
}; };
struct llist_node* llist_createnode(void *val);
void llist_init(struct linklist *l); void llist_init(struct linklist *l);
void llist_free(struct linklist *l); void llist_free(struct linklist *l);
void llist_free_full(struct linklist *l); void llist_free_full(struct linklist *l);

43
main.c
View File

@ -3,9 +3,9 @@
#include <string.h> #include <string.h>
#include "scan.h" #include "scan.h"
#include "parse.h" #include "parse.h"
#include "cg.h"
#include "ast.h" #include "ast.h"
#include "symbol.h" #include "target.h"
#include "print_ast.h"
// Print out a usage if started incorrectly // Print out a usage if started incorrectly
static void usage(char *prog) { static void usage(char *prog) {
@ -14,48 +14,29 @@ static void usage(char *prog) {
exit(1); exit(1);
} }
//Do clean up job // Do clean up job
void unload(void) { void unload(void) {
cg_unload();
symbol_unload();
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
atexit(unload); // atexit(unload);
if (argc < 3) { if (argc < 3) {
usage(argv[0]); usage(argv[0]);
} }
int outfile_opened = 0; FILE *Outfile;
if (argc >= 4) { if (argc >= 4) {
open_outputfile(argv[3]); Outfile = fopen(argv[3], "w");
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");
}
} else { } else {
fprintf(stderr, "Unknow target %s.\n", argv[1]); Outfile = fopen("out.txt", "w");
exit(1);
} }
symbol_init(); int target = target_parse(argv[1]);
struct ASTnode *rt = parse(argv[2]); struct ASTnode *rt = parse(argv[2]);
cg_main(target, rt); if (target == TARGET_AST) {
debug_ast_print(Outfile, rt);
}
ast_free(rt); ast_free(rt);
fclose(Outfile);
return (0); return (0);
} }

120
src/ast.c
View File

@ -4,6 +4,18 @@
#include "fatals.h" #include "fatals.h"
#include "util/linklist.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 // Build and return a binary AST node
struct ASTnode* ast_make_binary(int op, struct ASTnode *left, struct ASTnode *right) { struct ASTnode* ast_make_binary(int op, struct ASTnode *left, struct ASTnode *right) {
struct ASTbinnode *x = malloc_or_fail(sizeof(struct ASTbinnode), __FUNCTION__); 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); 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 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->op = A_LIT_I32;
x->type.vt = V_I32; x->val = v;
x->val = malloc_or_fail(sizeof(int32_t), __FUNCTION__);
*(int64_t*)x->val = v;
return ((struct ASTnode*)x); 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 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->op = A_LIT_I64;
x->type.vt = V_I64; x->val = v;
x->val = malloc_or_fail(sizeof(int64_t), __FUNCTION__);
*(int64_t*)x->val = v;
return ((struct ASTnode*)x); return ((struct ASTnode*)x);
} }
@ -46,11 +54,11 @@ struct ASTnode* ast_make_var(int id) {
} }
// Make a unary AST node: only one child // 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__); struct ASTunnode *x = malloc_or_fail(sizeof(struct ASTunnode), __FUNCTION__);
x->op = op; x->op = op;
x->c = c; x->left = child;
return ((struct ASTnode*)x); return ((struct ASTnode*)x);
} }
@ -64,7 +72,7 @@ struct ASTnode* ast_make_block() {
} }
// Make a assignment ast node // 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__); struct ASTassignnode *x = malloc_or_fail(sizeof(struct ASTassignnode), __FUNCTION__);
x->op = op; x->op = op;
@ -84,66 +92,44 @@ struct ASTnode* ast_make_if(struct ASTnode *left, struct ASTnode *right, struct
return ((struct ASTnode*)x); 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 // free an AST's memory
void ast_free(struct ASTnode *x) { void ast_free(struct ASTnode *x) {
if (x == NULL) { if (x == NULL) {
return; return;
} }
switch (ast_type(x->op)) { switch (x->op) {
case N_ASSIGN: { case A_IF: {
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) {
ast_free(((struct ASTifnode*)x)->cond); ast_free(((struct ASTifnode*)x)->cond);
} } // dont break
} break;
case N_UN: { case A_ASSIGN:
struct ASTunnode *t = (struct ASTunnode*)x; case A_ADD: case A_SUB: case A_MUL: case A_DIV:
ast_free(t->c); case A_EQ: case A_NE: case A_GT: case A_LT: case A_GE: case A_LE:
} break; case A_WHILE: {
case N_MULTI: { struct ASTbinnode *t = (struct ASTbinnode*)x;
struct ASTblocknode *t = (struct ASTblocknode*)x; ast_free(t->left);
struct llist_node *p = t->st.head; ast_free(t->right);
while (p) { } break;
ast_free(p->val);
p = p->nxt; case A_PRINT: case A_RETURN: {
} struct ASTunnode *t = (struct ASTunnode*)x;
llist_free(&t->st); ast_free(t->left);
} break; } break;
case N_LEAF: {
struct ASTlitnode *t = (struct ASTlitnode*)x; case A_BLOCK: {
if (t->op == A_LIT) { struct ASTblocknode *t = (struct ASTblocknode*)x;
if (t->val) { struct llist_node *p = t->st.head, *nxt;
free(t->val); while (p) {
nxt = p->nxt;
ast_free(p);
p = nxt;
} }
} llist_free(&t->st);
} break; } break;
default: {
} break;
} }
free(x); free(x);
} }

View File

@ -1,38 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#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);
}
}

View File

@ -1,119 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#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);
}

View File

@ -1,216 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#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();
}

View File

@ -2,6 +2,11 @@
#include <stdlib.h> #include <stdlib.h>
#include "scan.h" #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) { void fail_malloc(const char *func_name) {
fprintf(stderr, "%s: unable to malloc.\n", func_name); fprintf(stderr, "%s: unable to malloc.\n", func_name);
exit(1); exit(1);

View File

@ -5,11 +5,9 @@
#include "scan.h" #include "scan.h"
#include "token.h" #include "token.h"
#include "ast.h" #include "ast.h"
#include "symbol.h"
#include "fatals.h" #include "fatals.h"
static struct linklist Tokens; // current token for parsing 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. // Check that we have a binary operator and return its precedence.
// operators with larger precedence value will be evaluated first // operators with larger precedence value will be evaluated first
@ -57,7 +55,7 @@ static int arithop(int t) {
// operator ssociativity direction // operator ssociativity direction
// Returns false if left to right, e.g. + // 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) { static bool direction_rtl(int t) {
switch(t) { switch(t) {
case T_ASSIGN: case T_ASSIGN:
@ -77,10 +75,12 @@ static void next(void) {
// preview next kth token from input stream // preview next kth token from input stream
static struct token* preview(int k) { static struct token* preview(int k) {
if (Tokens.length <= k) { if (Tokens.length <= k) {
static struct token token_eof; static struct token token_eof = {
token_eof = token_make_eof(); .type = T_EOF
};
return (&token_eof); return (&token_eof);
} }
struct token* res = llist_get(&Tokens, k); struct token* res = llist_get(&Tokens, k);
return (res); return (res);
} }
@ -92,9 +92,7 @@ static struct token* current(void) {
// match a token or report syntax error // match a token or report syntax error
static void match(int t) { static void match(int t) {
if (t == T_SEMI && skip_semi) { if (current()->type == t) {
skip_semi = 0;
} else if (current()->type == t) {
next(); next();
} else { } else {
fail_ce_expect(token_typename[current()->type], token_typename[t]); 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. // check current token's type or report syntax error.
static void check(int t) { static void expect(int t) {
if (current()->type != t) { if (current()->type != t) {
fail_ce_expect(token_typename[current()->type], token_typename[t]); fail_ce_expect(token_typename[current()->type], token_typename[t]);
} }
@ -122,11 +120,14 @@ static struct ASTnode* primary(void) {
res = expression(); res = expression();
match(T_RP); match(T_RP);
} else if (current()->type == T_I32_LIT) { } 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(); next();
} else if (current()->type == T_I64_LIT) { } else if (current()->type == T_I64_LIT) {
res = ast_make_lit_i64(*(int64_t*)current()->val); res = ast_make_lit_i64(current()->val_i64);
} else if (current()->type == T_INDENT) { next();
} else if (current()->type == T_ID) {
// TODO: identifier.
/*
int id = findglob((char*)current()->val); int id = findglob((char*)current()->val);
if (id == -1) { if (id == -1) {
fprintf(stderr, "syntax error on line %d: unknown indentifier %s.\n", Line, (char*)current()->val); 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(); next();
return (ast_make_var(id)); return (ast_make_var(id));
*/
res = NULL;
next();
} else { } else {
fprintf(stderr, "syntax error on line %d: primary expression excpeted.\n", Line); fprintf(stderr, "syntax error on line %d: primary expression excpeted.\n", Line);
exit(1); exit(1);
@ -178,7 +182,7 @@ static struct ASTnode* binexpr(int precedence) {
} }
// parse one block of code, e.g. { a; b; } // parse one block of code, e.g. { a; b; }
static struct ASTnode* parse_block(void) { static struct ASTnode* block(void) {
match(T_LB); match(T_LB);
if (current()->type == T_RB) { if (current()->type == T_RB) {
next(); next();
@ -196,15 +200,15 @@ static struct ASTnode* parse_block(void) {
} }
} }
match(T_RB); match(T_RB);
skip_semi = 1;
return ((struct ASTnode*)res); return ((struct ASTnode*)res);
} }
// parse an expression // parse an expression
static struct ASTnode* expression(void) { static struct ASTnode* expression(void) {
if (current()->type == T_LB) { if (current()->type == T_SEMI) {
return (parse_block()); return (NULL);
} }
return (binexpr(0)); return (binexpr(0));
} }
@ -216,10 +220,11 @@ static struct ASTnode* print_statement(void) {
return (res); return (res);
} }
/*
// parse variable declaration statement // parse variable declaration statement
static struct ASTnode* var_declaration(void) { static struct ASTnode* var_declaration(void) {
match(T_INT); match(T_INT);
check(T_INDENT); expect(T_IDENT);
if (findglob((char*)current()->val) != -1) { if (findglob((char*)current()->val) != -1) {
fail_ce("variable declared twice."); fail_ce("variable declared twice.");
} }
@ -228,6 +233,7 @@ static struct ASTnode* var_declaration(void) {
match(T_SEMI); match(T_SEMI);
return (NULL); return (NULL);
} }
*/
// parse an if statement // parse an if statement
static struct ASTnode* if_statement(void) { static struct ASTnode* if_statement(void) {
@ -284,6 +290,10 @@ static struct ASTnode* for_statement(void) {
if (body == NULL && inc == NULL) { if (body == NULL && inc == NULL) {
wbody = NULL; wbody = NULL;
} else if (body == NULL) {
wbody = inc;
} else if (inc == NULL) {
wbody = body;
} else { } else {
struct ASTblocknode* wt = (struct ASTblocknode*)ast_make_block(); struct ASTblocknode* wt = (struct ASTblocknode*)ast_make_block();
llist_pushback_notnull(&wt->st, body); llist_pushback_notnull(&wt->st, body);
@ -293,40 +303,80 @@ static struct ASTnode* for_statement(void) {
llist_pushback_notnull(&container->st, init); llist_pushback_notnull(&container->st, init);
llist_pushback(&container->st, ast_make_binary(A_WHILE, cond, wbody)); 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 // parse one statement
static struct ASTnode* statement(void) { static struct ASTnode* statement(void) {
switch (current()->type) { switch (current()->type) {
case T_LB:
return (block());
case T_SEMI: case T_SEMI:
return (NULL); return (NULL);
case T_PRINT: case T_PRINT:
return (print_statement()); return (print_statement());
case T_INT:
return (var_declaration()); // case T_INT:
// return (var_declaration());
case T_IF: case T_IF:
return (if_statement()); return (if_statement());
case T_WHILE: case T_WHILE:
return (while_statement()); return (while_statement());
case T_FOR: case T_FOR:
return (for_statement()); return (for_statement());
default:
skip_semi = 0; case T_RETURN:
return (return_statement());
default: {
struct ASTnode* res = expression(); struct ASTnode* res = expression();
match(T_SEMI); match(T_SEMI);
return (res); 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 // Parse ans return the full ast
struct ASTnode* parse(const char *name) { struct ASTnode* parse(const char *name) {
Tokens = scan_tokens(name); Tokens = scan_tokens(name);
struct ASTnode* res = statement(); char *func_name;
struct llist_node *p = Tokens.head; struct ASTnode* res = function(&func_name);
while (p != Tokens.tail) {
free(p->val); free(func_name);
p = p->nxt; while (Tokens.length > 0) {
token_free(llist_popfront(&Tokens));
} }
llist_free(&Tokens); llist_free(&Tokens);
return (res); return (res);

65
src/print_ast.c Normal file
View File

@ -0,0 +1,65 @@
#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 = 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);
}

View File

@ -41,7 +41,7 @@ static void skip_whitespaces(void) {
// Scan and return an integer literal value from the input file. // Scan and return an integer literal value from the input file.
static void scan_int(struct token *t) { static void scan_int(struct token *t) {
long long res = 0; int64_t res = 0;
int c = preview(); int c = preview();
while ('0' <= c && c <= '9') { while ('0' <= c && c <= '9') {
res = res * 10 + (c - '0'); res = res * 10 + (c - '0');
@ -51,12 +51,10 @@ static void scan_int(struct token *t) {
if (INT32_MIN <= res && res <= INT32_MAX) { if (INT32_MIN <= res && res <= INT32_MAX) {
t->type = T_I32_LIT; t->type = T_I32_LIT;
t->val = malloc_or_fail(sizeof(int32_t), __FUNCTION__); t->val_i32 = (int32_t)res;
*((int32_t *)t->val) = (int)res;
} else { } else {
t->type = T_I64_LIT; t->type = T_I64_LIT;
t->val = malloc_or_fail(sizeof(int64_t), __FUNCTION__); t->val_i64 = (int64_t)res;
*((int64_t *)t->val) = res;
} }
} }
@ -102,6 +100,7 @@ static bool scan_keyword(struct token *t, char *s) {
"else", "else",
"while", "while",
"for", "for",
"return",
NULL NULL
}; };
@ -114,7 +113,8 @@ static bool scan_keyword(struct token *t, char *s) {
T_ELSE, T_ELSE,
T_WHILE, T_WHILE,
T_FOR, T_FOR,
-1 T_RETURN,
T_EXCEED,
}; };
for (int i = 0; map_s[i] != NULL; ++i) { for (int i = 0; map_s[i] != NULL; ++i) {
@ -139,7 +139,7 @@ static bool scan_1c(struct token *t) {
{'(', T_LP}, {'(', T_LP},
{')', T_RP}, {')', T_RP},
{';', T_SEMI}, {';', T_SEMI},
{'\0', -1} {'\0', T_EXCEED}
}; };
int c = preview(); int c = preview();
@ -156,7 +156,6 @@ static bool scan_1c(struct token *t) {
// Scan and return the next token found in the input. // Scan and return the next token found in the input.
static struct token* scan(void) { static struct token* scan(void) {
struct token *t = malloc_or_fail(sizeof(struct token), __FUNCTION__); struct token *t = malloc_or_fail(sizeof(struct token), __FUNCTION__);
t->val = NULL;
skip_whitespaces(); skip_whitespaces();
int c = preview(); int c = preview();
@ -203,20 +202,16 @@ static struct token* scan(void) {
next(); next();
} }
} else { } else {
// If it's a digit, scan the integer literal value in if (isdigit(c)) { // If it's a digit, scan the integer literal value in
if (isdigit(c)) {
scan_int(t); scan_int(t);
} else if (isalpha(c) || c == '_') { } else if (isalpha(c) || c == '_') {
t->val = scan_indentifier(NULL); t->val_s = scan_indentifier(NULL);
if (scan_keyword(t, t->val)) { if (scan_keyword(t, t->val_s)) { // got a keyword
// got a keyword free(t->val_s);
free(t->val); } else { // not a keyword, so it should be an indentifier.
t->val = NULL; t->type = T_ID;
} else {
// not a keyword, so it should be an indentifier.
t->type = T_INDENT;
} }
} else { } else { // cannot match to anything we know, report error.
fail_char(c); fail_char(c);
} }
} }
@ -242,4 +237,5 @@ struct linklist scan_tokens(const char *name) {
fclose(Infile); fclose(Infile);
return (res); return (res);
} }

View File

@ -1,3 +1,4 @@
/*
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -119,4 +120,4 @@ int addglob(char *s) {
trie_set(ss, res); trie_set(ss, res);
return (res); return (res);
} }
*/

22
src/target.c Normal file
View File

@ -0,0 +1,22 @@
#include <string.h>
#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);
}

View File

@ -1,5 +1,4 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include "token.h" #include "token.h"
const char *token_typename[63] = { const char *token_typename[63] = {
@ -10,20 +9,18 @@ const char *token_typename[63] = {
"+", "-", "*", "/", "+", "-", "*", "/",
"==", "!=", "<", ">", "<=", ">=", "==", "!=", "<", ">", "<=", ">=",
"int", "void", "char", "long", "int", "void", "char", "long",
"print", "if", "else", "while", "for", "short",
"a signed integer literal (size 32)", "a signed integer literal (size 64)", "an indentifier" "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) { void token_free(struct token *t) {
if (t->val) { if (t->type == T_ID && t->val_s) {
free(t->val); free(t->val_s);
} }
free(t); free(t);
} }
struct token token_make_eof(void) {
struct token res;
res.type = T_EOF;
res.val = NULL;
return (res);
}

View File

@ -1,28 +1,21 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <stdbool.h>
#include "fatals.h" #include "fatals.h"
#include "util/linklist.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. // Appends an element in the linklist.
void llist_pushback(struct linklist *l, void *val) { void llist_pushback(struct linklist *l, void *val) {
struct llist_node *x = (struct llist_node*)val;
x->nxt = NULL;
l->length += 1; l->length += 1;
if (!l->tail) { if (!l->tail) {
l->head = l->tail = llist_createnode(val); l->head = l->tail = val;
return; return;
} }
l->tail->nxt = llist_createnode(val);
l->tail = l->tail->nxt; l->tail->nxt = x;
l->tail = x;
} }
// A variant of pushback // 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) { void* llist_get(struct linklist *l, int index) {
if (index >= l->length) { if (index >= l->length) {
fprintf(stderr, "linklist out of range.\n"); 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) { for (int i = 0; i < index; ++i) {
p = p->nxt; p = p->nxt;
} }
return (p->val); return (p);
} }
// Modify the _index_ thh element. // Check if the given linklist is empty
void llist_set(struct linklist *l, int index, void *val) { bool llist_isempty(struct linklist *l) {
if (index >= l->length) { return (l->length == 0);
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;
} }
// Init a empty linklist. // Init a empty linklist.
@ -68,8 +52,8 @@ void llist_init(struct linklist *l) {
l->tail = NULL; l->tail = NULL;
} }
// Frees the linklist. // Frees all elements in the link list.
// Caller must make sure all elements in the linklist has already been freed. // Memory leaks if linklist element is still containing some pointer.
void llist_free(struct linklist *l) { void llist_free(struct linklist *l) {
struct llist_node *p = l->head; struct llist_node *p = l->head;
struct llist_node *nxt; struct llist_node *nxt;
@ -81,22 +65,6 @@ void llist_free(struct linklist *l) {
llist_init(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. // Insert _val_ into the linklist as the _index_ th element.
// If _index_ is too large, pushback only! // If _index_ is too large, pushback only!
void llist_insert(struct linklist *l, int index, void *val) { 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; return;
} }
struct llist_node *x = (struct llist_node*)val;
l->length += 1; l->length += 1;
struct llist_node *x = llist_createnode(val);
if (index == 0) { if (index == 0) {
x->nxt = l->head; x->nxt = l->head;
l->head = x; l->head = x;
@ -129,16 +97,13 @@ void* llist_popfront(struct linklist *l) {
} }
l->length -= 1; 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) { if (l->length == 0) {
free(l->head);
l->head = l->tail = NULL; l->head = l->tail = NULL;
return (res);
} }
struct llist_node *p = l->head;
l->head = p->nxt;
free(p);
return (res); return (res);
} }
@ -148,11 +113,11 @@ void* llist_remove(struct linklist *l, int index) {
if (index >= l->length) { if (index >= l->length) {
return (NULL); return (NULL);
} }
if (index == 0) { if (index == 0) {
return (llist_popfront(l)); return (llist_popfront(l));
} }
l->length -= 1; l->length -= 1;
struct llist_node *p = l->head; struct llist_node *p = l->head;
for (int i = 0; i < index - 2; ++i) { 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; struct llist_node *q = p->nxt;
p->nxt = q->nxt; p->nxt = q->nxt;
void *res = q->val; q->nxt = NULL;
free(q); return (q);
return res;
} }

View File

@ -1,4 +0,0 @@
{ print 12 * 3;
print 18 - 2 * 4;
print 1 + 2 + 9 - 5/2 + 3*5;
}

View File

@ -1,3 +0,0 @@
36
10
25

View File

@ -1,7 +0,0 @@
{
int fred;
int jim;
fred= 5;
jim= 12;
print fred + jim;
}

View File

@ -1 +0,0 @@
17

View File

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

View File

@ -1,5 +0,0 @@
1
2
3
4
5

View File

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

View File

@ -1,9 +0,0 @@
1
1
1
1
1
1
1
1
1

View File

@ -1,9 +0,0 @@
{
int i; int j;
i=6; j=12;
if (i < j) {
print i;
} else {
print j;
}
}

View File

@ -1 +0,0 @@
6

View File

@ -1,7 +0,0 @@
{ int i;
i=1;
while (i <= 10) {
print i;
i= i + 1;
}
}

View File

@ -1,10 +0,0 @@
1
2
3
4
5
6
7
8
9
10

View File

@ -1,6 +0,0 @@
{
int i;
for (i= 1; i <= 10; i= i + 1) {
print i;
}
}

View File

@ -1,10 +0,0 @@
1
2
3
4
5
6
7
8
9
10

View File

@ -1,6 +0,0 @@
{
long a = 5;
long b = a + 5;
int c = b - 1;
print c;
}

View File

@ -1 +0,0 @@
9

View File

@ -0,0 +1,3 @@
int main( {
return 0;
}

View File

@ -0,0 +1,3 @@
int main() {
return;
}

2
tests/invalid/no_brace.c Normal file
View File

@ -0,0 +1,2 @@
int main() {
return 0;

View File

@ -0,0 +1,3 @@
int main() {
return 0
}

3
tests/invalid/no_space.c Normal file
View File

@ -0,0 +1,3 @@
int main() {
return0;
}

View File

@ -0,0 +1,3 @@
int main() {
RETURN 0;
}

View File

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

View File

@ -0,0 +1,3 @@
int main() {
return 100;
}

10
tests/valid/newlines.c Normal file
View File

@ -0,0 +1,10 @@
int
main
(
)
{
return
0
;
}

View File

@ -0,0 +1 @@
int main(){return 0;}

3
tests/valid/return_0.c Normal file
View File

@ -0,0 +1,3 @@
int main() {
return 0;
}

3
tests/valid/return_2.c Normal file
View File

@ -0,0 +1,3 @@
int main() {
return 2;
}

1
tests/valid/spaces.c Normal file
View File

@ -0,0 +1 @@
int main ( ) { return 0 ; }