nctref/src/parse.c

870 lines
22 KiB
C

#include"parse.h"
#include<assert.h>
#include<stdlib.h>
#include<string.h>
#include"utils.h"
#include"vartable.h"
#include"reporting.h"
#include<stdint.h>
#include<signal.h>
typedef struct {
UseDef ud;
VarTableEntry *to;
} UseDefToAdd;
typedef struct {
Token *tokens;
ssize_t i;
VarTable *scope;
// Used to coalesce all scopes into one after parsing, to perform global register allocation
ASTChunk *topLevel;
// Used by pushstat to add statements
ASTChunk *currentChunk;
// Used by pushstmt to assemble use-def chain
size_t udsToAddCount;
UseDefToAdd *udsToAdd;
} Parser;
static Token get(Parser *P) {
if(P->tokens[P->i].type == TOKEN_EOF) {
return P->tokens[P->i];
} else {
return P->tokens[P->i++];
}
}
static Token expect(Parser *P, TokenKind t) {
Token tok = get(P);
if(tok.type != t) {
stahp(tok.row, tok.column, "Expected %s, got %s.", TOKEN_NAMES[t], TOKEN_NAMES[tok.type]);
}
return tok;
}
static Token peek(Parser *P, int depth) {
int j = 0;
for(; j < depth; j++) {
if(P->tokens[P->i + j].type == TOKEN_EOF) {
break;
}
}
return P->tokens[P->i + j];
}
static int maybe(Parser *P, TokenKind t) {
if(peek(P, 0).type == t) {
get(P);
return 1;
}
return 0;
}
static void pushstat(Parser *P, void *a) {
for(size_t i = 0; i < P->udsToAddCount; i++) {
VarTableEntry *to = P->udsToAdd[i].to;
UseDef *ud = malloc(sizeof(*ud));
memcpy(ud, &P->udsToAdd[i].ud, sizeof(*ud));
ud->stmt = a;
if(to->data.var.usedefFirst) {
to->data.var.usedefLast->next = ud;
to->data.var.usedefLast = ud;
} else {
to->data.var.usedefFirst = to->data.var.usedefLast = ud;
}
}
P->udsToAddCount = 0;
if(P->currentChunk->statementFirst) {
P->currentChunk->statementLast->statement.next = a;
P->currentChunk->statementLast = a;
} else {
P->currentChunk->statementFirst = P->currentChunk->statementLast = a;
}
}
static ASTExprPrimitive *parse_prim(Parser *P) {
ASTExprPrimitive *ret = malloc(sizeof(*ret));
ret->nodeKind = AST_EXPR_PRIMITIVE;
ret->type = (Type*) primitive_parse("s16");
Token tok = get(P);
const char *str = tok.content;
int base = 10;
if(strchr(str, 'r')) {
base = strtol(str, (char**) &str, 10);
str++; /* Go past the r. */
}
ret->val = strtol(str, NULL, base);
return ret;
}
static void newusedef(Parser *P, VarTableEntry *v, AST *expr) {
for(size_t i = 0; i < v->data.var.reachingDefs->defCount; i++) {
P->udsToAdd = realloc(P->udsToAdd, sizeof(*P->udsToAdd) * (++P->udsToAddCount));
P->udsToAdd[P->udsToAddCount - 1] = (UseDefToAdd) {
.ud = {
.def = v->data.var.reachingDefs->defs[i],
.use = expr,
.stmt = NULL, // set by pushstmt
.next = NULL,
},
.to = v
};
}
}
static AST *exprvar(Parser *P, VarTableEntry *v) {
AST *a = malloc(sizeof(ASTExprVar));
a->nodeKind = AST_EXPR_VAR;
a->exprVar.type = v->type;
a->exprVar.thing = v;
if(v->kind == VARTABLEENTRY_VAR) {
newusedef(P, v, a);
}
return a;
}
AST *nct_cast_expr(AST *what, Type *to) {
if(what == NULL) return NULL;
/* Only exists at parse-time, hence not part of type system and is handled separately */
if(what->nodeKind == AST_EXPR_STRING_LITERAL) {
if(to->type == TYPE_TYPE_ARRAY && type_equal(primitive_parse("u8"), to->array.of) && to->array.length == what->exprStrLit.length) {
ASTExprArray *ret = malloc(sizeof(*ret));
ret->nodeKind = AST_EXPR_ARRAY;
ret->items = malloc(sizeof(*ret->items) * to->array.length);
ret->type = to;
for(int i = 0; i < to->array.length; i++) {
uint8_t bajt = what->exprStrLit.data[i];
ASTExprPrimitive *item = malloc(sizeof(*item));
item->nodeKind = AST_EXPR_PRIMITIVE;
item->type = to->array.of;
item->val = bajt;
ret->items[i] = (AST*) item;
}
return (AST*) ret;
} else if(to->type == TYPE_TYPE_PRIMITIVE && to->primitive.width == 32) {
ASTExprPrimitive *ret = malloc(sizeof(*ret));
ret->nodeKind = AST_EXPR_PRIMITIVE;
ret->type = primitive_parse("u32");
memcpy(&ret->val, what->exprStrLit.data, sizeof(ret->val));
return (AST*) ret;
} else abort();
}
if(type_equal(what->expression.type, to)) return what;
if(!type_is_castable(what->expression.type, to)) {
return NULL;
}
if(what->nodeKind == AST_EXPR_PRIMITIVE && to->type == TYPE_TYPE_PRIMITIVE) {
ASTExprPrimitive *ret = malloc(sizeof(*ret));
ret->nodeKind = AST_EXPR_PRIMITIVE;
ret->type = to;
ret->val = what->exprPrim.val & (((int64_t) 1 << to->primitive.width) - 1);
return (AST*) ret;
} else {
ASTExprCast *ret = malloc(sizeof(*ret));
ret->nodeKind = AST_EXPR_CAST;
ret->type = to;
ret->what = what;
ret->to = to;
return (AST*) ret;
}
abort();
}
AST *nct_parse_expression(Parser *P, int lOP) {
if(lOP == 5) {
if(peek(P, 0).type == TOKEN_NUMBER) {
return (AST*) parse_prim(P);
} else if(peek(P, 0).type == TOKEN_IDENTIFIER) {
return exprvar(P, vartable_find(P->scope, get(P).content));
} else if(peek(P, 0).type == TOKEN_STRING) {
ASTExprStringLiteral *ret = malloc(sizeof(*ret));
ret->nodeKind = AST_EXPR_STRING_LITERAL;
Token tok = get(P);
ret->type = &TYPE_ERROR;
ret->data = tok.content;
ret->length = tok.length;
return (AST*) ret;
}
} else if(lOP == 4) {
if(maybe(P, TOKEN_STAR)) {
ASTExprUnaryOp *astop = malloc(sizeof(*astop));
astop->nodeKind = AST_EXPR_UNARY_OP;
astop->operator = UNOP_DEREF;
astop->operand = nct_parse_expression(P, lOP); /* Not +1! */
astop->type = astop->operand->expression.type->pointer.of;
return (AST*) astop;
} else if(maybe(P, TOKEN_AMPERSAND)) {
ASTExprUnaryOp *astop = malloc(sizeof(*astop));
astop->nodeKind = AST_EXPR_UNARY_OP;
astop->operator = UNOP_REF;
astop->operand = nct_parse_expression(P, lOP);
astop->type = type_pointer_wrap(astop->operand->expression.type);
return (AST*) astop;
} else if(maybe(P, TOKEN_MINUS)) {
AST *operand = nct_parse_expression(P, lOP);
if(operand->nodeKind == AST_EXPR_PRIMITIVE) {
operand->exprPrim.val *= -1;
return operand;
} else {
ASTExprUnaryOp *astop = malloc(sizeof(*astop));
astop->nodeKind = AST_EXPR_UNARY_OP;
astop->operator = UNOP_NEGATE;
astop->operand = operand;
astop->type = operand->expression.type;
return (AST*) astop;
}
} else if(maybe(P, TOKEN_TILDE)) {
AST *child = nct_parse_expression(P, lOP);
if(child->nodeKind == AST_EXPR_PRIMITIVE) {
child->exprPrim.val = \
~child->exprPrim.val;
return child;
} else {
ASTExprUnaryOp *astop = malloc(sizeof(*astop));
astop->nodeKind = AST_EXPR_UNARY_OP;
astop->operator = UNOP_BITWISE_NOT;
astop->operand = child;
astop->type = child->expression.type;
return (AST *) astop;
}
} else return nct_parse_expression(P, lOP + 1);
} else if(lOP == 3) {
AST *ret = nct_parse_expression(P, lOP + 1);
while(peek(P, 0).type == TOKEN_PAREN_L || peek(P, 0).type == TOKEN_SQUAREN_L) {
if(maybe(P, TOKEN_PAREN_L)) {
if(ret->expression.type->type != TYPE_TYPE_FUNCTION) {
stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Only function types may be called.");
}
ASTExprCall *call = malloc(sizeof(*call));
call->nodeKind = AST_EXPR_CALL;
call->type = ret->expression.type->function.ret;
call->what = ret;
call->args = NULL;
ret = (AST*) call;
int argCount = 0;
if(!maybe(P, TOKEN_PAREN_R)) {
while(peek(P, 0).type != TOKEN_PAREN_R && peek(P, 0).type != TOKEN_COMMA) {
call->args = realloc(call->args, (argCount + 1) * sizeof(AST*));
call->args[argCount] = nct_parse_expression(P, 0);
argCount++;
if(maybe(P, TOKEN_PAREN_R)) {
break;
} else expect(P, TOKEN_COMMA);
}
}
/* TODO: Check argument count. */
} else if(maybe(P, TOKEN_SQUAREN_L)) {
ASTExprUnaryOp *ref = malloc(sizeof(*ref));
ref->nodeKind = AST_EXPR_UNARY_OP;
ref->operator = UNOP_REF;
ref->operand = ret;
ref->type = type_pointer_wrap(ret->expression.type->array.of);
ASTExprBinaryOp *child = malloc(sizeof(*child));
child->nodeKind = AST_EXPR_BINARY_OP;
child->operands[0] = (AST*) ref;
child->operands[1] = nct_parse_expression(P, 0);
child->operator = BINOP_ADD;
child->type = ref->type;
int typesize = type_size(ret->expression.type->array.of);
if(typesize != 1) {
ASTExprPrimitive *scale = malloc(sizeof(*scale));
scale->nodeKind = AST_EXPR_PRIMITIVE;
scale->type = primitive_parse("u16");
scale->val = typesize;
ASTExprBinaryOp *mul = malloc(sizeof(*mul));
mul->nodeKind = AST_EXPR_BINARY_OP;
mul->operator = BINOP_MUL;
mul->operands[0] = scale;
mul->operands[1] = child->operands[1];
child->operands[1] = mul;
}
ASTExprUnaryOp *unop = malloc(sizeof(*unop));
unop->nodeKind = AST_EXPR_UNARY_OP;
unop->type = ret->expression.type->array.of;
unop->operator = UNOP_DEREF;
unop->operand = (AST*) child;
ret = (AST*) unop;
expect(P, TOKEN_SQUAREN_R);
} else abort();
}
return ret;
} else if(lOP == 2) {
AST *ret = nct_parse_expression(P, lOP + 1);
if(peek(P, 0).type == TOKEN_STAR || peek(P, 0).type == TOKEN_SLASH) {
while(1) {
BinaryOp op;
if(maybe(P, TOKEN_STAR)) op = BINOP_MUL;
else if(maybe(P, TOKEN_SLASH)) op = BINOP_DIV;
else break;
ASTExprBinaryOp *astop = malloc(sizeof(*astop));
astop->nodeKind = AST_EXPR_BINARY_OP;
astop->type = ret->expression.type;
astop->operator = op;
astop->operands[0] = ret;
AST *operand = nct_parse_expression(P, lOP + 1);
if(operand->expression.type->type != TYPE_TYPE_PRIMITIVE) {
stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Invalid combination of operator and operand types.");
}
astop->operands[1] = operand;
if(!astop->type) {
astop->type = operand->expression.type;
} else {
if(type_size(operand->expression.type) > type_size(astop->type)) {
astop->type = operand->expression.type;
}
}
ret = (AST*) astop;
}
}
return ret;
} else if(lOP == 1) {
AST *ret = nct_parse_expression(P, lOP + 1);
if(
peek(P, 0).type == TOKEN_PLUS
|| peek(P, 0).type == TOKEN_MINUS
|| peek(P, 0).type == TOKEN_AMPERSAND
|| peek(P, 0).type == TOKEN_VERTICAL_BAR
|| peek(P, 0).type == TOKEN_CARET
) {
while(1) {
BinaryOp op;
if(maybe(P, TOKEN_PLUS)) op = BINOP_ADD;
else if(maybe(P, TOKEN_MINUS)) op = BINOP_SUB;
else if(maybe(P, TOKEN_AMPERSAND)) op = BINOP_BITWISE_AND;
else if(maybe(P, TOKEN_VERTICAL_BAR)) op = BINOP_BITWISE_OR;
else if(maybe(P, TOKEN_CARET)) op = BINOP_BITWISE_XOR;
else break;
ASTExprBinaryOp *astop = malloc(sizeof(*astop));
astop->nodeKind = AST_EXPR_BINARY_OP;
astop->type = ret->expression.type;
astop->operator = op;
astop->operands[0] = ret;
ASTExpr *operand = &(astop->operands[1] = nct_parse_expression(P, lOP + 1))->expression;
if(operand->type->type != TYPE_TYPE_PRIMITIVE) {
stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Invalid combination of operator and operand types.");
}
if(!astop->type) {
astop->type = operand->type;
} else {
if(type_size(operand->type) > type_size(astop->type)) {
astop->type = operand->type;
}
}
ret = (AST*) astop;
}
}
return ret;
} else if(lOP == 0) {
AST *ret = nct_parse_expression(P, lOP + 1);
if(peek(P, 0).type == TOKEN_DOUBLE_EQUALS || peek(P, 0).type == TOKEN_EXCLAMATION_EQUALS) {
while(1) {
BinaryOp op;
if(maybe(P, TOKEN_DOUBLE_EQUALS)) op = BINOP_EQUAL;
else if(maybe(P, TOKEN_EXCLAMATION_EQUALS)) op = BINOP_NEQUAL;
else break;
ASTExprBinaryOp *astop = malloc(sizeof(*astop));
astop->nodeKind = AST_EXPR_BINARY_OP;
astop->type = NULL;
astop->operator = op;
astop->operands[0] = ret;
ASTExpr *operand = &(astop->operands[1] = nct_parse_expression(P, lOP + 1))->expression;
if(operand->type->type != TYPE_TYPE_PRIMITIVE) {
stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Invalid combination of operator and operand types.");
}
if(!astop->type) {
astop->type = operand->type;
} else {
if(type_size(operand->type) > type_size(astop->type)) {
astop->type = operand->type;
}
}
ret = (AST*) astop;
}
}
ret = ast_expression_optimize(ret);
return ret;
}
#ifdef DEBUG
else abort();
#endif
return NULL;
}
/* Since this function backtracks, don't use aborting functions like expect. */
Type *nct_parse_typename(Parser *P) {
int oldIdx = P->i;
if(peek(P, 0).type != TOKEN_IDENTIFIER) {
goto backtrack;
}
Type *ret = (Type*) primitive_parse(expect(P, TOKEN_IDENTIFIER).content);
if(!ret) {
goto backtrack;
}
while(peek(P, 0).type == TOKEN_PAREN_L || peek(P, 0).type == TOKEN_STAR || peek(P, 0).type == TOKEN_SQUAREN_L) {
if(maybe(P, TOKEN_STAR)) {
TypePointer *ptr = malloc(sizeof(*ptr));
ptr->type = TYPE_TYPE_POINTER;
ptr->of = ret;
ret = (Type*) ptr;
} else if(maybe(P, TOKEN_PAREN_L)) {
TypeFunction *fun = malloc(sizeof(*fun));
fun->type = TYPE_TYPE_FUNCTION;
fun->ret = ret;
fun->argCount = 0;
fun->args = malloc(0);
if(!maybe(P, TOKEN_PAREN_R)) {
while(1) {
fun->argCount++;
fun->args = realloc(fun->args, sizeof(Type*) * fun->argCount);
if((fun->args[fun->argCount - 1] = nct_parse_typename(P)) == NULL) {
free(fun);
goto backtrack;
}
if(maybe(P, TOKEN_PAREN_R)) {
break;
} else expect(P, TOKEN_COMMA);
}
}
ret = (Type*) fun;
} else if(maybe(P, TOKEN_SQUAREN_L)) {
TypeArray *arr = malloc(sizeof(*arr));
arr->type = TYPE_TYPE_ARRAY;
arr->of = ret;
if(peek(P, 0).type == TOKEN_NUMBER) {
ASTExprPrimitive *prim = parse_prim(P);
arr->length = prim->val;
free(prim);
} else if(maybe(P, TOKEN_QUESTION_MARK)) {
arr->length = 0;
} else {
//stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Array size must be either constant or '?'.");
goto backtrack;
}
expect(P, TOKEN_SQUAREN_R);
ret = (Type*) arr;
}
}
return ret;
backtrack:
P->i = oldIdx;
return NULL;
}
/* Potentially backtracking. Returns NULL upon failure. */
static AST *parse_declaration(Parser *P) {
int oldIdx = P->i;
int isLocal = maybe(P, TOKEN_LOCAL);
int isExternal = 0;
if(!isLocal) {
isExternal = maybe(P, TOKEN_EXTERN);
}
Type *type = nct_parse_typename(P);
if(!type) goto backtrack;
if(peek(P, 0).type != TOKEN_IDENTIFIER) goto backtrack;
Token name = expect(P, TOKEN_IDENTIFIER);
VarTableEntry *entry;
if(peek(P, 0).type == TOKEN_COLON && (entry = vartable_get(P->scope, name.content))) {
/* Forward declared. */
} else {
entry = calloc(sizeof(*entry), 1);
entry->type = type;
}
AST *ret = NULL;
if(maybe(P, TOKEN_EQUALS) || (peek(P, 0).type == TOKEN_SEMICOLON && !isExternal && !isLocal)) {
/*if(isExternal || isLocal) {
fputs("'local' and 'extern' keywords are to be used for symbol declaration only.\n", stderr);
abort();
return NULL;
}*/
entry->kind = VARTABLEENTRY_VAR;
entry->data.var.priority = 1;
ASTStmtAssign *assign = malloc(sizeof(*assign));
assign->nodeKind = AST_STMT_ASSIGN;
entry->data.var.reachingDefs = reachingdefs_push(NULL);
reachingdefs_set(entry->data.var.reachingDefs, (AST*) assign);
assign->what = exprvar(P, entry);
assign->to = peek(P, 0).type == TOKEN_SEMICOLON ? NULL : nct_parse_expression(P, 0);
ret = (AST*) assign;
} else {
ASTStmtDecl *decl = malloc(sizeof(*ret));
decl->nodeKind = AST_STMT_DECL;
decl->thing = entry;
decl->next = NULL;
if(maybe(P, TOKEN_COLON)) {
if(isExternal) {
fputs("External symbols may not be defined.\n", stderr);
abort();
return NULL;
}
entry->kind = VARTABLEENTRY_SYMBOL;
entry->data.symbol.isLocal = isLocal;
entry->data.symbol.isExternal = isExternal;
entry->data.symbol.name = name.content;
decl->expression = nct_cast_expr(nct_parse_expression(P, 0), type);
if(decl->expression) {
//if(ret->expression->expression.constantType == EXPRESSION_NOT_CONSTANT) {
// stahp(1, 4142, "Symbol declaration may contain constant expressions only.");
//}
}
} else if(isExternal) {
entry->kind = VARTABLEENTRY_SYMBOL;
entry->data.symbol.isLocal = isLocal;
entry->data.symbol.isExternal = isExternal;
entry->data.symbol.name = name.content;
} else {
abort();
}
ret = (AST*) decl;
}
vartable_set(P->scope, name.content, entry);
expect(P, TOKEN_SEMICOLON);
return ret;
backtrack:
P->i = oldIdx;
return NULL;
}
ASTChunk *nct_parse_chunk(Parser*, int, int);
void nct_parse_statement(Parser *P) {
if(maybe(P, TOKEN_IF)) {
expect(P, TOKEN_PAREN_L);
AST *e = nct_parse_expression(P, 0);
expect(P, TOKEN_PAREN_R);
ASTStmtIf *ret = malloc(sizeof(*ret));
ret->nodeKind = AST_STMT_IF;
ret->next = NULL;
ret->expression = e;
pushstat(P, ret);
expect(P, TOKEN_SQUIGGLY_L);
ret->then = (AST*) nct_parse_chunk(P, 0, 0);
expect(P, TOKEN_SQUIGGLY_R);
return;
} else if(maybe(P, TOKEN_LOOP)) {
ASTStmtLoop *ret = malloc(sizeof(*ret));
ret->nodeKind = AST_STMT_LOOP;
ret->next = NULL;
expect(P, TOKEN_SQUIGGLY_L);
ret->body = (AST*) nct_parse_chunk(P, 0, 1);
expect(P, TOKEN_SQUIGGLY_R);
pushstat(P, ret);
return;
} else if(maybe(P, TOKEN_BREAK)) {
ASTStmtBreak *ret = malloc(sizeof(*ret));
ret->nodeKind = AST_STMT_BREAK;
ret->next = NULL;
expect(P, TOKEN_SEMICOLON);
pushstat(P, ret);
return;
} else if(maybe(P, TOKEN_CONTINUE)) {
ASTStmtContinue *ret = malloc(sizeof(*ret));
ret->nodeKind = AST_STMT_CONTINUE;
ret->next = NULL;
expect(P, TOKEN_SEMICOLON);
pushstat(P, ret);
return;
} else if(peek(P, 0).type == TOKEN_IDENTIFIER) {
if(!strcmp(peek(P, 0).content, "@align")) {
ASTStmtExtAlign *ret = malloc(sizeof(*ret));
ret->nodeKind = AST_STMT_EXT_ALIGN;
ret->next = NULL;
get(P);
expect(P, TOKEN_PAREN_L);
ASTExprPrimitive *val = parse_prim(P);
ret->val = val->val;
free(val);
expect(P, TOKEN_PAREN_R);
expect(P, TOKEN_SEMICOLON);
pushstat(P, ret);
return;
} else if(!strcmp(peek(P, 0).content, "@org")) {
ASTStmtExtOrg *ret = malloc(sizeof(*ret));
ret->nodeKind = AST_STMT_EXT_ORG;
ret->next = NULL;
get(P);
expect(P, TOKEN_PAREN_L);
ASTExprPrimitive *val = parse_prim(P);
ret->val = val->val;
free(val);
expect(P, TOKEN_PAREN_R);
expect(P, TOKEN_SEMICOLON);
pushstat(P, ret);
return;
} else if(!strcmp(peek(P, 0).content, "@section")) {
ASTStmtExtSection *ret = malloc(sizeof(*ret));
ret->nodeKind = AST_STMT_EXT_SECTION;
ret->next = NULL;
get(P);
expect(P, TOKEN_PAREN_L);
ret->name = expect(P, TOKEN_STRING);
expect(P, TOKEN_PAREN_R);
expect(P, TOKEN_SEMICOLON);
pushstat(P, ret);
return;
}
}
{
AST *decl = parse_declaration(P);
if(decl) {
pushstat(P, decl);
return;
}
}
AST *e = nct_parse_expression(P, 0);
if(maybe(P, TOKEN_EQUALS)) {
ASTStmtAssign *ret = malloc(sizeof(*ret));
ret->nodeKind = AST_STMT_ASSIGN;
ret->next = NULL;
ret->what = e;
ret->to = nct_parse_expression(P, 0);//nct_cast_expr(nct_parse_expression(P, 0), ret->what->expression.type);
if(ret->what->nodeKind == AST_EXPR_VAR) {
reachingdefs_set(ret->what->exprVar.thing->data.var.reachingDefs, (AST*) ret);
}
expect(P, TOKEN_SEMICOLON);
pushstat(P, ret);
return;
} else {
ASTStmtExpr *ret = malloc(sizeof(*ret));
ret->nodeKind = AST_STMT_EXPR;
ret->next = NULL;
ret->expr = e;
expect(P, TOKEN_SEMICOLON);
pushstat(P, ret);
return;
}
}
ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize) {
if(P->scope) {
}
AST *ret = malloc(sizeof(ASTChunk));
ret->nodeKind = AST_CHUNK;
ret->chunk.statementFirst = ret->chunk.statementLast = NULL;
ret->chunk.varCount = 0;
ret->chunk.vars = NULL;
AST *oldChunk = P->currentChunk;
P->currentChunk = (AST*) ret;
P->scope = vartable_new(P->scope);
if(isTopLevel) {
P->topLevel = &ret->chunk;
}
vartable_new_reachingdefs_for_all_vars(P->scope);
/* Find all symbol names and struct types ahead of time. Searches for colons as those can only mean symbol declarations */
{
size_t oldIdx = P->i;
while(1) {
TokenKind k = get(P).type;
if(k == (isTopLevel ? TOKEN_EOF : TOKEN_SQUIGGLY_R)) {
break;
} else if(k == TOKEN_SQUIGGLY_L) { /* Don't enter deeper scopes. */
int depth = 0;
while(1) {
switch(get(P).type) {
case TOKEN_SQUIGGLY_L: depth++; break;
case TOKEN_SQUIGGLY_R: if(depth-- == 0) goto stomp; break;
default:;
}
}
stomp:;
} else if(k == TOKEN_COLON) {
/* Move back to beginning of declaration. */
do {
P->i--;
} while(P->i >= 0 && P->tokens[P->i].type != TOKEN_SEMICOLON && P->tokens[P->i].type != TOKEN_SQUIGGLY_R && P->tokens[P->i].type != TOKEN_PAREN_R);
P->i++;
AST *d = parse_declaration(P);
if(!d) abort();
free(d); /* We don't need it. */
}
}
P->i = oldIdx;
}
/* Now actual parsing. */
while(peek(P, 0).type != (isTopLevel ? TOKEN_EOF : TOKEN_SQUIGGLY_R)) {
nct_parse_statement(P);
}
vartable_coalesce_reachingdefs_for_all_vars(P->scope);
size_t nonSymbols = 0;
for(size_t i = 0; i < P->scope->count; i++) {
if(P->scope->data[i]->kind == VARTABLEENTRY_VAR) {
nonSymbols++;
if(varPrioritize) {
P->scope->data[i]->data.var.priority++;
}
}
}
P->topLevel->vars = realloc(P->topLevel->vars, sizeof(*P->topLevel->vars) * (P->topLevel->varCount + nonSymbols));
for(size_t i = 0; i < P->scope->count; i++) {
if(P->scope->data[i]->kind == VARTABLEENTRY_VAR) {
P->topLevel->vars[P->topLevel->varCount++] = P->scope->data[i];
}
}
P->scope = P->scope->parent;
P->currentChunk = oldChunk;
return &ret->chunk;
}
AST *nct_parse(Token *tokens) {
Parser P;
memset(&P, 0, sizeof(P));
P.tokens = tokens;
return (AST*) nct_parse_chunk(&P, 1, 0);
}