leg
Signed-off-by: szdytom <szdytom@163.com>
This commit is contained in:
parent
440bc22ac7
commit
6950807161
1
.gitignore
vendored
1
.gitignore
vendored
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
# Debugger
|
# Debugger
|
||||||
*.pdb
|
*.pdb
|
||||||
|
out.txt
|
||||||
|
|
||||||
# Linker output
|
# Linker output
|
||||||
*.ilk
|
*.ilk
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#ifndef ACC_AST_H
|
#ifndef ACC_AST_H
|
||||||
#define ACC_AST_H
|
#define ACC_AST_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
#include "util/linklist.h"
|
#include "util/linklist.h"
|
||||||
|
|
||||||
// AST operation types
|
// AST operation types
|
||||||
@ -8,12 +9,21 @@ 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_INTLIT, A_VAR,
|
A_LIT, A_VAR,
|
||||||
A_BLOCK,
|
A_BLOCK,
|
||||||
A_PRINT, A_IF, A_WHILE,
|
A_PRINT, A_IF, A_WHILE,
|
||||||
A_SOUL // what?
|
A_SOUL // what?
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// value type
|
||||||
|
enum {
|
||||||
|
V_I32, V_I64, V_BOOL
|
||||||
|
};
|
||||||
|
|
||||||
|
struct value_type {
|
||||||
|
int vt; // base value type
|
||||||
|
};
|
||||||
|
|
||||||
// AST nodde types
|
// AST nodde types
|
||||||
enum {
|
enum {
|
||||||
N_BIN, N_UN, N_MULTI, N_LEAF, N_ASSIGN
|
N_BIN, N_UN, N_MULTI, N_LEAF, N_ASSIGN
|
||||||
@ -51,10 +61,11 @@ struct ASTblocknode {
|
|||||||
struct linklist st; // statements linklist
|
struct linklist st; // statements linklist
|
||||||
};
|
};
|
||||||
|
|
||||||
// AST int literal node
|
// AST literal node
|
||||||
struct ASTintnode {
|
struct ASTlitnode {
|
||||||
int op;
|
int op;
|
||||||
int val;
|
struct value_type type;
|
||||||
|
void *val;
|
||||||
};
|
};
|
||||||
|
|
||||||
// AST assign literal node
|
// AST assign literal node
|
||||||
@ -71,7 +82,8 @@ struct ASTvarnode {
|
|||||||
};
|
};
|
||||||
|
|
||||||
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 ASTnode* ast_make_intlit(int val);
|
struct ASTnode* ast_make_lit_i32(int32_t x);
|
||||||
|
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);
|
||||||
|
@ -11,10 +11,10 @@ void open_outputfile(char *filename);
|
|||||||
void cg_unload(void);
|
void cg_unload(void);
|
||||||
|
|
||||||
// cg_x64.c
|
// cg_x64.c
|
||||||
void cgx64_generate(struct ASTnode *rt);
|
//void cgx64_generate(struct ASTnode *rt);
|
||||||
|
|
||||||
// cg_llvm.c
|
// cg_llvm.c
|
||||||
void cgllvm_generate(struct ASTnode *rt);
|
//void cgllvm_generate(struct ASTnode *rt);
|
||||||
|
|
||||||
// cg_ast.c
|
// cg_ast.c
|
||||||
void cgast_generate(struct ASTnode *rt);
|
void cgast_generate(struct ASTnode *rt);
|
||||||
|
21
include/ir.h
Normal file
21
include/ir.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef ACC_ACIR_H
|
||||||
|
#define ACC_ACIR_H
|
||||||
|
|
||||||
|
// operations in the ACC IR(ACIR)
|
||||||
|
enum {
|
||||||
|
IR_ADD, IR_SUB, IR_MUL, IR_DIV,
|
||||||
|
IR_EQ, IR_NE, IR_LT, IR_GT, IR_LE, IR_GE,
|
||||||
|
IR_NEG,
|
||||||
|
IR_LIT,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IRinstruction {
|
||||||
|
int op;
|
||||||
|
union {
|
||||||
|
struct { IRinstruction *left, *right; };
|
||||||
|
int val;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -12,5 +12,6 @@ void array_pushback(struct array *a, void *val);
|
|||||||
void array_free(struct array *a);
|
void array_free(struct array *a);
|
||||||
void* array_get(struct array *a, int index);
|
void* array_get(struct array *a, int index);
|
||||||
void array_set(struct array *a, int index, void *val);
|
void array_set(struct array *a, int index, void *val);
|
||||||
|
void* array_popback(struct array *a);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
12
include/util/hashmap.h
Normal file
12
include/util/hashmap.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef ACC_UTIL_HASHMAP
|
||||||
|
#define ACC_UTIL_HASHMAP
|
||||||
|
|
||||||
|
struct hashmap {
|
||||||
|
int size;
|
||||||
|
int cap;
|
||||||
|
linklist *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
void hashmap_init();
|
||||||
|
|
||||||
|
#endif
|
76
src/ast.c
76
src/ast.c
@ -1,5 +1,5 @@
|
|||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include "ast.h"
|
#include "ast.h"
|
||||||
#include "fatals.h"
|
#include "fatals.h"
|
||||||
#include "util/linklist.h"
|
#include "util/linklist.h"
|
||||||
@ -14,12 +14,25 @@ struct ASTnode* ast_make_binary(int op, struct ASTnode *left, struct ASTnode *ri
|
|||||||
return ((struct ASTnode*)x);
|
return ((struct ASTnode*)x);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make an AST int literal node
|
// Make an AST int32 literal node
|
||||||
struct ASTnode* ast_make_intlit(int val) {
|
struct ASTnode* ast_make_lit_i32(int32_t v) {
|
||||||
struct ASTintnode *x = malloc_or_fail(sizeof(struct ASTintnode), __FUNCTION__);
|
struct ASTlitnode *x = malloc_or_fail(sizeof(struct ASTlitnode), __FUNCTION__);
|
||||||
|
|
||||||
x->op = A_INTLIT;
|
x->op = A_LIT;
|
||||||
x->val = val;
|
x->type.vt = V_I32;
|
||||||
|
x->val = malloc_or_fail(sizeof(int32_t), __FUNCTION__);
|
||||||
|
*(int64_t*)x->val = v;
|
||||||
|
return ((struct ASTnode*)x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make an AST int32 literal node
|
||||||
|
struct ASTnode* ast_make_lit_i64(int64_t v) {
|
||||||
|
struct ASTlitnode *x = malloc_or_fail(sizeof(struct ASTlitnode), __FUNCTION__);
|
||||||
|
|
||||||
|
x->op = A_LIT;
|
||||||
|
x->type.vt = V_I64;
|
||||||
|
x->val = malloc_or_fail(sizeof(int64_t), __FUNCTION__);
|
||||||
|
*(int64_t*)x->val = v;
|
||||||
return ((struct ASTnode*)x);
|
return ((struct ASTnode*)x);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,21 +87,20 @@ struct ASTnode* ast_make_if(struct ASTnode *left, struct ASTnode *right, struct
|
|||||||
// Translate ast operation type to ast node type
|
// Translate ast operation type to ast node type
|
||||||
int ast_type(int t) {
|
int ast_type(int t) {
|
||||||
switch (t) {
|
switch (t) {
|
||||||
case A_ADD: case A_SUB: case A_MUL: case A_DIV:
|
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_EQ: case A_NE: case A_GT: case A_LT: case A_GE: case A_LE:
|
||||||
case A_IF: case A_WHILE:
|
case A_IF: case A_WHILE:
|
||||||
return (N_BIN);
|
return (N_BIN);
|
||||||
case A_ASSIGN:
|
case A_ASSIGN:
|
||||||
return (N_ASSIGN);
|
return (N_ASSIGN);
|
||||||
case A_INTLIT: case A_VAR:
|
case A_LIT: case A_VAR:
|
||||||
return (N_LEAF);
|
return (N_LEAF);
|
||||||
case A_BLOCK:
|
case A_BLOCK:
|
||||||
return (N_MULTI);
|
return (N_MULTI);
|
||||||
case A_PRINT:
|
case A_PRINT:
|
||||||
return (N_UN);
|
return (N_UN);
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "%s: unknown operation type %d.\n", __FUNCTION__, t);
|
fail_ast_op(t, __FUNCTION__);
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,21 +110,24 @@ void ast_free(struct ASTnode *x) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nt = ast_type(x->op);
|
switch (ast_type(x->op)) {
|
||||||
if (nt == N_ASSIGN) {
|
case N_ASSIGN: {
|
||||||
struct ASTassignnode *t = (struct ASTassignnode*)x;
|
struct ASTassignnode *t = (struct ASTassignnode*)x;
|
||||||
ast_free(t->right);
|
ast_free(t->right);
|
||||||
} else if (nt == N_BIN) {
|
} break;
|
||||||
|
case N_BIN: {
|
||||||
struct ASTbinnode *t = (struct ASTbinnode*)x;
|
struct ASTbinnode *t = (struct ASTbinnode*)x;
|
||||||
ast_free(t->left);
|
ast_free(t->left);
|
||||||
ast_free(t->right);
|
ast_free(t->right);
|
||||||
if (x->op == A_IF) {
|
if (x->op == A_IF) {
|
||||||
ast_free(((struct ASTifnode*)x)->cond);
|
ast_free(((struct ASTifnode*)x)->cond);
|
||||||
}
|
}
|
||||||
} else if (nt == N_UN) {
|
} break;
|
||||||
|
case N_UN: {
|
||||||
struct ASTunnode *t = (struct ASTunnode*)x;
|
struct ASTunnode *t = (struct ASTunnode*)x;
|
||||||
ast_free(t->c);
|
ast_free(t->c);
|
||||||
} else if (nt == N_MULTI) {
|
} break;
|
||||||
|
case N_MULTI: {
|
||||||
struct ASTblocknode *t = (struct ASTblocknode*)x;
|
struct ASTblocknode *t = (struct ASTblocknode*)x;
|
||||||
struct llist_node *p = t->st.head;
|
struct llist_node *p = t->st.head;
|
||||||
while (p) {
|
while (p) {
|
||||||
@ -120,6 +135,15 @@ void ast_free(struct ASTnode *x) {
|
|||||||
p = p->nxt;
|
p = p->nxt;
|
||||||
}
|
}
|
||||||
llist_free(&t->st);
|
llist_free(&t->st);
|
||||||
|
} break;
|
||||||
|
case N_LEAF: {
|
||||||
|
struct ASTlitnode *t = (struct ASTlitnode*)x;
|
||||||
|
if (t->op == A_LIT) {
|
||||||
|
if (t->val) {
|
||||||
|
free(t->val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
free(x);
|
free(x);
|
||||||
}
|
}
|
||||||
|
4
src/cg.c
4
src/cg.c
@ -25,9 +25,9 @@ void cg_unload(void) {
|
|||||||
// generates code
|
// generates code
|
||||||
void cg_main(int target, struct ASTnode *rt) {
|
void cg_main(int target, struct ASTnode *rt) {
|
||||||
if (target == CG_X64) {
|
if (target == CG_X64) {
|
||||||
cgx64_generate(rt);
|
//cgx64_generate(rt);
|
||||||
} else if (target == CG_LLVM) {
|
} else if (target == CG_LLVM) {
|
||||||
cgllvm_generate(rt);
|
//cgllvm_generate(rt);
|
||||||
} else if (target == CG_AST) {
|
} else if (target == CG_AST) {
|
||||||
cgast_generate(rt);
|
cgast_generate(rt);
|
||||||
} else {
|
} else {
|
||||||
|
16
src/cg_ast.c
16
src/cg_ast.c
@ -32,10 +32,20 @@ static void cgenerate_dfs(struct ASTnode *x) {
|
|||||||
|
|
||||||
int nt = ast_type(x->op);
|
int nt = ast_type(x->op);
|
||||||
if (nt == N_LEAF) {
|
if (nt == N_LEAF) {
|
||||||
if (x->op == A_INTLIT) {
|
if (x->op == A_LIT) {
|
||||||
struct ASTintnode *t = (struct ASTintnode*)x;
|
struct ASTlitnode *t = (struct ASTlitnode*)x;
|
||||||
cgprint_tabs();
|
cgprint_tabs();
|
||||||
fprintf(Outfile, "--->INT %d.\n", t->val);
|
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) {
|
} else if (x->op == A_VAR) {
|
||||||
struct ASTvarnode *t = (struct ASTvarnode*)x;
|
struct ASTvarnode *t = (struct ASTvarnode*)x;
|
||||||
cgprint_tabs();
|
cgprint_tabs();
|
||||||
|
308
src/cg_x64.c
308
src/cg_x64.c
@ -1,308 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "cg.h"
|
|
||||||
#include "ast.h"
|
|
||||||
#include "symbol.h"
|
|
||||||
#include "fatals.h"
|
|
||||||
#include "util/array.h"
|
|
||||||
#include "util/linklist.h"
|
|
||||||
|
|
||||||
// List of available registers
|
|
||||||
// and their names
|
|
||||||
static const int reg_count = 4;
|
|
||||||
static char *reglist[4] = { "%r8", "%r9", "%r10", "%r11" };
|
|
||||||
static int usedreg[4];
|
|
||||||
|
|
||||||
// Get a label number for jump
|
|
||||||
static int alloc_label(void) {
|
|
||||||
static int id = 0;
|
|
||||||
return (id++);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set all registers free
|
|
||||||
static void free_all_reg(void) {
|
|
||||||
for (int i = 0; i < reg_count; ++i) {
|
|
||||||
usedreg[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate a new register to use or report "Out of registers"
|
|
||||||
static int alloc_reg(void) {
|
|
||||||
for (int i = 0; i < reg_count; ++i) {
|
|
||||||
if (!usedreg[i]) {
|
|
||||||
usedreg[i] = 1;
|
|
||||||
return (i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fprintf(stderr, "Out of registers.\n");
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return a register to the list of available registers.
|
|
||||||
// Check to see if it's not already there.
|
|
||||||
static void free_reg(int r) {
|
|
||||||
if (r == -1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!usedreg[r]) {
|
|
||||||
fprintf(stderr, "Error trying to free register %d: not allocated.\n", r);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
usedreg[r] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print out the assembly preamble
|
|
||||||
static void cgpreamble(void) {
|
|
||||||
free_all_reg();
|
|
||||||
fputs( "\t.text\n"
|
|
||||||
".LC0:\n"
|
|
||||||
"\t.string\t\"%d\\n\"\n"
|
|
||||||
"printint:\n"
|
|
||||||
"\tpushq\t%rbp\n"
|
|
||||||
"\tmovq\t%rsp, %rbp\n"
|
|
||||||
"\tsubq\t$16, %rsp\n"
|
|
||||||
"\tmovl\t%edi, -4(%rbp)\n"
|
|
||||||
"\tmovl\t-4(%rbp), %eax\n"
|
|
||||||
"\tmovl\t%eax, %esi\n"
|
|
||||||
"\tleaq .LC0(%rip), %rdi\n"
|
|
||||||
"\tmovl $0, %eax\n"
|
|
||||||
"\tcall printf@PLT\n"
|
|
||||||
"\tnop\n"
|
|
||||||
"\tleave\n"
|
|
||||||
"\tret\n"
|
|
||||||
"\n"
|
|
||||||
"\t.globl\tmain\n"
|
|
||||||
"main:\n"
|
|
||||||
"\tpushq\t%rbp\n"
|
|
||||||
"\tmovq %rsp, %rbp\n", Outfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print out the assembly postamble
|
|
||||||
static void cgpostamble(void) {
|
|
||||||
fputs( "\tmovl $0, %eax\n"
|
|
||||||
"\tpopq %rbp\n"
|
|
||||||
"\tret\n", Outfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load an integer literal to a register.
|
|
||||||
// Return the id of the register
|
|
||||||
static int cgload_int(int val) {
|
|
||||||
int r = alloc_reg();
|
|
||||||
fprintf(Outfile, "\tmovl\t$%d, %sd\n", val, reglist[r]);
|
|
||||||
return (r);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add two registers together and return
|
|
||||||
// the number of the register with the result
|
|
||||||
static int cgadd(int r1, int r2) {
|
|
||||||
fprintf(Outfile, "\taddq\t%s, %s\n", reglist[r1], reglist[r2]);
|
|
||||||
free_reg(r1);
|
|
||||||
return (r2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subtract the second register from the first and
|
|
||||||
// return the number of the register with the result
|
|
||||||
static int cgsub(int r1, int r2) {
|
|
||||||
fprintf(Outfile, "\tsubq\t%s, %s\n", reglist[r2], reglist[r1]);
|
|
||||||
free_reg(r2);
|
|
||||||
return (r1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Multiply two registers together and return
|
|
||||||
// the number of the register with the result
|
|
||||||
static int cgmul(int r1, int r2) {
|
|
||||||
fprintf(Outfile, "\timulq\t%s, %s\n", reglist[r1], reglist[r2]);
|
|
||||||
free_reg(r1);
|
|
||||||
return (r2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Divide the first register by the second and
|
|
||||||
// return the number of the register with the result
|
|
||||||
static int cgdiv(int r1, int r2) {
|
|
||||||
fprintf(Outfile, "\tmovq\t%s,%%rax\n", reglist[r1]);
|
|
||||||
fprintf(Outfile, "\tcqo\n");
|
|
||||||
fprintf(Outfile, "\tidivq\t%s\n", reglist[r2]);
|
|
||||||
fprintf(Outfile, "\tmovq\t%%rax,%s\n", reglist[r1]);
|
|
||||||
free_reg(r2);
|
|
||||||
return (r1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call printint() with the given register
|
|
||||||
static void cgprint(int r) {
|
|
||||||
fprintf(Outfile, "\tmovq\t%s, %%rdi\n", reglist[r]);
|
|
||||||
fprintf(Outfile, "\tcall\tprintint\n");
|
|
||||||
free_reg(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load a global variable into a register
|
|
||||||
static int cgload_glob(char *name) {
|
|
||||||
int r = alloc_reg();
|
|
||||||
fprintf(Outfile, "\tmovq\t%s(%%rip), %s\n", name, reglist[r]);
|
|
||||||
return (r);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store a register's value into a variable
|
|
||||||
static int cgstore_glob(int r, char *name) {
|
|
||||||
fprintf(Outfile, "\tmovq\t%s, %s(%%rip)\n", reglist[r], name);
|
|
||||||
return (r);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compare two registers.
|
|
||||||
static int cgcompare(int r1, int r2, int op) {
|
|
||||||
static const int map_s[] = { A_EQ, A_NE, A_LT, A_LE, A_GT, A_GE, 0};
|
|
||||||
static const char *map_t[] = { "sete", "setne","setl", "setle","setg", "setge",NULL};
|
|
||||||
int how = -1;
|
|
||||||
for (int i = 0; map_t[i] != NULL; ++i) {
|
|
||||||
if (map_s[i] == op) {
|
|
||||||
how = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (how == -1) {
|
|
||||||
fprintf(stderr, "%s: unknown compare operator %d.\n", __FUNCTION__, op);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(Outfile, "\tcmpq\t%s, %s\n", reglist[r2], reglist[r1]);
|
|
||||||
fprintf(Outfile, "\t%s\t%sb\n", map_t[how], reglist[r2]);
|
|
||||||
fprintf(Outfile, "\tandq\t$255,%s\n", reglist[r2]);
|
|
||||||
free_reg(r1);
|
|
||||||
return (r2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Jump to label when condition register is false(0).
|
|
||||||
static void cgjmp_condfalse(int Lt, int x) {
|
|
||||||
fprintf(Outfile, "\tcmpq\t$0, %s\n", reglist[x]);
|
|
||||||
fprintf(Outfile, "\tje\t.L%d\n", Lt);
|
|
||||||
free_reg(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Jump to label no matter what.
|
|
||||||
static void cgjmp_always(int Lt) {
|
|
||||||
fprintf(Outfile, "\tjmp\t.L%d\n", Lt);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print label to Outfile
|
|
||||||
static void cgprint_label(int Lt) {
|
|
||||||
fprintf(Outfile, ".L%d:\n", Lt);
|
|
||||||
}
|
|
||||||
|
|
||||||
// init a global variable
|
|
||||||
static void cginit_glob(char *name) {
|
|
||||||
fprintf(Outfile, "\t.comm\t%s,8,8\n", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Given a AST('s root)
|
|
||||||
// Generate ASM code.
|
|
||||||
// Return value register id.
|
|
||||||
static int cgenerate_ast(struct ASTnode *rt) {
|
|
||||||
int nt = ast_type(rt->op);
|
|
||||||
|
|
||||||
if (nt == N_LEAF) {
|
|
||||||
if (rt->op == A_INTLIT) {
|
|
||||||
struct ASTintnode *x = (struct ASTintnode*)rt;
|
|
||||||
return (cgload_int(x->val));
|
|
||||||
} else if (rt->op == A_VAR) {
|
|
||||||
struct ASTvarnode *x = (struct ASTvarnode*)rt;
|
|
||||||
return (cgload_glob(array_get(&Gsym, x->id)));
|
|
||||||
} else {
|
|
||||||
fail_ast_op(rt->op, __FUNCTION__);
|
|
||||||
}
|
|
||||||
} else if (nt == N_BIN) {
|
|
||||||
if (rt->op == A_IF) {
|
|
||||||
struct ASTifnode *x = (struct ASTifnode*)rt;
|
|
||||||
int Lelse = alloc_label();
|
|
||||||
int Lend = alloc_label();
|
|
||||||
int condv = cgenerate_ast(x->cond);
|
|
||||||
|
|
||||||
cgjmp_condfalse(Lelse, condv);
|
|
||||||
free_reg(cgenerate_ast(x->left));
|
|
||||||
cgjmp_always(Lend);
|
|
||||||
|
|
||||||
cgprint_label(Lelse);
|
|
||||||
free_reg(cgenerate_ast(x->right));
|
|
||||||
|
|
||||||
cgprint_label(Lend);
|
|
||||||
return (-1);
|
|
||||||
} else if (rt->op == A_WHILE) {
|
|
||||||
struct ASTbinnode *x = (struct ASTbinnode*)rt;
|
|
||||||
int Lstart = alloc_label();
|
|
||||||
int Lend = alloc_label();
|
|
||||||
|
|
||||||
cgprint_label(Lstart);
|
|
||||||
int condv = cgenerate_ast(x->left);
|
|
||||||
cgjmp_condfalse(Lend, condv);
|
|
||||||
free_reg(cgenerate_ast(x->right));
|
|
||||||
cgjmp_always(Lstart);
|
|
||||||
|
|
||||||
cgprint_label(Lend);
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ASTbinnode *x = (struct ASTbinnode*)rt;
|
|
||||||
int lv = cgenerate_ast(x->left);
|
|
||||||
int rv = cgenerate_ast(x->right);
|
|
||||||
|
|
||||||
if (rt->op == A_ADD) {
|
|
||||||
return (cgadd(lv, rv));
|
|
||||||
} else if (rt->op == A_SUB) {
|
|
||||||
return (cgsub(lv, rv));
|
|
||||||
} else if (rt->op == A_MUL) {
|
|
||||||
return (cgmul(lv, rv));
|
|
||||||
} else if (rt->op == A_DIV) {
|
|
||||||
return (cgdiv(lv, rv));
|
|
||||||
} else if (A_EQ <= rt->op && rt->op <= A_GE) {
|
|
||||||
// a compare operator
|
|
||||||
return (cgcompare(lv, rv, rt->op));
|
|
||||||
} else {
|
|
||||||
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);
|
|
||||||
} else {
|
|
||||||
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(cv, array_get(&Gsym, x->left)));
|
|
||||||
} else {
|
|
||||||
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);
|
|
||||||
if (p->nxt) {
|
|
||||||
free_reg(val);
|
|
||||||
}
|
|
||||||
p = p->nxt;
|
|
||||||
}
|
|
||||||
return val;
|
|
||||||
} else {
|
|
||||||
fail_ast_op(rt->op, __FUNCTION__);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// generates code
|
|
||||||
void cgx64_generate(struct ASTnode *rt) {
|
|
||||||
for (int i = 0; i < Gsym.length; ++i) {
|
|
||||||
cginit_glob(array_get(&Gsym, i));
|
|
||||||
}
|
|
||||||
|
|
||||||
cgpreamble();
|
|
||||||
free_reg(cgenerate_ast(rt));
|
|
||||||
cgpostamble();
|
|
||||||
}
|
|
62
src/parse.c
62
src/parse.c
@ -75,16 +75,18 @@ 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) {
|
||||||
return (token_make_eof());
|
static struct token token_eof;
|
||||||
|
token_eof = token_make_eof();
|
||||||
|
return (&token_eof);
|
||||||
}
|
}
|
||||||
struct token* res = llist_get(&Tokens, k);
|
struct token* res = llist_get(&Tokens, k);
|
||||||
return (*res);
|
return (res);
|
||||||
}
|
}
|
||||||
|
|
||||||
// return current token from input stream
|
// return current token from input stream
|
||||||
static struct token current(void) {
|
static struct token* current(void) {
|
||||||
return (preview(0));
|
return (preview(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,17 +94,17 @@ static struct token current(void) {
|
|||||||
static void match(int t) {
|
static void match(int t) {
|
||||||
if (t == T_SEMI && skip_semi) {
|
if (t == T_SEMI && skip_semi) {
|
||||||
skip_semi = 0;
|
skip_semi = 0;
|
||||||
} else if (current().type == t) {
|
} 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]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 check(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]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,22 +116,20 @@ static struct ASTnode* expression(void);
|
|||||||
static struct ASTnode* primary(void) {
|
static struct ASTnode* primary(void) {
|
||||||
struct ASTnode *res;
|
struct ASTnode *res;
|
||||||
|
|
||||||
if (current().type == T_LP) {
|
if (current()->type == T_LP) {
|
||||||
// ( expr ) considered as primary
|
// ( expr ) considered as primary
|
||||||
next();
|
next();
|
||||||
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_intlit(*(int32_t*)current().val);
|
res = ast_make_lit_i32(*(int32_t*)current()->val);
|
||||||
next();
|
next();
|
||||||
} else if (current().type == T_I64_LIT) {
|
} else if (current()->type == T_I64_LIT) {
|
||||||
// todo
|
res = ast_make_lit_i64(*(int64_t*)current()->val);
|
||||||
fprintf(stderr, "TOOD: T_I64_LIT.\n");
|
} else if (current()->type == T_INDENT) {
|
||||||
exit(1);
|
int id = findglob((char*)current()->val);
|
||||||
} else if (current().type == T_INDENT) {
|
|
||||||
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);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
@ -151,7 +151,7 @@ static struct ASTnode* binexpr(int precedence) {
|
|||||||
struct ASTnode *left, *right;
|
struct ASTnode *left, *right;
|
||||||
|
|
||||||
left = primary();
|
left = primary();
|
||||||
int tt = current().type;
|
int tt = current()->type;
|
||||||
if (!is_binop(tt)) {
|
if (!is_binop(tt)) {
|
||||||
return (left);
|
return (left);
|
||||||
}
|
}
|
||||||
@ -168,7 +168,7 @@ static struct ASTnode* binexpr(int precedence) {
|
|||||||
left = ast_make_binary(arithop(tt), left, right); // join right into left
|
left = ast_make_binary(arithop(tt), left, right); // join right into left
|
||||||
}
|
}
|
||||||
|
|
||||||
tt = current().type;
|
tt = current()->type;
|
||||||
if (!is_binop(tt)) {
|
if (!is_binop(tt)) {
|
||||||
return (left);
|
return (left);
|
||||||
}
|
}
|
||||||
@ -180,18 +180,18 @@ 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* parse_block(void) {
|
||||||
match(T_LB);
|
match(T_LB);
|
||||||
if (current().type == T_RB) {
|
if (current()->type == T_RB) {
|
||||||
next();
|
next();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ASTblocknode* res = (struct ASTblocknode*)ast_make_block();
|
struct ASTblocknode* res = (struct ASTblocknode*)ast_make_block();
|
||||||
while (current().type != T_RB) {
|
while (current()->type != T_RB) {
|
||||||
struct ASTnode *x;
|
struct ASTnode *x;
|
||||||
x = statement();
|
x = statement();
|
||||||
llist_pushback_notnull(&res->st, x);
|
llist_pushback_notnull(&res->st, x);
|
||||||
|
|
||||||
if (current().type == T_EOF) {
|
if (current()->type == T_EOF) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -202,7 +202,7 @@ static struct ASTnode* parse_block(void) {
|
|||||||
|
|
||||||
// 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_LB) {
|
||||||
return (parse_block());
|
return (parse_block());
|
||||||
}
|
}
|
||||||
return (binexpr(0));
|
return (binexpr(0));
|
||||||
@ -220,10 +220,10 @@ static struct ASTnode* print_statement(void) {
|
|||||||
static struct ASTnode* var_declaration(void) {
|
static struct ASTnode* var_declaration(void) {
|
||||||
match(T_INT);
|
match(T_INT);
|
||||||
check(T_INDENT);
|
check(T_INDENT);
|
||||||
if (findglob((char*)current().val) != -1) {
|
if (findglob((char*)current()->val) != -1) {
|
||||||
fail_ce("variable declared twice.");
|
fail_ce("variable declared twice.");
|
||||||
}
|
}
|
||||||
addglob((char*)current().val);
|
addglob((char*)current()->val);
|
||||||
next();
|
next();
|
||||||
match(T_SEMI);
|
match(T_SEMI);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
@ -237,7 +237,7 @@ static struct ASTnode* if_statement(void) {
|
|||||||
match(T_RP); // )
|
match(T_RP); // )
|
||||||
struct ASTnode* then = statement();
|
struct ASTnode* then = statement();
|
||||||
struct ASTnode* else_then;
|
struct ASTnode* else_then;
|
||||||
if (current().type == T_ELSE) {
|
if (current()->type == T_ELSE) {
|
||||||
next(); // else
|
next(); // else
|
||||||
else_then = statement();
|
else_then = statement();
|
||||||
} else {
|
} else {
|
||||||
@ -263,15 +263,15 @@ static struct ASTnode* for_statement(void) {
|
|||||||
struct ASTnode *init = statement();
|
struct ASTnode *init = statement();
|
||||||
|
|
||||||
struct ASTnode *cond;
|
struct ASTnode *cond;
|
||||||
if (current().type != T_SEMI) {
|
if (current()->type != T_SEMI) {
|
||||||
cond = expression();
|
cond = expression();
|
||||||
} else {
|
} else {
|
||||||
cond = ast_make_intlit(1);
|
cond = ast_make_lit_i32(1);
|
||||||
}
|
}
|
||||||
next(); // skip the ;
|
next(); // skip the ;
|
||||||
|
|
||||||
struct ASTnode *inc;
|
struct ASTnode *inc;
|
||||||
if (current().type != T_RP) {
|
if (current()->type != T_RP) {
|
||||||
inc = expression();
|
inc = expression();
|
||||||
} else {
|
} else {
|
||||||
inc = NULL;
|
inc = NULL;
|
||||||
@ -298,7 +298,7 @@ static struct ASTnode* for_statement(void) {
|
|||||||
|
|
||||||
// parse one statement
|
// parse one statement
|
||||||
static struct ASTnode* statement(void) {
|
static struct ASTnode* statement(void) {
|
||||||
switch (current().type) {
|
switch (current()->type) {
|
||||||
case T_SEMI:
|
case T_SEMI:
|
||||||
return (NULL);
|
return (NULL);
|
||||||
case T_PRINT:
|
case T_PRINT:
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "util/array.h"
|
#include "util/array.h"
|
||||||
|
#include "fatals.h"
|
||||||
|
|
||||||
void array_init(struct array *a) {
|
void array_init(struct array *a) {
|
||||||
a->length = 0;
|
a->length = 0;
|
||||||
@ -18,15 +19,16 @@ void array_free(struct array *a) {
|
|||||||
|
|
||||||
static void array_enlarge(struct array *a) {
|
static void array_enlarge(struct array *a) {
|
||||||
if (a->cap == 0) {
|
if (a->cap == 0) {
|
||||||
a->cap = 128;
|
a->cap = 1;
|
||||||
|
} else if (a->cap <= 256) {
|
||||||
|
a->cap *= 8;
|
||||||
} else {
|
} else {
|
||||||
a->cap *= 2;
|
a->cap *= 1.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
void **old = a->begin;
|
a->begin = realloc(a->begin, a->cap);
|
||||||
a->begin = malloc(sizeof(void*) * a->cap);
|
if (a->begin == NULL) {
|
||||||
if (old) {
|
fail_malloc(__FUNCTION__);
|
||||||
memcpy(a->begin, old, a->length * sizeof(void*));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,3 +58,12 @@ void array_set(struct array *a, int index, void *val) {
|
|||||||
|
|
||||||
a->begin[index] = val;
|
a->begin[index] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* array_popback(struct array *a) {
|
||||||
|
if (a->length == 0) {
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
a->length -= 1;
|
||||||
|
return (a->begin[a->length]);
|
||||||
|
}
|
6
tests/input08
Normal file
6
tests/input08
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
long a = 5;
|
||||||
|
long b = a + 5;
|
||||||
|
int c = b - 1;
|
||||||
|
print c;
|
||||||
|
}
|
1
tests/input08.ans
Normal file
1
tests/input08.ans
Normal file
@ -0,0 +1 @@
|
|||||||
|
9
|
Loading…
x
Reference in New Issue
Block a user