#include"parse.h" #include #include #include #include"utils.h" #include"vartable.h" #include"reporting.h" #include #include #include"x86.h" #ifndef __GNUC__ static inline int __builtin_clzl(unsigned long x) { unsigned long n = 32; unsigned long y; y = x >>16; if (y != 0) { n = n -16; x = y; } y = x >> 8; if (y != 0) { n = n - 8; x = y; } y = x >> 4; if (y != 0) { n = n - 4; x = y; } y = x >> 2; if (y != 0) { n = n - 2; x = y; } y = x >> 1; if (y != 0) return n - 2; return n - x; } #endif typedef struct { Token *tokens; intmax_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 to place guard variable uses after loops to stop reg allocation from fucking up VarTable *loopScope; size_t guardedVarCount; ASTExprVar **guardedVars; } 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) { 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; 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); // Smallest integer type to store number char buf[8]; snprintf(buf, sizeof(buf), "s%i", ret->val ? (64 - __builtin_clzl(ret->val - 1)) : 1); ret->type = (Type*) primitive_parse(buf); return ret; } /*static void newusedef(Parser *P, VarTableEntry *v, AST *expr) { ReachingDefs *defs = v->data.var.reachingDefs; while(defs) { for(size_t i = 0; i < defs->defCount; i++) { P->udsToAdd = realloc(P->udsToAdd, sizeof(*P->udsToAdd) * (++P->udsToAddCount)); P->udsToAdd[P->udsToAddCount - 1].ud.def = defs->defs[i]; P->udsToAdd[P->udsToAddCount - 1].ud.use = expr; P->udsToAdd[P->udsToAddCount - 1].ud.stmt = NULL; // set by pushstmt P->udsToAdd[P->udsToAddCount - 1].ud.next = NULL; P->udsToAdd[P->udsToAddCount - 1].to = v; } if(defs->excludeParent) { break; } defs = defs->parent; } }*/ 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(P->loopScope) { // XXX: O(n)!!!!!!!!! int inloop = 0; for(VarTable *vt = v->owner; vt; vt = vt->parent) { if(vt->parent == P->loopScope) { inloop = 1; break; } } if(!inloop) { int alreadyAdded = 0; for(size_t i = 0; i < P->guardedVarCount; i++) { if(P->guardedVars[i]->thing == v) { alreadyAdded = 1; break; } } if(!alreadyAdded) { ASTExprVar *ev = malloc(sizeof(*ev)); memcpy(ev, a, sizeof(*ev)); P->guardedVars = realloc(P->guardedVars, sizeof(*P->guardedVars) * (P->guardedVarCount + 1)); P->guardedVars[P->guardedVarCount++] = ev; } } } 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) { if(to->primitive.width != what->exprStrLit.length * 8) { stahp(0, 0, "Size mismatch between string literal and target type"); } ASTExprPrimitive *ret = malloc(sizeof(*ret)); ret->nodeKind = AST_EXPR_PRIMITIVE; ret->type = to; 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 || to->type == TYPE_TYPE_POINTER)) { ASTExprPrimitive *ret = malloc(sizeof(*ret)); ret->nodeKind = AST_EXPR_PRIMITIVE; ret->type = to; if(to->type == TYPE_TYPE_PRIMITIVE) { ret->val = what->exprPrim.val & ((1UL << to->primitive.width) - 1); } else { ret->val = what->exprPrim.val & ((1UL << (8 * type_size(to))) - 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(); } ASTChunk *nct_parse_chunk(Parser*, int, int); Type *nct_parse_typename(Parser *P); AST *nct_parse_expression(Parser *P, int lOP) { if(lOP == 0) { // Test if this is an anonymous function Type *ft = nct_parse_typename(P); if(ft) { assert(ft->type == TYPE_TYPE_FUNCTION); ASTExprFunc *e = malloc(sizeof(*e)); e->nodeKind = AST_EXPR_FUNC; e->type = ft; maybe(P, TOKEN_SQUIGGLY_L); e->chunk = (AST*) nct_parse_chunk(P, 1, 0); maybe(P, TOKEN_SQUIGGLY_R); return (AST*) e; } } if(lOP == 5) { if(peek(P, 0).type == TOKEN_NUMBER) { return (AST*) parse_prim(P); } else if(peek(P, 0).type == TOKEN_IDENTIFIER) { if(!strcmp(peek(P, 0).content, "@stack")) { get(P); ASTExprStackPointer *ret = malloc(sizeof(*ret)); ret->nodeKind = AST_EXPR_STACK_POINTER; ret->type = primitive_parse("u32"); return (AST*) ret; } 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(maybe(P, TOKEN_PAREN_L)) { AST *e = nct_parse_expression(P, 0); expect(P, TOKEN_PAREN_R); return e; } } 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."); } VarTableEntry *tempo = calloc(1, sizeof(*tempo)); tempo->kind = VARTABLEENTRY_VAR; tempo->type = ret->expression.type->function.ret; tempo->data.var.name = "$temp"; tempo->data.var.color = COLOR_EAX; P->topLevel->vars = realloc(P->topLevel->vars, sizeof(*P->topLevel->vars) * (++P->topLevel->varCount)); P->topLevel->vars[P->topLevel->varCount - 1] = tempo; ASTExprCall *call = malloc(sizeof(*call)); call->nodeKind = AST_EXPR_CALL; call->type = ret->expression.type->function.ret; call->what = ret; call->args = NULL; 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); } } ASTStmtAssign *assign = calloc(1, sizeof(*assign)); assign->nodeKind = AST_STMT_ASSIGN; assign->what = exprvar(P, tempo); assign->to = call; pushstat(P, assign); ret = exprvar(P, tempo); /* 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] = (AST*) scale; mul->operands[1] = child->operands[1]; child->operands[1] = (AST*) 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(!type_is_number(astop->operands[0]->expression.type) || !type_is_number(astop->operands[1]->expression.type)) { stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Attempt to perform arithmetic on non-number types."); } if(type_size(astop->operands[0]->expression.type) < type_size(astop->operands[1]->expression.type)) { astop->operands[0] = nct_cast_expr(astop->operands[0], astop->operands[1]->expression.type); } if(type_size(astop->operands[1]->expression.type) < type_size(astop->operands[0]->expression.type)) { astop->operands[1] = nct_cast_expr(astop->operands[1], astop->operands[0]->expression.type); } 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; entry->data.var.color = -1; ASTStmtAssign *assign = malloc(sizeof(*assign)); assign->nodeKind = AST_STMT_ASSIGN; assign->next = NULL; //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; } 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; int isFirstLoop = P->loopScope == NULL; if(isFirstLoop) { P->loopScope = P->scope; } expect(P, TOKEN_SQUIGGLY_L); ret->body = (AST*) nct_parse_chunk(P, 0, 1); expect(P, TOKEN_SQUIGGLY_R); pushstat(P, ret); if(isFirstLoop) { P->loopScope = NULL; for(size_t i = 0; i < P->guardedVarCount; i++) { ASTExprVar *ev = P->guardedVars[i]; AST *es = calloc(1, sizeof(ASTStmtExpr)); es->nodeKind = AST_STMT_EXPR; es->stmtExpr.expr = (AST*) ev; pushstat(P, es); } P->guardedVarCount = 0; free(P->guardedVars); P->guardedVars = NULL; } 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_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) { AST *ret = calloc(1, sizeof(ASTChunk)); ret->nodeKind = AST_CHUNK; ret->chunk.statementFirst = ret->chunk.statementLast = NULL; ret->chunk.varCount = 0; ret->chunk.vars = NULL; ret->chunk.stackReservation = 0; AST *oldChunk = (AST*) P->currentChunk; P->currentChunk = &ret->chunk; P->scope = vartable_new(P->scope); ASTChunk *oldTopLevel = P->topLevel; 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->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 != TOKEN_EOF && peek(P, 0).type != 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->data[i]->owner = P->topLevel; // not sure why this line ever existed, it makes no sense } } P->scope = P->scope->parent; P->currentChunk = oldChunk; if(isTopLevel) { P->topLevel = oldTopLevel; } 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); }