refactory code
This commit is contained in:
parent
1d6c3ce4c0
commit
440bc22ac7
3
.gitignore
vendored
3
.gitignore
vendored
@ -8,6 +8,9 @@
|
|||||||
*.obj
|
*.obj
|
||||||
*.elf
|
*.elf
|
||||||
|
|
||||||
|
# Debugger
|
||||||
|
*.pdb
|
||||||
|
|
||||||
# Linker output
|
# Linker output
|
||||||
*.ilk
|
*.ilk
|
||||||
*.map
|
*.map
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
#ifndef ACC_FATALS_H
|
#ifndef ACC_FATALS_H
|
||||||
#define 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_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);
|
||||||
|
@ -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_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,
|
||||||
T_PRINT, T_IF, T_ELSE, T_WHILE, T_FOR,
|
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);
|
void token_free(struct token *t);
|
||||||
struct token token_make_eof(void);
|
struct token token_make_eof(void);
|
||||||
|
@ -13,13 +13,19 @@ struct linklist {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct llist_node* llist_createnode(void *val);
|
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_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_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_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
|
#endif
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
#ifndef ACC_UTIL_MISC_H
|
#ifndef ACC_UTIL_MISC_H
|
||||||
#define 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);
|
char *strclone(const char *s);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
35
src/ast.c
35
src/ast.c
@ -6,10 +6,7 @@
|
|||||||
|
|
||||||
// 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(sizeof(struct ASTbinnode));
|
struct ASTbinnode *x = malloc_or_fail(sizeof(struct ASTbinnode), __FUNCTION__);
|
||||||
if (x == NULL) {
|
|
||||||
fail_malloc(__FUNCTION__);
|
|
||||||
}
|
|
||||||
|
|
||||||
x->op = op;
|
x->op = op;
|
||||||
x->left = left;
|
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
|
// Make an AST int literal node
|
||||||
struct ASTnode* ast_make_intlit(int val) {
|
struct ASTnode* ast_make_intlit(int val) {
|
||||||
struct ASTintnode *x = malloc(sizeof(struct ASTintnode));
|
struct ASTintnode *x = malloc_or_fail(sizeof(struct ASTintnode), __FUNCTION__);
|
||||||
if (x == NULL) {
|
|
||||||
fail_malloc(__FUNCTION__);
|
|
||||||
}
|
|
||||||
|
|
||||||
x->op = A_INTLIT;
|
x->op = A_INTLIT;
|
||||||
x->val = val;
|
x->val = val;
|
||||||
@ -31,10 +25,7 @@ struct ASTnode* ast_make_intlit(int val) {
|
|||||||
|
|
||||||
// Make an AST variable value node
|
// Make an AST variable value node
|
||||||
struct ASTnode* ast_make_var(int id) {
|
struct ASTnode* ast_make_var(int id) {
|
||||||
struct ASTvarnode *x = malloc(sizeof(struct ASTvarnode));
|
struct ASTvarnode *x = malloc_or_fail(sizeof(struct ASTvarnode), __FUNCTION__);
|
||||||
if (x == NULL) {
|
|
||||||
fail_malloc(__FUNCTION__);
|
|
||||||
}
|
|
||||||
|
|
||||||
x->op = A_VAR;
|
x->op = A_VAR;
|
||||||
x->id = id;
|
x->id = id;
|
||||||
@ -43,10 +34,7 @@ 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 *c) {
|
||||||
struct ASTunnode *x = malloc(sizeof(struct ASTunnode));
|
struct ASTunnode *x = malloc_or_fail(sizeof(struct ASTunnode), __FUNCTION__);
|
||||||
if (x == NULL) {
|
|
||||||
fail_malloc(__FUNCTION__);
|
|
||||||
}
|
|
||||||
|
|
||||||
x->op = op;
|
x->op = op;
|
||||||
x->c = c;
|
x->c = c;
|
||||||
@ -55,10 +43,7 @@ struct ASTnode* ast_make_unary(int op, struct ASTnode *c) {
|
|||||||
|
|
||||||
// Make a block ast node
|
// Make a block ast node
|
||||||
struct ASTnode* ast_make_block() {
|
struct ASTnode* ast_make_block() {
|
||||||
struct ASTblocknode *x = malloc(sizeof(struct ASTblocknode));
|
struct ASTblocknode *x = malloc_or_fail(sizeof(struct ASTblocknode), __FUNCTION__);
|
||||||
if (x == NULL) {
|
|
||||||
fail_malloc(__FUNCTION__);
|
|
||||||
}
|
|
||||||
|
|
||||||
x->op = A_BLOCK;
|
x->op = A_BLOCK;
|
||||||
llist_init(&x->st);
|
llist_init(&x->st);
|
||||||
@ -67,10 +52,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, int left, struct ASTnode *right) {
|
||||||
struct ASTassignnode *x = malloc(sizeof(struct ASTassignnode));
|
struct ASTassignnode *x = malloc_or_fail(sizeof(struct ASTassignnode), __FUNCTION__);
|
||||||
if (x == NULL) {
|
|
||||||
fail_malloc(__FUNCTION__);
|
|
||||||
}
|
|
||||||
|
|
||||||
x->op = op;
|
x->op = op;
|
||||||
x->left = left;
|
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
|
// Make a if statement ast node
|
||||||
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) {
|
||||||
struct ASTifnode *x = malloc(sizeof(struct ASTifnode));
|
struct ASTifnode *x = malloc_or_fail(sizeof(struct ASTifnode), __FUNCTION__);
|
||||||
if (x == NULL) {
|
|
||||||
fail_malloc(__FUNCTION__);
|
|
||||||
}
|
|
||||||
|
|
||||||
x->op = A_IF;
|
x->op = A_IF;
|
||||||
x->left = left;
|
x->left = left;
|
||||||
|
@ -53,7 +53,7 @@ static int cgcomp_i(int x, int y, char *op, char *ty) {
|
|||||||
int r1 = alloc_tag();
|
int r1 = alloc_tag();
|
||||||
fprintf(Outfile, "\t%%%d = icmp %s %s %%%d, %%%d\n", r1, op, ty, x, y);
|
fprintf(Outfile, "\t%%%d = icmp %s %s %%%d, %%%d\n", r1, op, ty, x, y);
|
||||||
int r2 = alloc_tag();
|
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);
|
fprintf(Outfile, "\t%%%d = zext i1 %%%d to %s\n", r2, r1, ty);
|
||||||
}
|
}
|
||||||
return (r2);
|
return (r2);
|
||||||
|
@ -7,6 +7,14 @@ void fail_malloc(const char *func_name) {
|
|||||||
exit(1);
|
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) {
|
void fail_ast_op(int op, const char *func_name) {
|
||||||
fprintf(stderr, "%s: unknown ast operator %d.\n", func_name, op);
|
fprintf(stderr, "%s: unknown ast operator %d.\n", func_name, op);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
71
src/parse.c
71
src/parse.c
@ -1,5 +1,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include "scan.h"
|
#include "scan.h"
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
#include "ast.h"
|
#include "ast.h"
|
||||||
@ -42,10 +44,10 @@ static int arithop(int t) {
|
|||||||
{T_GT, A_GT},
|
{T_GT, A_GT},
|
||||||
{T_GE, A_GE},
|
{T_GE, A_GE},
|
||||||
{T_ASSIGN, A_ASSIGN},
|
{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]) {
|
if (t == map[i][0]) {
|
||||||
return map[i][1];
|
return map[i][1];
|
||||||
}
|
}
|
||||||
@ -54,22 +56,21 @@ static int arithop(int t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// operator ssociativity direction
|
// operator ssociativity direction
|
||||||
// Return 0 if left to right, e.g. +
|
// Returns false if left to right, e.g. +
|
||||||
// 1 if right to left, e.g. =
|
// true if right to left, e.g. =
|
||||||
static int direction_rtl(int t) {
|
static bool direction_rtl(int t) {
|
||||||
switch(t) {
|
switch(t) {
|
||||||
case T_ASSIGN:
|
case T_ASSIGN:
|
||||||
return (1);
|
return (true);
|
||||||
default:
|
default:
|
||||||
return (0);
|
return (false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next token
|
// Next token
|
||||||
static void next(void) {
|
static void next(void) {
|
||||||
if (Tokens.head) {
|
if (Tokens.head) {
|
||||||
token_free(Tokens.head->val);
|
token_free(llist_popfront(&Tokens));
|
||||||
llist_popfront(&Tokens);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +79,8 @@ static struct token preview(int k) {
|
|||||||
if (Tokens.length <= k) {
|
if (Tokens.length <= k) {
|
||||||
return (token_make_eof());
|
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
|
// return current token from input stream
|
||||||
@ -117,12 +119,12 @@ static struct ASTnode* primary(void) {
|
|||||||
next();
|
next();
|
||||||
res = expression();
|
res = expression();
|
||||||
match(T_RP);
|
match(T_RP);
|
||||||
} else if (current().type == T_INTLIT) {
|
} else if (current().type == T_I32_LIT) {
|
||||||
res = ast_make_intlit(*((int*)current().val));
|
res = ast_make_intlit(*(int32_t*)current().val);
|
||||||
next();
|
next();
|
||||||
} else if (current().type == T_LONGLIT) {
|
} else if (current().type == T_I64_LIT) {
|
||||||
// todo
|
// todo
|
||||||
fprintf(stderr, "TOOD.\n");
|
fprintf(stderr, "TOOD: T_I64_LIT.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
} else if (current().type == T_INDENT) {
|
} else if (current().type == T_INDENT) {
|
||||||
int id = findglob((char*)current().val);
|
int id = findglob((char*)current().val);
|
||||||
@ -296,29 +298,24 @@ static struct ASTnode* for_statement(void) {
|
|||||||
|
|
||||||
// parse one statement
|
// parse one statement
|
||||||
static struct ASTnode* statement(void) {
|
static struct ASTnode* statement(void) {
|
||||||
if (current().type == T_SEMI) {
|
switch (current().type) {
|
||||||
return (NULL);
|
case T_SEMI:
|
||||||
}
|
return (NULL);
|
||||||
else if (current().type == T_PRINT) {
|
case T_PRINT:
|
||||||
return (print_statement());
|
return (print_statement());
|
||||||
}
|
case T_INT:
|
||||||
else if (current().type == T_INT) {
|
return (var_declaration());
|
||||||
return (var_declaration());
|
case T_IF:
|
||||||
}
|
return (if_statement());
|
||||||
else if (current().type == T_IF) {
|
case T_WHILE:
|
||||||
return (if_statement());
|
return (while_statement());
|
||||||
}
|
case T_FOR:
|
||||||
else if (current().type == T_WHILE) {
|
return (for_statement());
|
||||||
return (while_statement());
|
default:
|
||||||
}
|
skip_semi = 0;
|
||||||
else if (current().type == T_FOR) {
|
struct ASTnode* res = expression();
|
||||||
return (for_statement());
|
match(T_SEMI);
|
||||||
}
|
return (res);
|
||||||
else {
|
|
||||||
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 <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <limits.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
#include "fatals.h"
|
#include "fatals.h"
|
||||||
#include "util/misc.h"
|
#include "util/misc.h"
|
||||||
@ -11,18 +12,6 @@ int Line = 1;
|
|||||||
static int Preview;
|
static int Preview;
|
||||||
static FILE *Infile;
|
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
|
// preview one char, not getting it out from the stream
|
||||||
static int preview(void) {
|
static int preview(void) {
|
||||||
if (!Preview) {
|
if (!Preview) {
|
||||||
@ -43,9 +32,7 @@ static void next(void) {
|
|||||||
// Skip past input that we don't need to deal with,
|
// Skip past input that we don't need to deal with,
|
||||||
// i.e. whitespace, newlines.
|
// i.e. whitespace, newlines.
|
||||||
static void skip_whitespaces(void) {
|
static void skip_whitespaces(void) {
|
||||||
int c;
|
int c = preview();
|
||||||
|
|
||||||
c = preview();
|
|
||||||
while (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f') {
|
while (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f') {
|
||||||
next();
|
next();
|
||||||
c = preview();
|
c = preview();
|
||||||
@ -53,7 +40,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 scanint(struct token *t) {
|
static void scan_int(struct token *t) {
|
||||||
long long res = 0;
|
long long res = 0;
|
||||||
int c = preview();
|
int c = preview();
|
||||||
while ('0' <= c && c <= '9') {
|
while ('0' <= c && c <= '9') {
|
||||||
@ -62,40 +49,35 @@ static void scanint(struct token *t) {
|
|||||||
c = preview();
|
c = preview();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (INT_MIN <= res && res <= INT_MAX) {
|
if (INT32_MIN <= res && res <= INT32_MAX) {
|
||||||
t->type = T_INTLIT;
|
t->type = T_I32_LIT;
|
||||||
t->val = malloc(sizeof(int));
|
t->val = malloc_or_fail(sizeof(int32_t), __FUNCTION__);
|
||||||
if (t->val == NULL) {
|
*((int32_t *)t->val) = (int)res;
|
||||||
fail_malloc(__FUNCTION__);
|
|
||||||
}
|
|
||||||
*((int *)t->val) = (int)res;
|
|
||||||
} else {
|
} else {
|
||||||
t->type = T_LONGLIT;
|
t->type = T_I64_LIT;
|
||||||
t->val = malloc(sizeof(long long));
|
t->val = malloc_or_fail(sizeof(int64_t), __FUNCTION__);
|
||||||
if (t->val == NULL) {
|
*((int64_t *)t->val) = res;
|
||||||
fail_malloc(__FUNCTION__);
|
|
||||||
}
|
|
||||||
*((long long *)t->val) = res;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan an identifier from the input file and
|
// 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) {
|
static char* scan_indentifier(int *n) {
|
||||||
int sz = 128, len = 0;
|
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));
|
memset(res, 0, sz * sizeof(char));
|
||||||
|
|
||||||
int c = preview();
|
int c = preview();
|
||||||
while (isdigit(c) || isalpha(c) || c == '_') {
|
while (isdigit(c) || isalpha(c) || c == '_') {
|
||||||
if (len >= sz - 1) {
|
if (len >= sz - 1) {
|
||||||
sz *= 2;
|
sz *= 2;
|
||||||
char *old = res;
|
char *res = realloc(res, sz * sizeof(char));
|
||||||
res = malloc(sz * sizeof(char));
|
if (res == NULL) {
|
||||||
memcpy(res, old, len * sizeof(char));
|
fail_malloc(__FUNCTION__);
|
||||||
|
}
|
||||||
memset(res + len * sizeof(char), 0, (sz - len) * sizeof(char));
|
memset(res + len * sizeof(char), 0, (sz - len) * sizeof(char));
|
||||||
free(old);
|
|
||||||
}
|
}
|
||||||
res[len++] = c;
|
res[len++] = c;
|
||||||
next();
|
next();
|
||||||
@ -108,8 +90,9 @@ static char* scan_indentifier(int *n) {
|
|||||||
return (res);
|
return (res);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given a word from the input, scan if it is a keyword
|
// Given a word from the input, scan if it is a keyword.
|
||||||
static int scan_keyword(struct token *t, char *s) {
|
// Returns true if found keyword.
|
||||||
|
static bool scan_keyword(struct token *t, char *s) {
|
||||||
static const char *map_s[] = {
|
static const char *map_s[] = {
|
||||||
"print",
|
"print",
|
||||||
"int",
|
"int",
|
||||||
@ -137,15 +120,15 @@ static int scan_keyword(struct token *t, char *s) {
|
|||||||
for (int i = 0; map_s[i] != NULL; ++i) {
|
for (int i = 0; map_s[i] != NULL; ++i) {
|
||||||
if (strequal(map_s[i], s)) {
|
if (strequal(map_s[i], s)) {
|
||||||
t->type = map_t[i];
|
t->type = map_t[i];
|
||||||
return (1);
|
return (true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (0);
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan one char token
|
// Scan one char token
|
||||||
// Return 1 if found
|
// Return 1 if found
|
||||||
static int scan_1c(struct token *t) {
|
static bool scan_1c(struct token *t) {
|
||||||
static const int map[][2] = {
|
static const int map[][2] = {
|
||||||
{'+', T_PLUS},
|
{'+', T_PLUS},
|
||||||
{'-', T_MINUS},
|
{'-', T_MINUS},
|
||||||
@ -164,18 +147,15 @@ static int scan_1c(struct token *t) {
|
|||||||
if (map[i][0] == c) {
|
if (map[i][0] == c) {
|
||||||
t->type = map[i][1];
|
t->type = map[i][1];
|
||||||
next();
|
next();
|
||||||
return (1);
|
return (true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (0);
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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(sizeof(struct token));
|
struct token *t = malloc_or_fail(sizeof(struct token), __FUNCTION__);
|
||||||
if (t == NULL) {
|
|
||||||
fail_malloc(__FUNCTION__);
|
|
||||||
}
|
|
||||||
t->val = NULL;
|
t->val = NULL;
|
||||||
|
|
||||||
skip_whitespaces();
|
skip_whitespaces();
|
||||||
@ -204,8 +184,7 @@ static struct token* scan(void) {
|
|||||||
t->type = T_NE;
|
t->type = T_NE;
|
||||||
next();
|
next();
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Unrecognised character %c on line %d.\n", c, Line);
|
fail_char(c);
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
} else if (c == '<') {
|
} else if (c == '<') {
|
||||||
t->type = T_LT;
|
t->type = T_LT;
|
||||||
@ -226,7 +205,7 @@ static struct token* scan(void) {
|
|||||||
} else {
|
} else {
|
||||||
// If it's a digit, scan the integer literal value in
|
// If it's a digit, scan the integer literal value in
|
||||||
if (isdigit(c)) {
|
if (isdigit(c)) {
|
||||||
scanint(t);
|
scan_int(t);
|
||||||
} else if (isalpha(c) || c == '_') {
|
} else if (isalpha(c) || c == '_') {
|
||||||
t->val = scan_indentifier(NULL);
|
t->val = scan_indentifier(NULL);
|
||||||
if (scan_keyword(t, t->val)) {
|
if (scan_keyword(t, t->val)) {
|
||||||
|
12
src/token.c
12
src/token.c
@ -2,6 +2,18 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "token.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) {
|
void token_free(struct token *t) {
|
||||||
if (t->val) {
|
if (t->val) {
|
||||||
free(t->val);
|
free(t->val);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#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* llist_createnode(void *val) {
|
||||||
struct llist_node *res = malloc(sizeof(struct llist_node));
|
struct llist_node *res = malloc(sizeof(struct llist_node));
|
||||||
if (res == NULL) {
|
if (res == NULL) {
|
||||||
@ -13,6 +14,7 @@ struct llist_node* llist_createnode(void *val) {
|
|||||||
return (res);
|
return (res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Appends an element in the linklist.
|
||||||
void llist_pushback(struct linklist *l, void *val) {
|
void llist_pushback(struct linklist *l, void *val) {
|
||||||
l->length += 1;
|
l->length += 1;
|
||||||
if (!l->tail) {
|
if (!l->tail) {
|
||||||
@ -23,44 +25,51 @@ void llist_pushback(struct linklist *l, void *val) {
|
|||||||
l->tail = l->tail->nxt;
|
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) {
|
void llist_pushback_notnull(struct linklist *l, void *val) {
|
||||||
if (val) {
|
if (val) {
|
||||||
llist_pushback(l, val);
|
llist_pushback(l, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void* llist_get(struct linklist *l, int x) {
|
// Returns the _index_ thh element.
|
||||||
if (x >= l->length) {
|
void* llist_get(struct linklist *l, int index) {
|
||||||
|
if (index >= l->length) {
|
||||||
fprintf(stderr, "linklist out of range.\n");
|
fprintf(stderr, "linklist out of range.\n");
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct llist_node *p = l->head;
|
struct llist_node *p = l->head;
|
||||||
for (int i = 0; i < x; ++i) {
|
for (int i = 0; i < index; ++i) {
|
||||||
p = p->nxt;
|
p = p->nxt;
|
||||||
}
|
}
|
||||||
return (p->val);
|
return (p->val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void llist_set(struct linklist *l, int x, void *val) {
|
// Modify the _index_ thh element.
|
||||||
if (x >= l->length) {
|
void llist_set(struct linklist *l, int index, void *val) {
|
||||||
|
if (index >= l->length) {
|
||||||
fprintf(stderr, "linklist out of range.\n");
|
fprintf(stderr, "linklist out of range.\n");
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct llist_node *p = l->head;
|
struct llist_node *p = l->head;
|
||||||
for (int i = 0; i < x; ++i) {
|
for (int i = 0; i < index; ++i) {
|
||||||
p = p->nxt;
|
p = p->nxt;
|
||||||
}
|
}
|
||||||
p->val = val;
|
p->val = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Init a empty linklist.
|
||||||
void llist_init(struct linklist *l) {
|
void llist_init(struct linklist *l) {
|
||||||
l->length = 0;
|
l->length = 0;
|
||||||
l->head = NULL;
|
l->head = NULL;
|
||||||
l->tail = 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) {
|
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;
|
||||||
@ -72,6 +81,24 @@ 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.
|
||||||
|
// 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) {
|
||||||
if (index >= l->length) {
|
if (index >= l->length) {
|
||||||
llist_pushback(l, val);
|
llist_pushback(l, val);
|
||||||
@ -94,18 +121,46 @@ void llist_insert(struct linklist *l, int index, void *val) {
|
|||||||
p->nxt = x;
|
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) {
|
if (l->head == NULL) {
|
||||||
return;
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
l->length -= 1;
|
l->length -= 1;
|
||||||
|
void *res = l->head->val;
|
||||||
if (l->length == 0) {
|
if (l->length == 0) {
|
||||||
free(l->head);
|
free(l->head);
|
||||||
l->head = l->tail = NULL;
|
l->head = l->tail = NULL;
|
||||||
|
return (res);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct llist_node *p = l->head;
|
struct llist_node *p = l->head;
|
||||||
l->head = p->nxt;
|
l->head = p->nxt;
|
||||||
free(p);
|
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 <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include "util/misc.h"
|
||||||
|
|
||||||
// check if two string are the same
|
// check if two string are the same
|
||||||
int strequal(const char *s1, const char *s2) {
|
bool strequal(const char *s1, const char *s2) {
|
||||||
for (int i = 1; ; ++i) {
|
return (strcmp(s1, s2) == 0);
|
||||||
if (s1[i] != s2[i]) {
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s1[i] == '\0') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A impl of C23 strdup()
|
// A impl of C23 strdup()
|
||||||
char* strclone(char *s) {
|
// Clones the given string
|
||||||
|
char* strclone(const char *s) {
|
||||||
int n = strlen(s);
|
int n = strlen(s);
|
||||||
char *res = malloc(n + 1);
|
char *res = malloc(n + 1);
|
||||||
memcpy(res, s, n * sizeof(char));
|
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