Signed-off-by: szdytom <szdytom@163.com>
This commit is contained in:
方而静 2023-06-11 20:50:44 +08:00
parent 440bc22ac7
commit 6950807161
14 changed files with 174 additions and 383 deletions

1
.gitignore vendored
View File

@ -10,6 +10,7 @@
# Debugger # Debugger
*.pdb *.pdb
out.txt
# Linker output # Linker output
*.ilk *.ilk

View File

@ -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);

View File

@ -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
View 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

View File

@ -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
View 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

View File

@ -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);
} }

View File

@ -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 {

View File

@ -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();

View File

@ -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();
}

View File

@ -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:

View File

@ -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
View File

@ -0,0 +1,6 @@
{
long a = 5;
long b = a + 5;
int c = b - 1;
print c;
}

1
tests/input08.ans Normal file
View File

@ -0,0 +1 @@
9