Author: mesyeti <mesyeti@mesyeti.uk>
add return statement
basic-std/std/string.bas | 16 ++++++++++++++++ basic/source/compiler.c | 1 + basic/source/compiler.h | 1 + basic/source/frontend/c89.c | 9 ++++++++- basic/source/lexer.c | 6 +++++- basic/source/lexer.h | 1 + basic/source/parser.c | 19 +++++++++++++++++++ basic/source/parser.h | 9 ++++++++- basic/source/semanticAnalysis.c | 34 ++++++++++++++++++++++++++++------ basic/test.bas | 7 +++++--
diff --git a/basic/source/compiler.c b/basic/source/compiler.c index be44878fc65b5df8a663184962e55f7e58d23efc..072ca73bd890e46aea621791e1360e012bb54ced 100644 --- a/basic/source/compiler.c +++ b/basic/source/compiler.c @@ -21,6 +21,7 @@ case NODE_DIM: frontend.compileDim(&node->dim); break; case NODE_EXTERN: frontend.compileExtern(&node->external); break; case NODE_IF: frontend.compileIf(&node->ifStat); break; case NODE_WHILE: frontend.compileWhile(&node->whileStat); break; + case NODE_RETURN: frontend.compileReturn(&node->ret); break; case NODE_BINARY_OP: { if (node->bin.op == TOKEN_ASSIGN) { frontend.compileAssign(&node->bin); diff --git a/basic/source/compiler.h b/basic/source/compiler.h index 7cbc036cf50b6ad3ce9329f9063de654d0cdc20f..2eb287227d27604cf79181892b55e170c0121c78 100644 --- a/basic/source/compiler.h +++ b/basic/source/compiler.h @@ -13,6 +13,7 @@ void (*compileExtern)(ExternNode* node); void (*compileIf)(IfNode* node); void (*compileAssign)(BinaryNode* node); void (*compileWhile)(WhileNode* node); + void (*compileReturn)(ReturnNode* node); } Frontend; void Frontend_Init(Frontend p_frontend); diff --git a/basic/source/frontend/c89.c b/basic/source/frontend/c89.c index 7f31c59e4d8756607456a1a398d947edb0273c77..e43c247e61169a45b121bef627ea133e6adcf3af 100644 --- a/basic/source/frontend/c89.c +++ b/basic/source/frontend/c89.c @@ -261,6 +261,12 @@ fprintf(out, "} nitron_%s;", type->name); } +static void CompileReturn(ReturnNode* node) { + fprintf(out, "return "); + CompileExprNode(node->node); + fprintf(out, ";\n"); +} + Frontend Frontend_C89() { char* path = ConcatString(options.out, ".c"); @@ -332,6 +338,7 @@ .compileFuncCall = &CompileFuncCall, .compileExtern = &CompileExtern, .compileIf = &CompileIf, .compileAssign = &CompileAssign, - .compileWhile = &CompileWhile + .compileWhile = &CompileWhile, + .compileReturn = &CompileReturn }; } diff --git a/basic/source/lexer.c b/basic/source/lexer.c index 2f729de40820e9a1df853dc5ff5598c062812166..f299bbce43069c349f3be6346898beb3a7c8187b 100644 --- a/basic/source/lexer.c +++ b/basic/source/lexer.c @@ -197,7 +197,8 @@ {"do", TOKEN_DO}, {"type", TOKEN_TYPE}, {"union", TOKEN_UNION}, {"program", TOKEN_PROGRAM}, - {"import", TOKEN_IMPORT} + {"import", TOKEN_IMPORT}, + {"return", TOKEN_RETURN} }; for (size_t i = 0; i < sizeof(keywords) / sizeof(Keyword); ++ i) { @@ -232,6 +233,9 @@ case TOKEN_WHILE: return "while"; case TOKEN_DO: return "do"; case TOKEN_TYPE: return "type"; case TOKEN_UNION: return "union"; + case TOKEN_PROGRAM: return "program"; + case TOKEN_IMPORT: return "import"; + case TOKEN_RETURN: return "return"; case TOKEN_IDENTIFIER: return "identifier"; case TOKEN_STRING: return "string"; case TOKEN_INT: return "int"; diff --git a/basic/source/lexer.h b/basic/source/lexer.h index f83f268cf819277e0caf9781d9332cba025e9c6e..51ca0c421bfd058f71baa5718e2da06105738e5d 100644 --- a/basic/source/lexer.h +++ b/basic/source/lexer.h @@ -26,6 +26,7 @@ TOKEN_TYPE, TOKEN_UNION, TOKEN_PROGRAM, TOKEN_IMPORT, + TOKEN_RETURN, // misc TOKEN_IDENTIFIER, diff --git a/basic/source/parser.c b/basic/source/parser.c index 2a585fc994f18509254620a874fd36f3069027f9..e1783ab6ee4a5e007d49a3464ba2d24b692a56ed 100644 --- a/basic/source/parser.c +++ b/basic/source/parser.c @@ -682,6 +682,20 @@ node.import = ret; return node; } +static Node ParseReturn(Parser* p) { + ReturnNode ret; + ret.i = INFO(NODE_RETURN); + + Advance(p); + ret.node = NodeToHeap(ParseBinary(p)); + + Expect(p, TOKEN_LINE); + + Node node; + node.ret = ret; + return node; +} + static Node ParseNode(Parser* p) { switch (p->tokens[p->i].type) { case TOKEN_FUNC: @@ -693,6 +707,7 @@ case TOKEN_WHILE: return ParseWhile(p); case TOKEN_TYPE: return ParseTypeDef(p); case TOKEN_PROGRAM: return ParseProgram(p); case TOKEN_IMPORT: return ParseImport(p); + case TOKEN_RETURN: return ParseReturn(p); case TOKEN_LPAREN: case TOKEN_ACCESS: case TOKEN_IDENTIFIER: { @@ -1014,6 +1029,10 @@ break; } case NODE_IMPORT: { free(node->import.name); + break; + } + case NODE_RETURN: { + Parser_FreeNode(node->ret.node); break; } default: return; diff --git a/basic/source/parser.h b/basic/source/parser.h index 0bb03b42b3ad8fce6e3750b92757feabd3ccfe04..cd7ea068f2d262169b953c609cd28f97bdb95784 100644 --- a/basic/source/parser.h +++ b/basic/source/parser.h @@ -22,7 +22,8 @@ NODE_WHILE, NODE_TYPE_DEF, NODE_TYPE_BLOCK, NODE_PROGRAM, - NODE_IMPORT + NODE_IMPORT, + NODE_RETURN } NodeType; typedef struct { @@ -142,6 +143,11 @@ NodeInfo i; char* name; } ImportNode; +typedef struct { + NodeInfo i; + Node* node; +} ReturnNode; + union Node { NodeInfo i; IntNode integer; @@ -159,6 +165,7 @@ WhileNode whileStat; TypeDefNode typeDef; TypeBlockNode typeBlock; ImportNode import; + ReturnNode ret; }; typedef struct { diff --git a/basic/source/semanticAnalysis.c b/basic/source/semanticAnalysis.c index 4f06c5c0abcf1332f55b78d69b6df72c7cfe7450..1235acabde83d5a7bd24ee4802f0f4808b4c0974 100644 --- a/basic/source/semanticAnalysis.c +++ b/basic/source/semanticAnalysis.c @@ -7,6 +7,8 @@ #include "state.h" #include "parser.h" #include "semanticAnalysis.h" +static Function* thisFunc = NULL; + void SemanticAnalysis_Init(size_t wordSize) { State_Init(); @@ -31,6 +33,8 @@ Type type; type.name = NewString("unit"); type.type = TYPE_UNIT; State_AddType(type); + + thisFunc = NULL; } void Expect(Node* node, NodeType type) { @@ -79,19 +83,23 @@ #define GET_PRIM(NAME, PTR) \ ((UsedType) {(PTR), State_GetType(NAME) - state.types, 0}) -static UsedType EvalAssign(Node* node, UsedType left, UsedType right) { +static bool AssignCompatible(UsedType left, UsedType right) { Type* leftType = State_GetTypeFromUsed(left); Type* rightType = State_GetTypeFromUsed(right); - - bool compatible = true; if ((left.ptr != right.ptr) || (leftType->type != rightType->type)) { - compatible = false; + return false; } else if (leftType->type == TYPE_PRIM) { - if (leftType->primType != rightType->primType) compatible = false; - else if (leftType->size < rightType->size) compatible = false; + if (leftType->primType != rightType->primType) return false; + else if (leftType->size < rightType->size) return false; } + + return true; +} + +static UsedType EvalAssign(Node* node, UsedType left, UsedType right) { + bool compatible = AssignCompatible(left, right); if (!compatible) { PrintError( @@ -353,7 +361,9 @@ State_AddVar(var); } for (size_t i = 0; i < node->funcDef.bodyLen; ++ i) { + thisFunc = &func; SemanticAnalysis_EvalType(&node->funcDef.body[i]); + thisFunc = NULL; } inFunc = false; State_FreeScope(); @@ -499,6 +509,18 @@ return GET_PRIM("unit", 0); } case NODE_PROGRAM: return GET_PRIM("unit", 0); case NODE_IMPORT: return GET_PRIM("unit", 0); + case NODE_RETURN: { + if (!inFunc) { + PrintError(node->i.err, "Return statement outside of function"); + } + + UsedType type = SemanticAnalysis_EvalType(node->ret.node); + + if (AssignCompatible(thisFunc->ret, type)) { + PrintError(node->i.err, "Return type does not match function type"); + } + return GET_PRIM("unit", 0); + } default: { Unexpected(node); } diff --git a/basic/test.bas b/basic/test.bas index 532d91881fffa19498acf9852c9bc48d1077876e..5efc554e8f2f83da16dc67a388ca4deac79a44ac 100644 --- a/basic/test.bas +++ b/basic/test.bas @@ -5,6 +5,9 @@ extern func puts(str as ptr(char)) i32 extern func printf(str as ptr(char), val as int) i32 -import lib +func add(a as int, b as int) i32 + return a + b +end -PrintStrLn("hello world!") +printf("2 + 2 = %d\n", add(2, 2)) +printf("2 + 3 = %d\n", add(2, 3)) diff --git a/basic-std/std/string.bas b/basic-std/std/string.bas new file mode 100644 index 0000000000000000000000000000000000000000..7846d0e933f514872229c0524e98165f35fc1b9f --- /dev/null +++ b/basic-std/std/string.bas @@ -0,0 +1,16 @@ +'NITRON + +func StringLen(str as ptr(char)) int + dim ret as int + + while ^str != 0 do + ret = ret + 1 + str = str + 1 + end + + return ret +end + +func StringEq(str1 as ptr(char), str2 as ptr(char)) bool + +end