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
|
||||
*.pdb
|
||||
out.txt
|
||||
|
||||
# Linker output
|
||||
*.ilk
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifndef ACC_AST_H
|
||||
#define ACC_AST_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "util/linklist.h"
|
||||
|
||||
// AST operation types
|
||||
@ -8,12 +9,21 @@ enum {
|
||||
A_ASSIGN,
|
||||
A_ADD, A_SUB, A_MUL, A_DIV,
|
||||
A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE,
|
||||
A_INTLIT, A_VAR,
|
||||
A_LIT, A_VAR,
|
||||
A_BLOCK,
|
||||
A_PRINT, A_IF, A_WHILE,
|
||||
A_SOUL // what?
|
||||
};
|
||||
|
||||
// value type
|
||||
enum {
|
||||
V_I32, V_I64, V_BOOL
|
||||
};
|
||||
|
||||
struct value_type {
|
||||
int vt; // base value type
|
||||
};
|
||||
|
||||
// AST nodde types
|
||||
enum {
|
||||
N_BIN, N_UN, N_MULTI, N_LEAF, N_ASSIGN
|
||||
@ -51,10 +61,11 @@ struct ASTblocknode {
|
||||
struct linklist st; // statements linklist
|
||||
};
|
||||
|
||||
// AST int literal node
|
||||
struct ASTintnode {
|
||||
// AST literal node
|
||||
struct ASTlitnode {
|
||||
int op;
|
||||
int val;
|
||||
struct value_type type;
|
||||
void *val;
|
||||
};
|
||||
|
||||
// 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_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_block();
|
||||
struct ASTnode* ast_make_var(int id);
|
||||
|
@ -11,10 +11,10 @@ void open_outputfile(char *filename);
|
||||
void cg_unload(void);
|
||||
|
||||
// cg_x64.c
|
||||
void cgx64_generate(struct ASTnode *rt);
|
||||
//void cgx64_generate(struct ASTnode *rt);
|
||||
|
||||
// cg_llvm.c
|
||||
void cgllvm_generate(struct ASTnode *rt);
|
||||
//void cgllvm_generate(struct ASTnode *rt);
|
||||
|
||||
// cg_ast.c
|
||||
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_get(struct array *a, int index);
|
||||
void array_set(struct array *a, int index, void *val);
|
||||
void* array_popback(struct array *a);
|
||||
|
||||
#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
|
52
src/ast.c
52
src/ast.c
@ -1,5 +1,5 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "ast.h"
|
||||
#include "fatals.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);
|
||||
}
|
||||
|
||||
// Make an AST int literal node
|
||||
struct ASTnode* ast_make_intlit(int val) {
|
||||
struct ASTintnode *x = malloc_or_fail(sizeof(struct ASTintnode), __FUNCTION__);
|
||||
// Make an AST int32 literal node
|
||||
struct ASTnode* ast_make_lit_i32(int32_t v) {
|
||||
struct ASTlitnode *x = malloc_or_fail(sizeof(struct ASTlitnode), __FUNCTION__);
|
||||
|
||||
x->op = A_INTLIT;
|
||||
x->val = val;
|
||||
x->op = A_LIT;
|
||||
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);
|
||||
}
|
||||
|
||||
@ -80,15 +93,14 @@ int ast_type(int t) {
|
||||
return (N_BIN);
|
||||
case A_ASSIGN:
|
||||
return (N_ASSIGN);
|
||||
case A_INTLIT: case A_VAR:
|
||||
case A_LIT: case A_VAR:
|
||||
return (N_LEAF);
|
||||
case A_BLOCK:
|
||||
return (N_MULTI);
|
||||
case A_PRINT:
|
||||
return (N_UN);
|
||||
default:
|
||||
fprintf(stderr, "%s: unknown operation type %d.\n", __FUNCTION__, t);
|
||||
exit(1);
|
||||
fail_ast_op(t, __FUNCTION__);
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,21 +110,24 @@ void ast_free(struct ASTnode *x) {
|
||||
return;
|
||||
}
|
||||
|
||||
int nt = ast_type(x->op);
|
||||
if (nt == N_ASSIGN) {
|
||||
switch (ast_type(x->op)) {
|
||||
case N_ASSIGN: {
|
||||
struct ASTassignnode *t = (struct ASTassignnode*)x;
|
||||
ast_free(t->right);
|
||||
} else if (nt == N_BIN) {
|
||||
} 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);
|
||||
}
|
||||
} else if (nt == N_UN) {
|
||||
} break;
|
||||
case N_UN: {
|
||||
struct ASTunnode *t = (struct ASTunnode*)x;
|
||||
ast_free(t->c);
|
||||
} else if (nt == N_MULTI) {
|
||||
} break;
|
||||
case N_MULTI: {
|
||||
struct ASTblocknode *t = (struct ASTblocknode*)x;
|
||||
struct llist_node *p = t->st.head;
|
||||
while (p) {
|
||||
@ -120,6 +135,15 @@ void ast_free(struct ASTnode *x) {
|
||||
p = p->nxt;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
4
src/cg.c
4
src/cg.c
@ -25,9 +25,9 @@ void cg_unload(void) {
|
||||
// generates code
|
||||
void cg_main(int target, struct ASTnode *rt) {
|
||||
if (target == CG_X64) {
|
||||
cgx64_generate(rt);
|
||||
//cgx64_generate(rt);
|
||||
} else if (target == CG_LLVM) {
|
||||
cgllvm_generate(rt);
|
||||
//cgllvm_generate(rt);
|
||||
} else if (target == CG_AST) {
|
||||
cgast_generate(rt);
|
||||
} 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);
|
||||
if (nt == N_LEAF) {
|
||||
if (x->op == A_INTLIT) {
|
||||
struct ASTintnode *t = (struct ASTintnode*)x;
|
||||
if (x->op == A_LIT) {
|
||||
struct ASTlitnode *t = (struct ASTlitnode*)x;
|
||||
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) {
|
||||
struct ASTvarnode *t = (struct ASTvarnode*)x;
|
||||
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
|
||||
static struct token preview(int k) {
|
||||
static struct token* preview(int 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);
|
||||
return (*res);
|
||||
return (res);
|
||||
}
|
||||
|
||||
// return current token from input stream
|
||||
static struct token current(void) {
|
||||
static struct token* current(void) {
|
||||
return (preview(0));
|
||||
}
|
||||
|
||||
@ -92,17 +94,17 @@ static struct token current(void) {
|
||||
static void match(int t) {
|
||||
if (t == T_SEMI && skip_semi) {
|
||||
skip_semi = 0;
|
||||
} else if (current().type == t) {
|
||||
} else if (current()->type == t) {
|
||||
next();
|
||||
} 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.
|
||||
static void check(int t) {
|
||||
if (current().type != t) {
|
||||
fail_ce_expect(token_typename[current().type], token_typename[t]);
|
||||
if (current()->type != 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) {
|
||||
struct ASTnode *res;
|
||||
|
||||
if (current().type == T_LP) {
|
||||
if (current()->type == T_LP) {
|
||||
// ( expr ) considered as primary
|
||||
next();
|
||||
res = expression();
|
||||
match(T_RP);
|
||||
} else if (current().type == T_I32_LIT) {
|
||||
res = ast_make_intlit(*(int32_t*)current().val);
|
||||
} else if (current()->type == T_I32_LIT) {
|
||||
res = ast_make_lit_i32(*(int32_t*)current()->val);
|
||||
next();
|
||||
} else if (current().type == T_I64_LIT) {
|
||||
// todo
|
||||
fprintf(stderr, "TOOD: T_I64_LIT.\n");
|
||||
exit(1);
|
||||
} else if (current().type == T_INDENT) {
|
||||
int id = findglob((char*)current().val);
|
||||
} else if (current()->type == T_I64_LIT) {
|
||||
res = ast_make_lit_i64(*(int64_t*)current()->val);
|
||||
} else if (current()->type == T_INDENT) {
|
||||
int id = findglob((char*)current()->val);
|
||||
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);
|
||||
}
|
||||
next();
|
||||
@ -151,7 +151,7 @@ static struct ASTnode* binexpr(int precedence) {
|
||||
struct ASTnode *left, *right;
|
||||
|
||||
left = primary();
|
||||
int tt = current().type;
|
||||
int tt = current()->type;
|
||||
if (!is_binop(tt)) {
|
||||
return (left);
|
||||
}
|
||||
@ -168,7 +168,7 @@ static struct ASTnode* binexpr(int precedence) {
|
||||
left = ast_make_binary(arithop(tt), left, right); // join right into left
|
||||
}
|
||||
|
||||
tt = current().type;
|
||||
tt = current()->type;
|
||||
if (!is_binop(tt)) {
|
||||
return (left);
|
||||
}
|
||||
@ -180,18 +180,18 @@ static struct ASTnode* binexpr(int precedence) {
|
||||
// parse one block of code, e.g. { a; b; }
|
||||
static struct ASTnode* parse_block(void) {
|
||||
match(T_LB);
|
||||
if (current().type == T_RB) {
|
||||
if (current()->type == T_RB) {
|
||||
next();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ASTblocknode* res = (struct ASTblocknode*)ast_make_block();
|
||||
while (current().type != T_RB) {
|
||||
while (current()->type != T_RB) {
|
||||
struct ASTnode *x;
|
||||
x = statement();
|
||||
llist_pushback_notnull(&res->st, x);
|
||||
|
||||
if (current().type == T_EOF) {
|
||||
if (current()->type == T_EOF) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -202,7 +202,7 @@ static struct ASTnode* parse_block(void) {
|
||||
|
||||
// parse an expression
|
||||
static struct ASTnode* expression(void) {
|
||||
if (current().type == T_LB) {
|
||||
if (current()->type == T_LB) {
|
||||
return (parse_block());
|
||||
}
|
||||
return (binexpr(0));
|
||||
@ -220,10 +220,10 @@ static struct ASTnode* print_statement(void) {
|
||||
static struct ASTnode* var_declaration(void) {
|
||||
match(T_INT);
|
||||
check(T_INDENT);
|
||||
if (findglob((char*)current().val) != -1) {
|
||||
if (findglob((char*)current()->val) != -1) {
|
||||
fail_ce("variable declared twice.");
|
||||
}
|
||||
addglob((char*)current().val);
|
||||
addglob((char*)current()->val);
|
||||
next();
|
||||
match(T_SEMI);
|
||||
return (NULL);
|
||||
@ -237,7 +237,7 @@ static struct ASTnode* if_statement(void) {
|
||||
match(T_RP); // )
|
||||
struct ASTnode* then = statement();
|
||||
struct ASTnode* else_then;
|
||||
if (current().type == T_ELSE) {
|
||||
if (current()->type == T_ELSE) {
|
||||
next(); // else
|
||||
else_then = statement();
|
||||
} else {
|
||||
@ -263,15 +263,15 @@ static struct ASTnode* for_statement(void) {
|
||||
struct ASTnode *init = statement();
|
||||
|
||||
struct ASTnode *cond;
|
||||
if (current().type != T_SEMI) {
|
||||
if (current()->type != T_SEMI) {
|
||||
cond = expression();
|
||||
} else {
|
||||
cond = ast_make_intlit(1);
|
||||
cond = ast_make_lit_i32(1);
|
||||
}
|
||||
next(); // skip the ;
|
||||
|
||||
struct ASTnode *inc;
|
||||
if (current().type != T_RP) {
|
||||
if (current()->type != T_RP) {
|
||||
inc = expression();
|
||||
} else {
|
||||
inc = NULL;
|
||||
@ -298,7 +298,7 @@ static struct ASTnode* for_statement(void) {
|
||||
|
||||
// parse one statement
|
||||
static struct ASTnode* statement(void) {
|
||||
switch (current().type) {
|
||||
switch (current()->type) {
|
||||
case T_SEMI:
|
||||
return (NULL);
|
||||
case T_PRINT:
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "util/array.h"
|
||||
#include "fatals.h"
|
||||
|
||||
void array_init(struct array *a) {
|
||||
a->length = 0;
|
||||
@ -18,15 +19,16 @@ void array_free(struct array *a) {
|
||||
|
||||
static void array_enlarge(struct array *a) {
|
||||
if (a->cap == 0) {
|
||||
a->cap = 128;
|
||||
a->cap = 1;
|
||||
} else if (a->cap <= 256) {
|
||||
a->cap *= 8;
|
||||
} else {
|
||||
a->cap *= 2;
|
||||
a->cap *= 1.7;
|
||||
}
|
||||
|
||||
void **old = a->begin;
|
||||
a->begin = malloc(sizeof(void*) * a->cap);
|
||||
if (old) {
|
||||
memcpy(a->begin, old, a->length * sizeof(void*));
|
||||
a->begin = realloc(a->begin, a->cap);
|
||||
if (a->begin == NULL) {
|
||||
fail_malloc(__FUNCTION__);
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,3 +58,12 @@ void array_set(struct array *a, int index, void *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