main function(AST)
Signed-off-by: szdytom <szdytom@163.com>
This commit is contained in:
parent
6950807161
commit
121c37c16a
32
README.md
32
README.md
@ -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
|
|
||||||
```
|
|
||||||
|
@ -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
|
||||||
|
29
include/cg.h
29
include/cg.h
@ -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
|
|
@ -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
7
include/print_ast.h
Normal 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
|
||||||
|
|
@ -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);
|
||||||
|
@ -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
11
include/target.h
Normal 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
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
*/
|
||||||
|
@ -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
43
main.c
@ -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
120
src/ast.c
@ -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);
|
||||||
}
|
}
|
||||||
|
38
src/cg.c
38
src/cg.c
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
119
src/cg_ast.c
119
src/cg_ast.c
@ -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);
|
|
||||||
}
|
|
||||||
|
|
216
src/cg_llvm.c
216
src/cg_llvm.c
@ -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();
|
|
||||||
}
|
|
@ -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);
|
||||||
|
104
src/parse.c
104
src/parse.c
@ -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
65
src/print_ast.c
Normal 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);
|
||||||
|
}
|
||||||
|
|
36
src/scan.c
36
src/scan.c
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
22
src/target.c
Normal 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);
|
||||||
|
}
|
21
src/token.c
21
src/token.c
@ -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);
|
|
||||||
}
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
{ print 12 * 3;
|
|
||||||
print 18 - 2 * 4;
|
|
||||||
print 1 + 2 + 9 - 5/2 + 3*5;
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
36
|
|
||||||
10
|
|
||||||
25
|
|
@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
int fred;
|
|
||||||
int jim;
|
|
||||||
fred= 5;
|
|
||||||
jim= 12;
|
|
||||||
print fred + jim;
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
17
|
|
@ -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;
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
1
|
|
||||||
2
|
|
||||||
3
|
|
||||||
4
|
|
||||||
5
|
|
@ -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;
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
1
|
|
||||||
1
|
|
||||||
1
|
|
||||||
1
|
|
||||||
1
|
|
||||||
1
|
|
||||||
1
|
|
||||||
1
|
|
||||||
1
|
|
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
int i; int j;
|
|
||||||
i=6; j=12;
|
|
||||||
if (i < j) {
|
|
||||||
print i;
|
|
||||||
} else {
|
|
||||||
print j;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
6
|
|
@ -1,7 +0,0 @@
|
|||||||
{ int i;
|
|
||||||
i=1;
|
|
||||||
while (i <= 10) {
|
|
||||||
print i;
|
|
||||||
i= i + 1;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
1
|
|
||||||
2
|
|
||||||
3
|
|
||||||
4
|
|
||||||
5
|
|
||||||
6
|
|
||||||
7
|
|
||||||
8
|
|
||||||
9
|
|
||||||
10
|
|
@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
int i;
|
|
||||||
for (i= 1; i <= 10; i= i + 1) {
|
|
||||||
print i;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
1
|
|
||||||
2
|
|
||||||
3
|
|
||||||
4
|
|
||||||
5
|
|
||||||
6
|
|
||||||
7
|
|
||||||
8
|
|
||||||
9
|
|
||||||
10
|
|
@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
long a = 5;
|
|
||||||
long b = a + 5;
|
|
||||||
int c = b - 1;
|
|
||||||
print c;
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
9
|
|
3
tests/invalid/missing_paren.c
Normal file
3
tests/invalid/missing_paren.c
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
int main( {
|
||||||
|
return 0;
|
||||||
|
}
|
3
tests/invalid/missing_retval.c
Normal file
3
tests/invalid/missing_retval.c
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
int main() {
|
||||||
|
return;
|
||||||
|
}
|
2
tests/invalid/no_brace.c
Normal file
2
tests/invalid/no_brace.c
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
int main() {
|
||||||
|
return 0;
|
3
tests/invalid/no_semicolon.c
Normal file
3
tests/invalid/no_semicolon.c
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
int main() {
|
||||||
|
return 0
|
||||||
|
}
|
3
tests/invalid/no_space.c
Normal file
3
tests/invalid/no_space.c
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
int main() {
|
||||||
|
return0;
|
||||||
|
}
|
3
tests/invalid/wrong_case.c
Normal file
3
tests/invalid/wrong_case.c
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
int main() {
|
||||||
|
RETURN 0;
|
||||||
|
}
|
@ -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
|
|
3
tests/valid/multi_digit.c
Normal file
3
tests/valid/multi_digit.c
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
int main() {
|
||||||
|
return 100;
|
||||||
|
}
|
10
tests/valid/newlines.c
Normal file
10
tests/valid/newlines.c
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
int
|
||||||
|
main
|
||||||
|
(
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
0
|
||||||
|
;
|
||||||
|
}
|
1
tests/valid/no_newlines.c
Normal file
1
tests/valid/no_newlines.c
Normal file
@ -0,0 +1 @@
|
|||||||
|
int main(){return 0;}
|
3
tests/valid/return_0.c
Normal file
3
tests/valid/return_0.c
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
int main() {
|
||||||
|
return 0;
|
||||||
|
}
|
3
tests/valid/return_2.c
Normal file
3
tests/valid/return_2.c
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
int main() {
|
||||||
|
return 2;
|
||||||
|
}
|
1
tests/valid/spaces.c
Normal file
1
tests/valid/spaces.c
Normal file
@ -0,0 +1 @@
|
|||||||
|
int main ( ) { return 0 ; }
|
Loading…
x
Reference in New Issue
Block a user