refactory code
This commit is contained in:
parent
1d6c3ce4c0
commit
440bc22ac7
3
.gitignore
vendored
3
.gitignore
vendored
@ -8,6 +8,9 @@
|
||||
*.obj
|
||||
*.elf
|
||||
|
||||
# Debugger
|
||||
*.pdb
|
||||
|
||||
# Linker output
|
||||
*.ilk
|
||||
*.map
|
||||
|
@ -1,8 +1,10 @@
|
||||
#ifndef ACC_FATALS_H
|
||||
#define ACC_FATALS_H
|
||||
|
||||
#include "noreturn.h"
|
||||
#include <stddef.h>
|
||||
#include <stdnoreturn.h>
|
||||
|
||||
void* malloc_or_fail(size_t s, 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_ce_expect(const char *expected, const char *got);
|
||||
|
@ -1,6 +0,0 @@
|
||||
#ifndef ACC_NORETURN_H
|
||||
#define ACC_NORETURN_H
|
||||
|
||||
#define noreturn _Noreturn
|
||||
|
||||
#endif
|
@ -19,9 +19,9 @@ enum {
|
||||
T_EQ, T_NE, T_LT, T_GT, T_LE, T_GE,
|
||||
T_INT, T_VOID, T_CHAR, T_LONG,
|
||||
T_PRINT, T_IF, T_ELSE, T_WHILE, T_FOR,
|
||||
T_INTLIT, T_LONGLIT, T_INDENT,
|
||||
T_I32_LIT, T_I64_LIT, T_INDENT,
|
||||
};
|
||||
extern const char *token_typename[29];
|
||||
extern const char *token_typename[63];
|
||||
|
||||
void token_free(struct token *t);
|
||||
struct token token_make_eof(void);
|
||||
|
@ -13,13 +13,19 @@ struct linklist {
|
||||
};
|
||||
|
||||
struct llist_node* llist_createnode(void *val);
|
||||
void llist_pushback(struct linklist *l, void *val);
|
||||
void llist_pushback_notnull(struct linklist *l, void *val);
|
||||
void* llist_get(struct linklist *l, int x);
|
||||
void llist_set(struct linklist *l, int x, void *val);
|
||||
|
||||
void llist_init(struct linklist *l);
|
||||
void llist_free(struct linklist *l);
|
||||
void llist_free_full(struct linklist *l);
|
||||
|
||||
void llist_pushback(struct linklist *l, void *val);
|
||||
void llist_pushback_notnull(struct linklist *l, void *val);
|
||||
|
||||
void* llist_get(struct linklist *l, int x);
|
||||
void llist_set(struct linklist *l, int x, void *val);
|
||||
|
||||
void llist_insert(struct linklist *l, int x, void *val);
|
||||
void llist_popfront(struct linklist *l);
|
||||
void* llist_popfront(struct linklist *l);
|
||||
void* llist_remove(struct linklist *l, int index);
|
||||
|
||||
#endif
|
||||
|
@ -1,7 +1,9 @@
|
||||
#ifndef ACC_UTIL_MISC_H
|
||||
#define ACC_UTIL_MISC_H
|
||||
|
||||
int strequal(const char *s1, const char *s2);
|
||||
#include <stdbool.h>
|
||||
|
||||
bool strequal(const char *s1, const char *s2);
|
||||
char *strclone(const char *s);
|
||||
|
||||
#endif
|
||||
|
35
src/ast.c
35
src/ast.c
@ -6,10 +6,7 @@
|
||||
|
||||
// Build and return a binary AST node
|
||||
struct ASTnode* ast_make_binary(int op, struct ASTnode *left, struct ASTnode *right) {
|
||||
struct ASTbinnode *x = malloc(sizeof(struct ASTbinnode));
|
||||
if (x == NULL) {
|
||||
fail_malloc(__FUNCTION__);
|
||||
}
|
||||
struct ASTbinnode *x = malloc_or_fail(sizeof(struct ASTbinnode), __FUNCTION__);
|
||||
|
||||
x->op = op;
|
||||
x->left = left;
|
||||
@ -19,10 +16,7 @@ struct ASTnode* ast_make_binary(int op, struct ASTnode *left, struct ASTnode *ri
|
||||
|
||||
// Make an AST int literal node
|
||||
struct ASTnode* ast_make_intlit(int val) {
|
||||
struct ASTintnode *x = malloc(sizeof(struct ASTintnode));
|
||||
if (x == NULL) {
|
||||
fail_malloc(__FUNCTION__);
|
||||
}
|
||||
struct ASTintnode *x = malloc_or_fail(sizeof(struct ASTintnode), __FUNCTION__);
|
||||
|
||||
x->op = A_INTLIT;
|
||||
x->val = val;
|
||||
@ -31,10 +25,7 @@ struct ASTnode* ast_make_intlit(int val) {
|
||||
|
||||
// Make an AST variable value node
|
||||
struct ASTnode* ast_make_var(int id) {
|
||||
struct ASTvarnode *x = malloc(sizeof(struct ASTvarnode));
|
||||
if (x == NULL) {
|
||||
fail_malloc(__FUNCTION__);
|
||||
}
|
||||
struct ASTvarnode *x = malloc_or_fail(sizeof(struct ASTvarnode), __FUNCTION__);
|
||||
|
||||
x->op = A_VAR;
|
||||
x->id = id;
|
||||
@ -43,10 +34,7 @@ struct ASTnode* ast_make_var(int id) {
|
||||
|
||||
// Make a unary AST node: only one child
|
||||
struct ASTnode* ast_make_unary(int op, struct ASTnode *c) {
|
||||
struct ASTunnode *x = malloc(sizeof(struct ASTunnode));
|
||||
if (x == NULL) {
|
||||
fail_malloc(__FUNCTION__);
|
||||
}
|
||||
struct ASTunnode *x = malloc_or_fail(sizeof(struct ASTunnode), __FUNCTION__);
|
||||
|
||||
x->op = op;
|
||||
x->c = c;
|
||||
@ -55,10 +43,7 @@ struct ASTnode* ast_make_unary(int op, struct ASTnode *c) {
|
||||
|
||||
// Make a block ast node
|
||||
struct ASTnode* ast_make_block() {
|
||||
struct ASTblocknode *x = malloc(sizeof(struct ASTblocknode));
|
||||
if (x == NULL) {
|
||||
fail_malloc(__FUNCTION__);
|
||||
}
|
||||
struct ASTblocknode *x = malloc_or_fail(sizeof(struct ASTblocknode), __FUNCTION__);
|
||||
|
||||
x->op = A_BLOCK;
|
||||
llist_init(&x->st);
|
||||
@ -67,10 +52,7 @@ struct ASTnode* ast_make_block() {
|
||||
|
||||
// Make a assignment ast node
|
||||
struct ASTnode* ast_make_assign(int op, int left, struct ASTnode *right) {
|
||||
struct ASTassignnode *x = malloc(sizeof(struct ASTassignnode));
|
||||
if (x == NULL) {
|
||||
fail_malloc(__FUNCTION__);
|
||||
}
|
||||
struct ASTassignnode *x = malloc_or_fail(sizeof(struct ASTassignnode), __FUNCTION__);
|
||||
|
||||
x->op = op;
|
||||
x->left = left;
|
||||
@ -80,10 +62,7 @@ struct ASTnode* ast_make_assign(int op, int left, struct ASTnode *right) {
|
||||
|
||||
// Make a if statement ast node
|
||||
struct ASTnode* ast_make_if(struct ASTnode *left, struct ASTnode *right, struct ASTnode *cond) {
|
||||
struct ASTifnode *x = malloc(sizeof(struct ASTifnode));
|
||||
if (x == NULL) {
|
||||
fail_malloc(__FUNCTION__);
|
||||
}
|
||||
struct ASTifnode *x = malloc_or_fail(sizeof(struct ASTifnode), __FUNCTION__);
|
||||
|
||||
x->op = A_IF;
|
||||
x->left = left;
|
||||
|
@ -53,7 +53,7 @@ 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 (ty[0] != 'i' || ty[1] != '1' || ty[2] != '\0') {
|
||||
if (strcmp(ty, "i1") != 0) { // special case for bool
|
||||
fprintf(Outfile, "\t%%%d = zext i1 %%%d to %s\n", r2, r1, ty);
|
||||
}
|
||||
return (r2);
|
||||
|
@ -7,6 +7,14 @@ void fail_malloc(const char *func_name) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void* malloc_or_fail(size_t s, const char *func_name) {
|
||||
void *res = malloc(s);
|
||||
if (res == NULL) {
|
||||
fail_malloc(func_name);
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
void fail_ast_op(int op, const char *func_name) {
|
||||
fprintf(stderr, "%s: unknown ast operator %d.\n", func_name, op);
|
||||
exit(1);
|
||||
|
71
src/parse.c
71
src/parse.c
@ -1,5 +1,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "scan.h"
|
||||
#include "token.h"
|
||||
#include "ast.h"
|
||||
@ -42,10 +44,10 @@ static int arithop(int t) {
|
||||
{T_GT, A_GT},
|
||||
{T_GE, A_GE},
|
||||
{T_ASSIGN, A_ASSIGN},
|
||||
{T_EOF}
|
||||
{-1}
|
||||
};
|
||||
|
||||
for (int i = 0; map[i][0] != T_EOF; ++i) {
|
||||
for (int i = 0; map[i][0] != -1; ++i) {
|
||||
if (t == map[i][0]) {
|
||||
return map[i][1];
|
||||
}
|
||||
@ -54,22 +56,21 @@ static int arithop(int t) {
|
||||
}
|
||||
|
||||
// operator ssociativity direction
|
||||
// Return 0 if left to right, e.g. +
|
||||
// 1 if right to left, e.g. =
|
||||
static int direction_rtl(int t) {
|
||||
// Returns false if left to right, e.g. +
|
||||
// true if right to left, e.g. =
|
||||
static bool direction_rtl(int t) {
|
||||
switch(t) {
|
||||
case T_ASSIGN:
|
||||
return (1);
|
||||
return (true);
|
||||
default:
|
||||
return (0);
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
|
||||
// Next token
|
||||
static void next(void) {
|
||||
if (Tokens.head) {
|
||||
token_free(Tokens.head->val);
|
||||
llist_popfront(&Tokens);
|
||||
token_free(llist_popfront(&Tokens));
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,7 +79,8 @@ static struct token preview(int k) {
|
||||
if (Tokens.length <= k) {
|
||||
return (token_make_eof());
|
||||
}
|
||||
return (*((struct token*)llist_get(&Tokens, k)));
|
||||
struct token* res = llist_get(&Tokens, k);
|
||||
return (*res);
|
||||
}
|
||||
|
||||
// return current token from input stream
|
||||
@ -117,12 +119,12 @@ static struct ASTnode* primary(void) {
|
||||
next();
|
||||
res = expression();
|
||||
match(T_RP);
|
||||
} else if (current().type == T_INTLIT) {
|
||||
res = ast_make_intlit(*((int*)current().val));
|
||||
} else if (current().type == T_I32_LIT) {
|
||||
res = ast_make_intlit(*(int32_t*)current().val);
|
||||
next();
|
||||
} else if (current().type == T_LONGLIT) {
|
||||
} else if (current().type == T_I64_LIT) {
|
||||
// todo
|
||||
fprintf(stderr, "TOOD.\n");
|
||||
fprintf(stderr, "TOOD: T_I64_LIT.\n");
|
||||
exit(1);
|
||||
} else if (current().type == T_INDENT) {
|
||||
int id = findglob((char*)current().val);
|
||||
@ -296,29 +298,24 @@ static struct ASTnode* for_statement(void) {
|
||||
|
||||
// parse one statement
|
||||
static struct ASTnode* statement(void) {
|
||||
if (current().type == T_SEMI) {
|
||||
return (NULL);
|
||||
}
|
||||
else if (current().type == T_PRINT) {
|
||||
return (print_statement());
|
||||
}
|
||||
else if (current().type == T_INT) {
|
||||
return (var_declaration());
|
||||
}
|
||||
else if (current().type == T_IF) {
|
||||
return (if_statement());
|
||||
}
|
||||
else if (current().type == T_WHILE) {
|
||||
return (while_statement());
|
||||
}
|
||||
else if (current().type == T_FOR) {
|
||||
return (for_statement());
|
||||
}
|
||||
else {
|
||||
skip_semi = 0;
|
||||
struct ASTnode* res = expression();
|
||||
match(T_SEMI);
|
||||
return (res);
|
||||
switch (current().type) {
|
||||
case T_SEMI:
|
||||
return (NULL);
|
||||
case T_PRINT:
|
||||
return (print_statement());
|
||||
case T_INT:
|
||||
return (var_declaration());
|
||||
case T_IF:
|
||||
return (if_statement());
|
||||
case T_WHILE:
|
||||
return (while_statement());
|
||||
case T_FOR:
|
||||
return (for_statement());
|
||||
default:
|
||||
skip_semi = 0;
|
||||
struct ASTnode* res = expression();
|
||||
match(T_SEMI);
|
||||
return (res);
|
||||
}
|
||||
}
|
||||
|
||||
|
79
src/scan.c
79
src/scan.c
@ -1,8 +1,9 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "token.h"
|
||||
#include "fatals.h"
|
||||
#include "util/misc.h"
|
||||
@ -11,18 +12,6 @@ int Line = 1;
|
||||
static int Preview;
|
||||
static FILE *Infile;
|
||||
|
||||
const char *token_typename[] = {
|
||||
"EOF",
|
||||
";",
|
||||
"{", "}", "(", ")",
|
||||
"=",
|
||||
"+", "-", "*", "/",
|
||||
"==", "!=", "<", ">", "<=", ">=",
|
||||
"int", "void", "char", "long",
|
||||
"print", "if", "else", "while", "for",
|
||||
"an integer literal (type int)", "an integer literal (type long)", "an indentifier"
|
||||
};
|
||||
|
||||
// preview one char, not getting it out from the stream
|
||||
static int preview(void) {
|
||||
if (!Preview) {
|
||||
@ -43,9 +32,7 @@ static void next(void) {
|
||||
// Skip past input that we don't need to deal with,
|
||||
// i.e. whitespace, newlines.
|
||||
static void skip_whitespaces(void) {
|
||||
int c;
|
||||
|
||||
c = preview();
|
||||
int c = preview();
|
||||
while (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f') {
|
||||
next();
|
||||
c = preview();
|
||||
@ -53,7 +40,7 @@ static void skip_whitespaces(void) {
|
||||
}
|
||||
|
||||
// Scan and return an integer literal value from the input file.
|
||||
static void scanint(struct token *t) {
|
||||
static void scan_int(struct token *t) {
|
||||
long long res = 0;
|
||||
int c = preview();
|
||||
while ('0' <= c && c <= '9') {
|
||||
@ -62,40 +49,35 @@ static void scanint(struct token *t) {
|
||||
c = preview();
|
||||
}
|
||||
|
||||
if (INT_MIN <= res && res <= INT_MAX) {
|
||||
t->type = T_INTLIT;
|
||||
t->val = malloc(sizeof(int));
|
||||
if (t->val == NULL) {
|
||||
fail_malloc(__FUNCTION__);
|
||||
}
|
||||
*((int *)t->val) = (int)res;
|
||||
if (INT32_MIN <= res && res <= INT32_MAX) {
|
||||
t->type = T_I32_LIT;
|
||||
t->val = malloc_or_fail(sizeof(int32_t), __FUNCTION__);
|
||||
*((int32_t *)t->val) = (int)res;
|
||||
} else {
|
||||
t->type = T_LONGLIT;
|
||||
t->val = malloc(sizeof(long long));
|
||||
if (t->val == NULL) {
|
||||
fail_malloc(__FUNCTION__);
|
||||
}
|
||||
*((long long *)t->val) = res;
|
||||
t->type = T_I64_LIT;
|
||||
t->val = malloc_or_fail(sizeof(int64_t), __FUNCTION__);
|
||||
*((int64_t *)t->val) = res;
|
||||
}
|
||||
}
|
||||
|
||||
// Scan an identifier from the input file and
|
||||
// Return the identifier (char*)
|
||||
// Return the identifier string (char*)
|
||||
// Writes the length into _n_ or NULL
|
||||
static char* scan_indentifier(int *n) {
|
||||
int sz = 128, len = 0;
|
||||
|
||||
char *res = malloc(sz * sizeof(char));
|
||||
char *res = malloc_or_fail(sz * sizeof(char), __FUNCTION__);
|
||||
memset(res, 0, sz * sizeof(char));
|
||||
|
||||
int c = preview();
|
||||
while (isdigit(c) || isalpha(c) || c == '_') {
|
||||
if (len >= sz - 1) {
|
||||
sz *= 2;
|
||||
char *old = res;
|
||||
res = malloc(sz * sizeof(char));
|
||||
memcpy(res, old, len * sizeof(char));
|
||||
char *res = realloc(res, sz * sizeof(char));
|
||||
if (res == NULL) {
|
||||
fail_malloc(__FUNCTION__);
|
||||
}
|
||||
memset(res + len * sizeof(char), 0, (sz - len) * sizeof(char));
|
||||
free(old);
|
||||
}
|
||||
res[len++] = c;
|
||||
next();
|
||||
@ -108,8 +90,9 @@ static char* scan_indentifier(int *n) {
|
||||
return (res);
|
||||
}
|
||||
|
||||
// Given a word from the input, scan if it is a keyword
|
||||
static int scan_keyword(struct token *t, char *s) {
|
||||
// Given a word from the input, scan if it is a keyword.
|
||||
// Returns true if found keyword.
|
||||
static bool scan_keyword(struct token *t, char *s) {
|
||||
static const char *map_s[] = {
|
||||
"print",
|
||||
"int",
|
||||
@ -137,15 +120,15 @@ static int scan_keyword(struct token *t, char *s) {
|
||||
for (int i = 0; map_s[i] != NULL; ++i) {
|
||||
if (strequal(map_s[i], s)) {
|
||||
t->type = map_t[i];
|
||||
return (1);
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Scan one char token
|
||||
// Return 1 if found
|
||||
static int scan_1c(struct token *t) {
|
||||
static bool scan_1c(struct token *t) {
|
||||
static const int map[][2] = {
|
||||
{'+', T_PLUS},
|
||||
{'-', T_MINUS},
|
||||
@ -164,18 +147,15 @@ static int scan_1c(struct token *t) {
|
||||
if (map[i][0] == c) {
|
||||
t->type = map[i][1];
|
||||
next();
|
||||
return (1);
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Scan and return the next token found in the input.
|
||||
static struct token* scan(void) {
|
||||
struct token *t = malloc(sizeof(struct token));
|
||||
if (t == NULL) {
|
||||
fail_malloc(__FUNCTION__);
|
||||
}
|
||||
struct token *t = malloc_or_fail(sizeof(struct token), __FUNCTION__);
|
||||
t->val = NULL;
|
||||
|
||||
skip_whitespaces();
|
||||
@ -204,8 +184,7 @@ static struct token* scan(void) {
|
||||
t->type = T_NE;
|
||||
next();
|
||||
} else {
|
||||
fprintf(stderr, "Unrecognised character %c on line %d.\n", c, Line);
|
||||
exit(1);
|
||||
fail_char(c);
|
||||
}
|
||||
} else if (c == '<') {
|
||||
t->type = T_LT;
|
||||
@ -226,7 +205,7 @@ static struct token* scan(void) {
|
||||
} else {
|
||||
// If it's a digit, scan the integer literal value in
|
||||
if (isdigit(c)) {
|
||||
scanint(t);
|
||||
scan_int(t);
|
||||
} else if (isalpha(c) || c == '_') {
|
||||
t->val = scan_indentifier(NULL);
|
||||
if (scan_keyword(t, t->val)) {
|
||||
|
12
src/token.c
12
src/token.c
@ -2,6 +2,18 @@
|
||||
#include <stdio.h>
|
||||
#include "token.h"
|
||||
|
||||
const char *token_typename[63] = {
|
||||
"EOF",
|
||||
";",
|
||||
"{", "}", "(", ")",
|
||||
"=",
|
||||
"+", "-", "*", "/",
|
||||
"==", "!=", "<", ">", "<=", ">=",
|
||||
"int", "void", "char", "long",
|
||||
"print", "if", "else", "while", "for",
|
||||
"a signed integer literal (size 32)", "a signed integer literal (size 64)", "an indentifier"
|
||||
};
|
||||
|
||||
void token_free(struct token *t) {
|
||||
if (t->val) {
|
||||
free(t->val);
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "fatals.h"
|
||||
#include "util/linklist.h"
|
||||
|
||||
// Create a linklist node using given value.
|
||||
struct llist_node* llist_createnode(void *val) {
|
||||
struct llist_node *res = malloc(sizeof(struct llist_node));
|
||||
if (res == NULL) {
|
||||
@ -13,6 +14,7 @@ struct llist_node* llist_createnode(void *val) {
|
||||
return (res);
|
||||
}
|
||||
|
||||
// Appends an element in the linklist.
|
||||
void llist_pushback(struct linklist *l, void *val) {
|
||||
l->length += 1;
|
||||
if (!l->tail) {
|
||||
@ -23,44 +25,51 @@ void llist_pushback(struct linklist *l, void *val) {
|
||||
l->tail = l->tail->nxt;
|
||||
}
|
||||
|
||||
// A variant of pushback
|
||||
// Only does pushback if _val_ is not null.
|
||||
void llist_pushback_notnull(struct linklist *l, void *val) {
|
||||
if (val) {
|
||||
llist_pushback(l, val);
|
||||
}
|
||||
}
|
||||
|
||||
void* llist_get(struct linklist *l, int x) {
|
||||
if (x >= l->length) {
|
||||
// Returns the _index_ thh element.
|
||||
void* llist_get(struct linklist *l, int index) {
|
||||
if (index >= l->length) {
|
||||
fprintf(stderr, "linklist out of range.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
struct llist_node *p = l->head;
|
||||
for (int i = 0; i < x; ++i) {
|
||||
for (int i = 0; i < index; ++i) {
|
||||
p = p->nxt;
|
||||
}
|
||||
return (p->val);
|
||||
}
|
||||
|
||||
void llist_set(struct linklist *l, int x, void *val) {
|
||||
if (x >= l->length) {
|
||||
// Modify the _index_ thh element.
|
||||
void llist_set(struct linklist *l, int index, void *val) {
|
||||
if (index >= l->length) {
|
||||
fprintf(stderr, "linklist out of range.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
struct llist_node *p = l->head;
|
||||
for (int i = 0; i < x; ++i) {
|
||||
for (int i = 0; i < index; ++i) {
|
||||
p = p->nxt;
|
||||
}
|
||||
p->val = val;
|
||||
}
|
||||
|
||||
// Init a empty linklist.
|
||||
void llist_init(struct linklist *l) {
|
||||
l->length = 0;
|
||||
l->head = NULL;
|
||||
l->tail = NULL;
|
||||
}
|
||||
|
||||
// Frees the linklist.
|
||||
// Caller must make sure all elements in the linklist has already been freed.
|
||||
void llist_free(struct linklist *l) {
|
||||
struct llist_node *p = l->head;
|
||||
struct llist_node *nxt;
|
||||
@ -72,6 +81,24 @@ void llist_free(struct linklist *l) {
|
||||
llist_init(l);
|
||||
}
|
||||
|
||||
// Frees the linklist.
|
||||
// Callee will free all elements in the link list.
|
||||
void llist_free_full(struct linklist *l) {
|
||||
struct llist_node *p = l->head;
|
||||
struct llist_node *nxt;
|
||||
while (p) {
|
||||
nxt = p->nxt;
|
||||
if (p->val) {
|
||||
free(p->val);
|
||||
}
|
||||
free(p);
|
||||
p = nxt;
|
||||
}
|
||||
llist_init(l);
|
||||
}
|
||||
|
||||
// Insert _val_ into the linklist as the _index_ th element.
|
||||
// If _index_ is too large, pushback only!
|
||||
void llist_insert(struct linklist *l, int index, void *val) {
|
||||
if (index >= l->length) {
|
||||
llist_pushback(l, val);
|
||||
@ -94,18 +121,46 @@ void llist_insert(struct linklist *l, int index, void *val) {
|
||||
p->nxt = x;
|
||||
}
|
||||
|
||||
void llist_popfront(struct linklist *l) {
|
||||
// Pop the first element of the link list
|
||||
// Return the first element.
|
||||
void* llist_popfront(struct linklist *l) {
|
||||
if (l->head == NULL) {
|
||||
return;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
l->length -= 1;
|
||||
void *res = l->head->val;
|
||||
if (l->length == 0) {
|
||||
free(l->head);
|
||||
l->head = l->tail = NULL;
|
||||
return (res);
|
||||
}
|
||||
|
||||
struct llist_node *p = l->head;
|
||||
l->head = p->nxt;
|
||||
free(p);
|
||||
return (res);
|
||||
}
|
||||
|
||||
// Removes the _index_ th element from the linklist.
|
||||
// Returns the removed value.
|
||||
void* llist_remove(struct linklist *l, int index) {
|
||||
if (index >= l->length) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (index == 0) {
|
||||
return (llist_popfront(l));
|
||||
}
|
||||
|
||||
l->length -= 1;
|
||||
struct llist_node *p = l->head;
|
||||
for (int i = 0; i < index - 2; ++i) {
|
||||
p = p->nxt;
|
||||
}
|
||||
struct llist_node *q = p->nxt;
|
||||
p->nxt = q->nxt;
|
||||
void *res = q->val;
|
||||
free(q);
|
||||
return res;
|
||||
}
|
||||
|
@ -1,22 +1,15 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "util/misc.h"
|
||||
|
||||
// check if two string are the same
|
||||
int strequal(const char *s1, const char *s2) {
|
||||
for (int i = 1; ; ++i) {
|
||||
if (s1[i] != s2[i]) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (s1[i] == '\0') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (1);
|
||||
bool strequal(const char *s1, const char *s2) {
|
||||
return (strcmp(s1, s2) == 0);
|
||||
}
|
||||
|
||||
// A impl of C23 strdup()
|
||||
char* strclone(char *s) {
|
||||
// Clones the given string
|
||||
char* strclone(const char *s) {
|
||||
int n = strlen(s);
|
||||
char *res = malloc(n + 1);
|
||||
memcpy(res, s, n * sizeof(char));
|
||||
|
50
tests/test_llvm.lua
Normal file
50
tests/test_llvm.lua
Normal file
@ -0,0 +1,50 @@
|
||||
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
|
@ -1,30 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Run each test and compare
|
||||
# against known good output
|
||||
|
||||
set -e
|
||||
|
||||
echo "Testing for target llvm..."
|
||||
|
||||
if [ ! -f ../acc ]
|
||||
then echo "Need to build ../acc first!"; exit 1
|
||||
fi
|
||||
|
||||
for i in input*
|
||||
do if [ ! -f "out.$i" ]
|
||||
then echo "Can't run test on $i, no answer file!"
|
||||
else
|
||||
echo -n $i
|
||||
../acc llvm $i
|
||||
clang -o out out.ll -w
|
||||
./out > trial.$i
|
||||
cmp -s "out.$i" "trial.$i"
|
||||
if [ "$?" -eq "1" ]
|
||||
then echo ": failed"
|
||||
diff -c "out.$i" "trial.$i"
|
||||
echo
|
||||
else echo ": OK"
|
||||
fi
|
||||
rm -f out out.ll "trial.$i"
|
||||
fi
|
||||
done
|
@ -1,30 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Run each test and compare
|
||||
# against known good output
|
||||
|
||||
set -e
|
||||
|
||||
echo "Testing for target x86_64..."
|
||||
|
||||
if [ ! -f ../acc ]
|
||||
then echo "Need to build ../acc first!"; exit 1
|
||||
fi
|
||||
|
||||
for i in input*
|
||||
do if [ ! -f "out.$i" ]
|
||||
then echo "Can't run test on $i, no answer file!"
|
||||
else
|
||||
echo -n $i
|
||||
../acc x86_64 $i
|
||||
gcc -o out out.s
|
||||
./out > trial.$i
|
||||
cmp -s "out.$i" "trial.$i"
|
||||
if [ "$?" -eq "1" ]
|
||||
then echo ": failed"
|
||||
diff -c "out.$i" "trial.$i"
|
||||
echo
|
||||
else echo ": OK"
|
||||
fi
|
||||
rm -f out out.s "trial.$i"
|
||||
fi
|
||||
done
|
Loading…
x
Reference in New Issue
Block a user