Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #define _CRT_SECURE_NO_WARNINGS
- #include <stdint.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <stdio.h>
- #include <string.h>
- #include <assert.h>
- struct Scanner {
- const char *filename;
- const char *source;
- const char *pos;
- };
- enum TokenType {
- Tok_Invalid,
- Tok_End,
- Tok_Identifier,
- Tok_Number,
- Tok_Assign,
- Tok_Add,
- Tok_Sub,
- Tok_Mul,
- Tok_Div,
- Tok_Dot,
- Tok_Comma,
- Tok_LParen,
- Tok_RParen,
- Tok_LBracket,
- Tok_RBracket,
- Tok_LBlock,
- Tok_RBlock,
- Tok_Newline,
- Tok_Kw_Def,
- Tok_Kw_New,
- Tok_Kw_Var,
- };
- struct Token {
- Scanner *scanner;
- uint32_t begin, end;
- TokenType type;
- };
- bool tokenEqual(Token *a, Token *b)
- {
- if (a->type != b->type) return false;
- uint32_t aLen = a->end - a->begin;
- uint32_t bLen = b->end - b->begin;
- if (aLen != bLen) return false;
- const char *aSrc = a->scanner->source + a->begin;
- const char *bSrc = b->scanner->source + b->begin;
- return !memcmp(aSrc, bSrc, aLen);
- }
- static void errorAtV(Scanner *scanner, uint32_t offset, const char *message, va_list args)
- {
- char err[4096];
- vsprintf(err, message, args);
- const char *src = scanner->source;
- uint32_t line = 0, col = 0;
- for (uint32_t i = 0; i < offset; i++) {
- if (src[i] == '\n') {
- line++;
- col = 0;
- } else {
- col++;
- }
- }
- fprintf(stderr, "%s:%u:%u: %s\n", scanner->filename, line + 1, col + 1, err);
- exit(1);
- }
- static void errorAtOffset(Scanner *scanner, uint32_t offset, const char *message, ...)
- {
- va_list args;
- va_start(args, message);
- errorAtV(scanner, offset, message, args);
- va_end(args);
- }
- static void errorAt(Token token, const char *message, ...)
- {
- va_list args;
- va_start(args, message);
- errorAtV(token.scanner, token.begin, message, args);
- va_end(args);
- }
- Token lex(Scanner *scanner)
- {
- const char *begin = scanner->source;
- const char *p = scanner->pos;
- whitespace:
- while (*p == ' ' || *p == '\t' || *p == '\r') {
- p++;
- }
- if (p[0] == '/' && p[1] == '/') {
- p += 2;
- while (*p != '\0' && *p != '\n') {
- p++;
- }
- goto whitespace;
- }
- Token token;
- token.scanner = scanner;
- token.begin = (uint32_t)(p - begin);
- if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || *p == '_') {
- const char *ident = p;
- uint32_t len;
- token.type = Tok_Identifier;
- p++;
- while ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9') || *p == '_') {
- p++;
- }
- len = (uint32_t)(p - ident);
- if (len == 3 && !memcmp(ident, "def", 3)) token.type = Tok_Kw_Def;
- else if (len == 3 && !memcmp(ident, "new", 3)) token.type = Tok_Kw_New;
- else if (len == 3 && !memcmp(ident, "var", 3)) token.type = Tok_Kw_Var;
- goto accept;
- }
- if (*p >= '0' && *p <= '9') {
- token.type = Tok_Number;
- p++;
- while (*p >= '0' && *p <= '9') {
- p++;
- }
- goto accept;
- }
- switch (*p) {
- case '\0':
- token.type = Tok_End;
- token.end = token.begin + 1;
- return token;
- case '=': token.type = Tok_Assign; break;
- case '+': token.type = Tok_Add; break;
- case '-': token.type = Tok_Sub; break;
- case '*': token.type = Tok_Mul; break;
- case '/': token.type = Tok_Div; break;
- case '.': token.type = Tok_Dot; break;
- case ',': token.type = Tok_Comma; break;
- case '(': token.type = Tok_LParen; break;
- case ')': token.type = Tok_RParen; break;
- case '[': token.type = Tok_LBracket; break;
- case ']': token.type = Tok_RBracket; break;
- case '{': token.type = Tok_LBlock; break;
- case '}': token.type = Tok_RBlock; break;
- case '\n': token.type = Tok_Newline; break;
- default:
- errorAtOffset(scanner, token.begin, "Unexpected character '%c' (0x%02x)", *p, *p);
- }
- p++;
- accept:
- scanner->pos = p;
- token.end = (uint32_t)(p - begin);
- return token;
- }
- struct Parser {
- Scanner *scanner;
- Token token;
- Token prev_token;
- };
- static void errorAtCurrent(Parser *p, const char *message, ...)
- {
- va_list args;
- va_start(args, message);
- errorAtV(p->token.scanner, p->token.begin, message, args);
- va_end(args);
- }
- static void errorAtPrev(Parser *p, const char *message, ...)
- {
- va_list args;
- va_start(args, message);
- errorAtV(p->prev_token.scanner, p->prev_token.begin, message, args);
- va_end(args);
- }
- static bool accept(Parser *p, TokenType type)
- {
- if (p->token.type == type) {
- p->prev_token = p->token;
- p->token = lex(p->scanner);
- return true;
- }
- return false;
- }
- static void require(Parser *p, TokenType type, const char *message)
- {
- if (!accept(p, type)) {
- errorAtCurrent(p, "Expected %s", message);
- }
- }
- enum AstType {
- Ast_Def,
- Ast_Block,
- Ast_Var,
- Ast_New,
- Ast_Assign,
- Ast_Binop,
- Ast_Index,
- Ast_Ident,
- Ast_Number,
- Ast_Call,
- Ast_Member,
- Ast_Paren,
- };
- struct Ast {
- AstType type;
- Token token;
- union {
- struct {
- Token name;
- Ast *block;
- } def;
- struct {
- Ast *stmt;
- uint32_t numStmt;
- } block;
- struct {
- Token name;
- Ast *expr;
- } var;
- struct {
- Ast *type;
- Ast *count;
- } new_;
- struct {
- Ast *left;
- Ast *right;
- } assign;
- struct {
- Token op;
- Ast *left;
- Ast *right;
- } binop;
- struct {
- Ast *left;
- Ast *index;
- } index;
- struct {
- Token name;
- } ident;
- struct {
- Token value;
- } number;
- struct {
- Ast *func;
- Ast *args;
- uint32_t numArgs;
- } call;
- struct {
- Ast *expr;
- Token field;
- } member;
- struct {
- Ast *expr;
- } paren;
- };
- };
- static Ast astPool[1024 * 16];
- static uint32_t astPoolIndex;
- Ast *pushAst(AstType type, Token *token)
- {
- Ast *ast = &astPool[astPoolIndex++];
- ast->type = type;
- if (token) {
- ast->token = *token;
- }
- return ast;
- }
- Ast *pushAsts(Ast *asts, uint32_t amount)
- {
- Ast *res = astPool + astPoolIndex;
- memcpy(res, asts, amount * sizeof(Ast));
- astPoolIndex += amount;
- return res;
- }
- Ast *parseExpr(Parser *p);
- Ast *parseType(Parser *p)
- {
- Ast *ast = NULL;
- if (accept(p, Tok_Identifier)) {
- ast = pushAst(Ast_Ident, &p->prev_token);
- ast->ident.name = p->prev_token;
- } else {
- errorAtCurrent(p, "Expected a type");
- }
- return ast;
- }
- Ast *parseAtom(Parser *p)
- {
- Ast *ast = NULL;
- if (accept(p, Tok_Identifier)) {
- ast = pushAst(Ast_Ident, &p->prev_token);
- ast->ident.name = p->prev_token;
- } else if (accept(p, Tok_Number)) {
- ast = pushAst(Ast_Number, &p->prev_token);
- ast->number.value = p->prev_token;
- } else if (accept(p, Tok_LParen)) {
- ast = pushAst(Ast_Paren, &p->prev_token);
- ast->paren.expr = parseExpr(p);
- require(p, Tok_RParen, "closing paren");
- } else if (accept(p, Tok_Kw_New)) {
- ast = pushAst(Ast_New, &p->prev_token);
- ast->new_.type = parseType(p);
- if (accept(p, Tok_LBracket)) {
- ast->new_.count = parseExpr(p);
- require(p, Tok_RBracket, "closing bracket");
- }
- } else {
- errorAtCurrent(p, "Expected an expression");
- }
- return ast;
- }
- Ast *parseCall(Parser *p)
- {
- Ast *left = parseAtom(p);
- for (;;) {
- if (accept(p, Tok_LParen)) {
- Ast args[32];
- uint32_t numArgs = 0;
- Ast *call = pushAst(Ast_Call, &p->prev_token);
- call->call.func = left;
- if (!accept(p, Tok_RParen)) {
- do {
- args[numArgs] = *parseExpr(p);
- numArgs++;
- } while (accept(p, Tok_Comma));
- require(p, Tok_RParen, "closing paren");
- }
- call->call.args = pushAsts(args, numArgs);
- call->call.numArgs = numArgs;
- left = call;
- } else if (accept(p, Tok_LBracket)) {
- Ast *index = pushAst(Ast_Index, &p->prev_token);
- index->index.left = left;
- index->index.index = parseExpr(p);
- require(p, Tok_RBracket, "closing bracket");
- left = index;
- } else if (accept(p, Tok_Dot)) {
- Ast *member = pushAst(Ast_Member, &p->prev_token);
- member->member.expr = left;
- require(p, Tok_Identifier, "member name");
- member->member.field = p->prev_token;
- left = member;
- } else {
- break;
- }
- }
- return left;
- }
- Ast *parseTerm(Parser *p)
- {
- Ast *left = parseCall(p);
- while (accept(p, Tok_Mul) || accept(p, Tok_Div)) {
- Ast *binop = pushAst(Ast_Binop, &p->prev_token);
- binop->binop.op = binop->token;
- binop->binop.left = left;
- binop->binop.right = parseCall(p);
- left = binop;
- }
- return left;
- }
- Ast *parseSum(Parser *p)
- {
- Ast *left = parseTerm(p);
- while (accept(p, Tok_Add) || accept(p, Tok_Sub)) {
- Ast *binop = pushAst(Ast_Binop, &p->prev_token);
- binop->binop.op = binop->token;
- binop->binop.left = left;
- binop->binop.right = parseTerm(p);
- left = binop;
- }
- return left;
- }
- Ast *parseExpr(Parser *p)
- {
- Ast *expr = parseSum(p);
- if (accept(p, Tok_Assign)) {
- errorAtPrev(p, "Illegal assignment in expression");
- }
- return expr;
- }
- Ast *parseStmt(Parser *p)
- {
- Ast *expr = parseSum(p);
- if (accept(p, Tok_Assign)) {
- Ast *assign = pushAst(Ast_Assign, &p->prev_token);
- assign->assign.left = expr;
- assign->assign.right = parseExpr(p);
- expr = assign;
- }
- return expr;
- }
- Ast *finishBlock(Parser *p)
- {
- Ast *block = pushAst(Ast_Block, &p->prev_token);
- Ast stmt[128];
- uint32_t numStmt = 0;
- while (!accept(p, Tok_RBlock)) {
- Ast *ast = NULL;
- if (accept(p, Tok_Newline)) {
- /* Nop */
- } else if (accept(p, Tok_Kw_Var)) {
- ast = pushAst(Ast_Var, &p->prev_token);
- require(p, Tok_Identifier, "variable name");
- ast->var.name = p->prev_token;
- if (accept(p, Tok_Assign)) {
- ast->var.expr = parseExpr(p);
- }
- } else {
- ast = parseStmt(p);
- require(p, Tok_Newline, "expected newline after statement");
- }
- if (ast) {
- stmt[numStmt] = *ast;
- numStmt++;
- }
- }
- block->block.stmt = pushAsts(stmt, numStmt);
- block->block.numStmt = numStmt;
- return block;
- }
- Ast *parseTop(Parser *p)
- {
- if (accept(p, Tok_Kw_Def)) {
- Ast *def = pushAst(Ast_Def, &p->prev_token);
- require(p, Tok_Identifier, "name for function");
- def->def.name = p->prev_token;
- require(p, Tok_LParen, "argument list");
- /* TODO */
- require(p, Tok_RParen, "closing argument list");
- require(p, Tok_LBlock, "function body");
- def->def.block = finishBlock(p);
- return def;
- } else if (accept(p, Tok_Newline)) {
- /* Nop */
- return NULL;
- } else {
- errorAtCurrent(p, "Expected top-level declaration");
- return NULL;
- }
- }
- Ast *parse(Scanner *scanner)
- {
- Parser parser, *p = &parser;
- p->scanner = scanner;
- p->prev_token.type = Tok_Invalid;
- p->token = lex(scanner);
- Ast *block = pushAst(Ast_Block, NULL);
- block->token.type = Tok_Invalid;
- Ast stmt[128];
- uint32_t numStmt = 0;
- while (!accept(p, Tok_End)) {
- Ast *top = parseTop(p);
- if (top) {
- stmt[numStmt] = *top;
- numStmt++;
- }
- }
- block->block.stmt = pushAsts(stmt, numStmt);
- block->block.numStmt = numStmt;
- return block;
- }
- void printIndent(int indent) {
- for (int i = 0; i < indent; i++) {
- printf("%s", " ");
- }
- }
- void printAst(Ast *ast, int indent)
- {
- switch (ast->type)
- {
- case Ast_Def:
- printf("def %.*s() ", ast->def.name.end - ast->def.name.begin, ast->def.name.scanner->source + ast->def.name.begin);
- printAst(ast->def.block, indent + 1);
- break;
- case Ast_Block:
- if (ast->token.type != Tok_Invalid) printf("{\n");
- for (uint32_t i = 0; i < ast->block.numStmt; i++) {
- printIndent(indent);
- printAst(ast->block.stmt + i, indent);
- putchar('\n');
- }
- printIndent(indent - 1);
- if (ast->token.type != Tok_Invalid) printf("}");
- break;
- case Ast_Var:
- printf("var %.*s", ast->var.name.end - ast->var.name.begin, ast->var.name.scanner->source + ast->var.name.begin);
- if (ast->var.expr) {
- printf(" = ");
- printAst(ast->var.expr, indent);
- }
- break;
- case Ast_New:
- printf("new ");
- printAst(ast->new_.type, indent);
- if (ast->new_.count) {
- putchar('[');
- printAst(ast->new_.count, indent);
- putchar(']');
- }
- break;
- case Ast_Assign:
- printAst(ast->assign.left, indent);
- printf(" = ");
- printAst(ast->assign.right, indent);
- break;
- case Ast_Binop:
- printAst(ast->binop.left, indent);
- printf(" %.*s ", ast->binop.op.end - ast->binop.op.begin, ast->binop.op.scanner->source + ast->binop.op.begin);
- printAst(ast->binop.right, indent);
- break;
- case Ast_Index:
- printAst(ast->index.left, indent);
- putchar('[');
- printAst(ast->index.index, indent);
- putchar(']');
- break;
- case Ast_Ident:
- printf("%.*s", ast->ident.name.end - ast->ident.name.begin, ast->ident.name.scanner->source + ast->ident.name.begin);
- break;
- case Ast_Number:
- printf("%.*s", ast->number.value.end - ast->number.value.begin, ast->number.value.scanner->source + ast->number.value.begin);
- break;
- case Ast_Call:
- printAst(ast->index.left, indent);
- putchar('(');
- for (uint32_t i = 0; i < ast->call.numArgs; i++) {
- printAst(ast->call.args + i, indent);
- }
- putchar(')');
- break;
- case Ast_Member:
- printAst(ast->member.expr, indent);
- putchar('.');
- printf("%.*s", ast->member.field.end - ast->member.field.begin, ast->member.field.scanner->source + ast->member.field.begin);
- break;
- case Ast_Paren:
- putchar('(');
- printAst(ast->paren.expr, indent);
- putchar(')');
- break;
- }
- }
- struct Slice {
- void *data;
- uint32_t offset, count;
- };
- enum TypeType {
- Type_Unit,
- Type_Int,
- Type_Slice,
- };
- struct Type {
- TypeType type;
- union {
- struct {
- Type *type;
- } slice;
- };
- };
- bool typeEqual(Type *a, Type *b)
- {
- if (a->type != b->type) return false;
- switch (a->type) {
- case Type_Unit: return true;
- case Type_Int: return true;
- case Type_Slice:
- return typeEqual(a->slice.type, b->slice.type);
- }
- assert(0);
- return false;
- }
- uint32_t typeSize(Type *type)
- {
- switch (type->type) {
- case Type_Unit:
- return 0;
- case Type_Int:
- return 4;
- case Type_Slice:
- return sizeof(Slice);
- }
- assert(0);
- return 0;
- }
- Type intType = { Type_Int };
- Type unitType = { Type_Unit };
- static Type typePool[1024 * 16];
- static uint32_t typePoolIndex;
- Type *pushType(TypeType type)
- {
- Type *res = &typePool[typePoolIndex++];
- res->type = type;
- return res;
- }
- struct Local
- {
- Token name;
- Type *type;
- uint16_t stackOffset;
- };
- struct Codegen
- {
- Local locals[128];
- uint32_t numLocals;
- uint16_t stackTop;
- uint16_t code[1024];
- uint32_t codeLen;
- };
- enum Op
- {
- Op_Invalid,
- Op_LocalRef,
- Op_SliceRef,
- Op_MakeSlice,
- Op_PopSlice,
- Op_LoadSlice,
- Op_StoreSlice,
- Op_DropSlice,
- Op_ImmInt,
- Op_PopInt,
- Op_LoadInt,
- Op_StoreInt,
- Op_AddInt,
- Op_SubInt,
- Op_MulInt,
- Op_PrintInt,
- Op_Return,
- };
- void emit0(Codegen *c, Op op)
- {
- c->code[c->codeLen + 0] = (uint16_t)op;
- c->codeLen += 1;
- }
- void emit1(Codegen *c, Op op, uint16_t a0)
- {
- c->code[c->codeLen + 0] = (uint16_t)op;
- c->code[c->codeLen + 1] = a0;
- c->codeLen += 2;
- }
- void emit2(Codegen *c, Op op, uint16_t a0, uint16_t a1)
- {
- c->code[c->codeLen + 0] = (uint16_t)op;
- c->code[c->codeLen + 1] = a0;
- c->code[c->codeLen + 2] = a1;
- c->codeLen += 3;
- }
- Type *compileType(Codegen *c, Ast *ast)
- {
- switch (ast->type) {
- case Ast_Ident: {
- if (ast->ident.name.end - ast->ident.name.begin == 3 && !memcmp(ast->ident.name.scanner->source + ast->ident.name.begin, "Int", 3)) {
- return &intType;
- } else {
- errorAt(ast->token, "Unknown type name");
- }
- }
- }
- errorAt(ast->token, "Unknown type");
- return NULL;
- }
- Type *compileLValue(Codegen *c, Ast *ast);
- Type *compileRValue(Codegen *c, Ast *ast)
- {
- switch (ast->type) {
- case Ast_Call: {
- Type *argTypes[32];
- for (uint32_t i = 0; i < ast->call.numArgs; i++) {
- argTypes[i] = compileRValue(c, ast->call.args + i);
- }
- if (ast->call.func->type == Ast_Ident
- && ast->call.func->ident.name.end - ast->call.func->ident.name.begin == 5
- && !memcmp(ast->call.func->ident.name.scanner->source + ast->call.func->ident.name.begin, "print", 5)) {
- if (ast->call.numArgs != 1) {
- errorAt(ast->token, "Invalid amount of arguments to print");
- }
- if (argTypes[0]->type == Type_Int) {
- emit0(c, Op_PrintInt);
- } else {
- errorAt(ast->call.args[0].token, "Invalid type to print");
- }
- } else {
- errorAt(ast->call.func->token, "Unimplemented");
- }
- return &unitType;
- } break;
- case Ast_Number: {
- int value = 0;
- for (uint32_t i = ast->number.value.begin; i != ast->number.value.end; i++)
- value = value * 10 + (ast->number.value.scanner->source[i] - '0');
- emit1(c, Op_ImmInt, (uint16_t)(int16_t)value);
- return &intType;
- } break;
- case Ast_New: {
- Type *sliceType = pushType(Type_Slice);
- sliceType->slice.type = compileType(c, ast->new_.type);
- compileRValue(c, ast->new_.count);
- emit1(c, Op_MakeSlice, typeSize(sliceType->slice.type));
- return sliceType;
- } break;
- case Ast_Ident:
- case Ast_Index: {
- Type *type = compileLValue(c, ast);
- if (type->type == Type_Int) {
- emit0(c, Op_LoadInt);
- } else if (type->type == Type_Slice) {
- emit0(c, Op_LoadSlice);
- } else {
- errorAt(ast->token, "Invalid rvalue type");
- }
- return type;
- } break;
- case Ast_Paren: {
- return compileRValue(c, ast->paren.expr);
- } break;
- case Ast_Binop: {
- Type *lType = compileRValue(c, ast->binop.left);
- Type *rType = compileRValue(c, ast->binop.right);
- if (!typeEqual(lType, rType)) {
- errorAt(ast->token, "Type mismatch");
- }
- if (lType->type == Type_Int) {
- Op op = Op_Invalid;
- switch (ast->binop.op.type) {
- case Tok_Add: op = Op_AddInt; break;
- case Tok_Sub: op = Op_SubInt; break;
- case Tok_Mul: op = Op_MulInt; break;
- default:
- errorAt(ast->binop.op, "Invalid operator");
- }
- emit0(c, op);
- }
- return lType;
- } break;
- }
- errorAt(ast->token, "Invalid rvalue");
- return NULL;
- }
- Type *compileLValue(Codegen *c, Ast *ast)
- {
- switch (ast->type) {
- case Ast_Ident: {
- uint32_t i;
- for (i = c->numLocals; i > 0; --i) {
- Local *local = &c->locals[i - 1];
- if (tokenEqual(&local->name, &ast->ident.name)) break;
- }
- if (i == 0) {
- errorAt(ast->ident.name, "undefined variable");
- }
- Local *local = &c->locals[i - 1];
- emit1(c, Op_LocalRef, local->stackOffset);
- return local->type;
- } break;
- case Ast_Index: {
- Type *sliceType = compileLValue(c, ast->index.left);
- if (sliceType->type == Type_Slice) {
- Type *indexType = compileRValue(c, ast->index.index);
- if (indexType->type != Type_Int) {
- errorAt(ast->index.index->token, "Index type is not an integer");
- }
- emit1(c, Op_SliceRef, (uint16_t)typeSize(sliceType->slice.type));
- return sliceType->slice.type;
- } else {
- errorAt(ast->token, "Cannot index type");
- }
- } break;
- }
- errorAt(ast->token, "Invalid lvalue");
- return NULL;
- }
- void compileStmt(Codegen *c, Ast *ast)
- {
- switch (ast->type) {
- case Ast_Var: {
- Type *exprType = compileRValue(c, ast->var.expr);
- emit1(c, Op_LocalRef, c->stackTop);
- if (exprType->type == Type_Int) {
- emit0(c, Op_StoreInt);
- } else if (exprType->type == Type_Slice) {
- emit0(c, Op_StoreSlice);
- } else {
- errorAt(ast->token, "Invalid expression type");
- }
- c->locals[c->numLocals].name = ast->var.name;
- c->locals[c->numLocals].stackOffset = c->stackTop;
- c->locals[c->numLocals].type = exprType;
- c->numLocals++;
- c->stackTop += (typeSize(exprType) + 7) & 7;
- } break;
- case Ast_Assign: {
- Type *rType = compileRValue(c, ast->assign.right);
- Type *lType = compileLValue(c, ast->assign.left);
- if (!typeEqual(lType, rType)) {
- errorAt(ast->token, "Type mismatch");
- }
- if (lType->type == Type_Int) {
- emit0(c, Op_StoreInt);
- } else if (lType->type == Type_Slice) {
- emit0(c, Op_StoreSlice);
- } else {
- errorAt(ast->token, "Invalid expression type");
- }
- } break;
- case Ast_Block: {
- uint32_t prevTop = c->stackTop;
- uint32_t prevNum = c->numLocals;
- for (uint32_t i = 0; i < ast->block.numStmt; i++)
- compileStmt(c, ast->block.stmt + i);
- for (uint32_t i = c->numLocals; i > prevNum; --i) {
- Local *local = &c->locals[i - 1];
- if (local->type->type == Type_Slice) {
- emit1(c, Op_LocalRef, local->stackOffset);
- emit0(c, Op_DropSlice);
- }
- }
- c->numLocals = prevNum;
- c->stackTop = prevTop;
- } break;
- default: {
- Type *type = compileRValue(c, ast);
- if (type->type == Type_Int) {
- emit0(c, Op_PopInt);
- } else if (type->type == Type_Slice) {
- emit0(c, Op_PopSlice);
- } else if (type->type == Type_Unit) {
- /* Nop */
- } else {
- errorAt(ast->token, "Invalid expression type");
- }
- }
- }
- }
- void compileTop(Codegen *c, Ast *ast)
- {
- switch (ast->type) {
- case Ast_Def: {
- compileStmt(c, ast->def.block);
- emit0(c, Op_Return);
- } break;
- }
- }
- void printDisassembly(const uint16_t *code, uint32_t length)
- {
- const uint16_t *end = code + length;
- while (code != end) {
- switch (*code) {
- case Op_Invalid: printf("invalid"); code++; break;
- case Op_LocalRef: printf("ref.local %u", code[1]); code += 2; break;
- case Op_SliceRef: printf("ref.slice %u", code[1]); code += 2; break;
- case Op_MakeSlice: printf("slice.make %u", code[1]); code += 2; break;
- case Op_PopSlice: printf("slice.pop"); code++; break;
- case Op_LoadSlice: printf("slice.load"); code++; break;
- case Op_StoreSlice: printf("slice.store"); code++; break;
- case Op_DropSlice: printf("slice.drop"); code++; break;
- case Op_ImmInt: printf("int.imm %d", (int)(int16_t)code[1]); code += 2; break;
- case Op_PopInt: printf("int.pop"); code++; break;
- case Op_LoadInt: printf("int.load"); code++; break;
- case Op_StoreInt: printf("int.store"); code++; break;
- case Op_AddInt: printf("int.add"); code++; break;
- case Op_SubInt: printf("int.sub"); code++; break;
- case Op_MulInt: printf("int.mul"); code++; break;
- case Op_PrintInt: printf("int.print"); code++; break;
- case Op_Return: printf("return"); code++; break;
- }
- putchar('\n');
- }
- }
- void execute(const uint16_t *code)
- {
- char localStack[1024];
- void *refStack[16];
- uint32_t refTop = 0;
- int32_t intStack[16];
- int32_t intTop = 0;
- char structStack[128];
- uint32_t structTop = 0;
- for (;;) {
- switch (*code) {
- case Op_Invalid: {
- assert(0);
- } break;
- case Op_LocalRef: {
- refStack[refTop++] = localStack + code[1];
- code += 2;
- } break;
- case Op_SliceRef: {
- Slice *slice = (Slice*)refStack[refTop - 1];
- int32_t index = intStack[intTop - 1];
- assert((uint32_t)index < slice->count);
- refStack[refTop - 1] = (char*)slice->data + slice->offset + code[1] * index;
- intTop--;
- code += 2;
- } break;
- case Op_MakeSlice: {
- Slice slice;
- int32_t count = intStack[intTop - 1];
- slice.data = calloc(count, code[1]);
- slice.offset = 0;
- slice.count = count;
- memcpy(structStack + structTop, &slice, sizeof(Slice));
- structTop += sizeof(Slice);
- intTop--;
- code += 2;
- } break;
- case Op_PopSlice: {
- structTop -= sizeof(Slice);
- refTop--;
- code++;
- } break;
- case Op_LoadSlice: {
- Slice *slice = (Slice*)refStack[refTop - 1];
- memcpy(structStack + structTop, slice, sizeof(Slice));
- structTop += sizeof(Slice);
- refTop--;
- code++;
- } break;
- case Op_StoreSlice: {
- Slice *slice = (Slice*)refStack[refTop - 1];
- structTop -= sizeof(Slice);
- memcpy(slice, structStack + structTop, sizeof(Slice));
- refTop--;
- code++;
- } break;
- case Op_DropSlice: {
- Slice *slice = (Slice*)refStack[refTop - 1];
- free(slice->data);
- refTop--;
- code++;
- } break;
- case Op_ImmInt: {
- intStack[intTop] = (int16_t)code[1];
- intTop++;
- code += 2;
- } break;
- case Op_PopInt: {
- intTop--;
- code++;
- } break;
- case Op_LoadInt: {
- intStack[intTop] = *(int32_t*)refStack[refTop - 1];
- intTop++;
- refTop--;
- code++;
- } break;
- case Op_StoreInt: {
- *(int32_t*)refStack[refTop - 1] = intStack[intTop - 1];
- intTop--;
- code++;
- } break;
- case Op_AddInt: {
- intStack[intTop - 2] = intStack[intTop - 2] + intStack[intTop - 1];
- intTop--;
- code++;
- } break;
- case Op_SubInt: {
- intStack[intTop - 2] = intStack[intTop - 2] - intStack[intTop - 1];
- intTop--;
- code++;
- } break;
- case Op_MulInt: {
- intStack[intTop - 2] = intStack[intTop - 2] * intStack[intTop - 1];
- intTop--;
- code++;
- } break;
- case Op_PrintInt: {
- printf("%d\n", intStack[intTop - 1]);
- intTop--;
- code++;
- } break;
- case Op_Return: {
- return;
- } break;
- }
- }
- }
- const char *testSrc = R"(
- def main() {
- var data = new Int[2]
- data[0] = (1 + 2) * 3
- data[1] = 1 + 2 * 3
- print(data[0] - data[1])
- }
- )";
- int main(int argc, char **argv)
- {
- Scanner scanner;
- scanner.filename = "test";
- scanner.source = testSrc;
- scanner.pos = scanner.source;
- Ast *ast = parse(&scanner);
- printAst(ast, 0);
- Codegen codegen = { };
- compileTop(&codegen, &ast->block.stmt[0]);
- printDisassembly(codegen.code, codegen.codeLen);
- execute(codegen.code);
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement