Author: mesyeti <mesyeti@mesyeti.uk>
refactor function call parsing
basic-std/std/io.bas | 2 basic/source/compiler.c | 23 +++-- basic/source/compiler.h | 2 basic/source/frontend/c89.c | 28 +++++- basic/source/lexer.c | 6 + basic/source/lexer.h | 2 basic/source/parser.c | 83 +++++++++++++++++--- basic/source/parser.h | 13 ++ basic/source/semanticAnalysis.c | 137 ++++++++++++++++++++++------------ basic/source/state.c | 31 +------ basic/source/state.h | 40 +++++---- basic/test2.bas | 4
diff --git a/basic/source/compiler.c b/basic/source/compiler.c index 072ca73bd890e46aea621791e1360e012bb54ced..ad14a7482ad0738f79589c9ed02bdc5e08e51b54 100644 --- a/basic/source/compiler.c +++ b/basic/source/compiler.c @@ -14,17 +14,19 @@ } void Compiler_CompileBodyNode(Node* node) { switch (node->i.type) { - - case NODE_FUNC_CALL: frontend.compileFuncCall(&node->funcCall); break; - case NODE_FUNC_DEF: frontend.compileFuncDef(&node->funcDef); break; - 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_FUNC_DEF: frontend.compileFuncDef(&node->funcDef); break; + 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); + break; + } + else if (node->bin.op == TOKEN_LPAREN) { + frontend.compileFuncCall(&node->bin); break; } } // fall through @@ -44,12 +46,15 @@ case NODE_TYPE_DEF: break; case NODE_TYPE_BLOCK: break; case NODE_PROGRAM: break; case NODE_IMPORT: break; - case NODE_FUNC_CALL: frontend.compileFuncCall(&node->funcCall); break; case NODE_IF: frontend.compileIf(&node->ifStat); break; case NODE_WHILE: frontend.compileWhile(&node->whileStat); break; case NODE_BINARY_OP: { if (node->bin.op == TOKEN_ASSIGN) { frontend.compileAssign(&node->bin); + break; + } + else if (node->bin.op == TOKEN_LPAREN) { + frontend.compileFuncCall(&node->bin); break; } } // fall through diff --git a/basic/source/compiler.h b/basic/source/compiler.h index 2eb287227d27604cf79181892b55e170c0121c78..471c75bedd63c48688dc0a0d87a7117bf44a72b3 100644 --- a/basic/source/compiler.h +++ b/basic/source/compiler.h @@ -8,7 +8,7 @@ void (*finish)(bool program); void (*beginMain)(void); void (*compileFuncDef)(FuncDefNode* node); void (*compileDim)(DimNode* node); - void (*compileFuncCall)(FuncCallNode* node); + void (*compileFuncCall)(BinaryNode* node); void (*compileExtern)(ExternNode* node); void (*compileIf)(IfNode* node); void (*compileAssign)(BinaryNode* node); diff --git a/basic/source/frontend/c89.c b/basic/source/frontend/c89.c index e43c247e61169a45b121bef627ea133e6adcf3af..8a88fe5c2d03d09db7aec0a358f2f3d18013d88e 100644 --- a/basic/source/frontend/c89.c +++ b/basic/source/frontend/c89.c @@ -98,7 +98,7 @@ static void CompileExprNode(Node* node); static void CompileFuncCallExpr(FuncCallNode* node) { - fprintf(out, "%s(", node->func); + fprintf(out, "("); for (size_t i = 0; i < node->paramsNum; ++ i) { CompileExprNode(&node->params[i]); @@ -142,6 +142,7 @@ fprintf(out, "."); } break; } + case TOKEN_LPAREN: break; // function call, nothing to do default: assert(0); } @@ -165,13 +166,16 @@ CompileExprNode(node->unary.operand); fprintf(out, ")"); break; } - case NODE_FUNC_CALL: CompileFuncCallExpr(&node->funcCall); break; + case NODE_FUNC_CALL: CompileFuncCallExpr(&node->bin.right->funcCall); break; default: assert(0); } } -static void CompileFuncCall(FuncCallNode* node) { - CompileFuncCallExpr(node); +static void CompileFuncCall(BinaryNode* node) { + Node node2; + node2.bin = *node; + + CompileExprNode(&node2); fprintf(out, ";\n"); } @@ -298,15 +302,25 @@ } // declare all globals for (size_t i = 0; i < state.scopeSize[0]; ++ i) { - Var* var = &state.scopes[0][i]; + Var* var = &state.scopes[0][i]; + Type* varType = State_GetTypeFromUsed(var->type); + + if (varType->type == TYPE_FUNC) continue; CompileUsedType(var->type); fprintf(out, " nitron_%s;\n", var->name); } // declare all functions - for (size_t i = 0; i < state.funcNum; ++ i) { - Function* func = &state.funcs[i]; + for (size_t i = 0; i < state.scopeSize[0]; ++ i) { + Var* var = &state.scopes[0][i]; + Type* varType = State_GetTypeFromUsed(var->type); + + if ((var->type.ptr > 0) || (var->type.array > 0) || (varType->type != TYPE_FUNC)) { + continue; + } + + Function* func = &varType->func; if (func->sub) { fprintf(out, "void"); diff --git a/basic/source/lexer.c b/basic/source/lexer.c index f299bbce43069c349f3be6346898beb3a7c8187b..9d5185d1937492c9c9dcf83cf7da9c350119df2a 100644 --- a/basic/source/lexer.c +++ b/basic/source/lexer.c @@ -147,7 +147,9 @@ case '>': *token = TOKEN(TOKEN_GREATER, NULL); return LEXER_TOKEN; case '&': *token = TOKEN(TOKEN_ADDRESS, NULL); return LEXER_TOKEN; case '^': *token = TOKEN(TOKEN_ACCESS, NULL); return LEXER_TOKEN; case '\n': *token = TOKEN(TOKEN_LINE, NULL); return LEXER_TOKEN; - case '\'': { + case '[': *token = TOKEN(TOKEN_LSQUARE, NULL); return LEXER_TOKEN; + case ']': *token = TOKEN(TOKEN_RSQUARE, NULL); return LEXER_TOKEN; + case '\'': { // comment while (true) { GET_CHAR(ch); @@ -244,6 +246,8 @@ case TOKEN_LPAREN: return "lparen"; case TOKEN_RPAREN: return "rparen"; case TOKEN_DOT: return "dot"; case TOKEN_COMMA: return "comma"; + case TOKEN_LSQUARE: return "left square"; + case TOKEN_RSQUARE: return "right square"; case TOKEN_ADD: return "add"; case TOKEN_SUBTRACT: return "subtract"; case TOKEN_MULTIPLY: return "multiply"; diff --git a/basic/source/lexer.h b/basic/source/lexer.h index 51ca0c421bfd058f71baa5718e2da06105738e5d..3e69d894e04c7addcd8704162ca225d804184f27 100644 --- a/basic/source/lexer.h +++ b/basic/source/lexer.h @@ -39,6 +39,8 @@ TOKEN_LPAREN, TOKEN_RPAREN, TOKEN_DOT, TOKEN_COMMA, + TOKEN_LSQUARE, + TOKEN_RSQUARE, // operators TOKEN_ADD, diff --git a/basic/source/parser.c b/basic/source/parser.c index e1783ab6ee4a5e007d49a3464ba2d24b692a56ed..b0c758165c06d351f4e31a0c0f9a51cefb78376b 100644 --- a/basic/source/parser.c +++ b/basic/source/parser.c @@ -91,11 +91,6 @@ Advance(p); switch (token->type) { case TOKEN_IDENTIFIER: { - if (p->tokens[p->i].type == TOKEN_LPAREN) { - -- p->i; - return ParseFuncCall(p); - } - ret.ident = (IdentifierNode) {INFO(NODE_IDENTIFIER), NewString(token->contents)}; return ret; } @@ -134,6 +129,33 @@ default: return false; } } +static Node ParseFuncArray(Parser* p) { + Node left = ParseAtom(p); + + while ((p->tokens[p->i].type == TOKEN_LPAREN) || (p->tokens[p->i].type == TOKEN_LSQUARE)) { + if (p->tokens[p->i].type == TOKEN_LPAREN) { // function call + Node callNode = ParseFuncCall(p); // parse parameter list + + left.bin = (BinaryNode) { + INFO(NODE_BINARY_OP), NodeToHeap(left), NodeToHeap(callNode), TOKEN_LPAREN + }; + } + else { // array access + Advance(p); + Node idxNode = ParseBinary(p); + + Expect(p, TOKEN_RSQUARE); + Advance(p); + + left.bin = (BinaryNode) { + INFO(NODE_BINARY_OP), NodeToHeap(left), NodeToHeap(idxNode), TOKEN_LSQUARE + }; + } + } + + return left; +} + static Node ParseUnary(Parser* p) { Token* tok = &p->tokens[p->i]; @@ -150,7 +172,7 @@ }; return ret; } else { - return ParseAtom(p); + return ParseFuncArray(p); } } @@ -430,12 +452,21 @@ Expect(p, TOKEN_IDENTIFIER); ret.name = NewString(p->tokens[p->i].contents); Advance(p); + + if (p->tokens[p->i].type == TOKEN_LSQUARE) { + Advance(p); + ret.array = true; + ret.arrayLen = NodeToHeap(ParseBinary(p)); + + Expect(p, TOKEN_RSQUARE); + Advance(p); + } + Expect(p, TOKEN_AS); Advance(p); ret.varType = SafeMalloc(sizeof(Node)); *ret.varType = ParseType(p); - Advance(p); Expect(p, TOKEN_LINE); @@ -448,9 +479,7 @@ static Node ParseFuncCall(Parser* p) { FuncCallNode ret; ret.i = INFO(NODE_FUNC_CALL); - ret.func = NewString(p->tokens[p->i].contents); - Advance(p); Expect(p, TOKEN_LPAREN); Advance(p); @@ -717,8 +746,12 @@ } Node ret = ParseBinary(p); + // this if statement is sickening if ( - ((ret.i.type == NODE_BINARY_OP) && (ret.bin.op != TOKEN_ASSIGN)) || + ( + (ret.i.type == NODE_BINARY_OP) && (ret.bin.op != TOKEN_ASSIGN) && + (ret.bin.op != TOKEN_LPAREN) + ) || ((ret.i.type != NODE_BINARY_OP) && (ret.i.type != NODE_FUNC_CALL)) ) { PrintError(p->tokens[p->i].err, "Unexpected %s", Parser_TypeStr(ret.i.type)); @@ -778,6 +811,7 @@ case TOKEN_LESS: printf("<"); break; case TOKEN_GREATER: printf(">"); break; case TOKEN_ASSIGN: printf("="); break; case TOKEN_DOT: printf("."); break; + case TOKEN_LPAREN: printf(""); break; default: assert(0); } @@ -819,13 +853,20 @@ puts("end"); break; } case NODE_DIM: { - printf("dim %s as ", node->dim.name); + printf("dim %s", node->dim.name); + + if (node->dim.array) { + printf(" "); + Parser_PrintNode(node->dim.arrayLen); + } + + printf(" as "); Parser_PrintNode(node->dim.varType); puts(""); break; } case NODE_FUNC_CALL: { - printf("%s(", node->funcCall.func); + printf("("); for (size_t i = 0; i < node->funcCall.paramsNum; ++ i) { Parser_PrintNode(&node->funcCall.params[i]); @@ -900,6 +941,13 @@ break; } case NODE_IMPORT: { printf("import %s\n", node->import.name); + break; + } + case NODE_ARRAY: { + Parser_PrintNode(node->array.array); + putchar('['); + Parser_PrintNode(node->array.idx); + putchar(']'); break; } default: { @@ -984,11 +1032,13 @@ case NODE_DIM: { free(node->dim.name); Parser_FreeNode(node->dim.varType); free(node->dim.varType); + + if (node->dim.array) { + Parser_FreeNode(node->dim.arrayLen); + } break; } case NODE_FUNC_CALL: { - free(node->funcCall.func); - for (size_t i = 0; i < node->funcCall.paramsNum; ++ i) { Parser_FreeNode(&node->funcCall.params[i]); } @@ -1033,6 +1083,11 @@ break; } case NODE_RETURN: { Parser_FreeNode(node->ret.node); + break; + } + case NODE_ARRAY: { + Parser_FreeNode(node->array.array); + Parser_FreeNode(node->array.idx); break; } default: return; diff --git a/basic/source/parser.h b/basic/source/parser.h index cd7ea068f2d262169b953c609cd28f97bdb95784..44d7f5966696bb6110814a2ea14725cbc7ff4b7d 100644 --- a/basic/source/parser.h +++ b/basic/source/parser.h @@ -23,7 +23,8 @@ NODE_TYPE_DEF, NODE_TYPE_BLOCK, NODE_PROGRAM, NODE_IMPORT, - NODE_RETURN + NODE_RETURN, + NODE_ARRAY } NodeType; typedef struct { @@ -89,11 +90,12 @@ typedef struct { NodeInfo i; char* name; Node* varType; + bool array; + Node* arrayLen; } DimNode; typedef struct { NodeInfo i; - char* func; Node* params; size_t paramsNum; } FuncCallNode; @@ -148,6 +150,12 @@ NodeInfo i; Node* node; } ReturnNode; +typedef struct { + NodeInfo i; + Node* array; + Node* idx; +} ArrayNode; + union Node { NodeInfo i; IntNode integer; @@ -166,6 +174,7 @@ TypeDefNode typeDef; TypeBlockNode typeBlock; ImportNode import; ReturnNode ret; + ArrayNode array; }; typedef struct { diff --git a/basic/source/semanticAnalysis.c b/basic/source/semanticAnalysis.c index 1235acabde83d5a7bd24ee4802f0f4808b4c0974..1a382c2409465ec9bcad45e6b8db88e0ddc5e8d2 100644 --- a/basic/source/semanticAnalysis.c +++ b/basic/source/semanticAnalysis.c @@ -137,11 +137,67 @@ PrintError(node->i.err, "Type '%s' does not have member '%s'", leftType->name, member); return GET_PRIM("unit", 0); } +static UsedType EvalFuncCall(Node* node, UsedType left) { + Type* leftType = State_GetTypeFromUsed(left); + + if (leftType->type != TYPE_FUNC) { + PrintError(node->i.err, "Type '%s' cannot be called", leftType->name); + } + + assert(node->bin.right->i.type == NODE_FUNC_CALL); + + Node* call = node->bin.right; + Function* func = &leftType->func; + + if (func->paramsLen != call->funcCall.paramsNum) { + PrintError( + call->i.err, "Expected %d parameters, got %d", + func->paramsLen, call->funcCall.paramsNum + ); + } + + for (size_t i = 0; i < func->paramsLen; ++ i) { + UsedType type = SemanticAnalysis_EvalType(&call->funcCall.params[i]); + UsedType param = func->params[i].type; + Type* paramType = State_GetTypeFromUsed(param); + Type* callType = State_GetTypeFromUsed(type); + + bool paramLit = strcmp(callType->name, "__lit") == 0; + + if (!State_UsedTypeEq(type, param)) { + if ( + (callType->type == TYPE_PRIM) && (paramType->type == TYPE_PRIM) && + (callType->primType == paramType->primType) && + (paramType->size >= callType->size) + ) { + continue; + } + + if (paramLit && (paramType->type == TYPE_PRIM)) continue; + + PrintError(call->i.err, + "Expected %s for parameter %s, got %s", + paramType->name, func->params[i].name, callType->name + ); + } + } + + if (func->sub) { + return GET_PRIM("unit", 0); + } + else { + return func->ret; + } +} + static UsedType EvalBinOp(Node* node) { UsedType left = SemanticAnalysis_EvalType(node->bin.left); if (node->bin.op == TOKEN_DOT) { return EvalDot(node, left); + } + if (node->bin.op == TOKEN_LPAREN) { + return EvalFuncCall(node, left); } UsedType right = SemanticAnalysis_EvalType(node->bin.right); @@ -346,7 +402,22 @@ PrintError(node->i.err, "Nested function definitions are not allowed"); } Function func = DecToFunc(node->funcDef.dec); - State_AddFunc(func); + + // create type for this function + Type type; + type.type = TYPE_FUNC; + type.name = NULL; + type.size = (size_t) -1; + type.func = func; + + size_t funcTypeIdx = State_AddType(type); + + // create variable for this function + Var funcVar; + funcVar.type = (UsedType) {0, funcTypeIdx, 0}; + funcVar.name = node->funcDef.dec.name; + + State_AddVar(funcVar); // now analyse the body State_AddScope(); @@ -369,52 +440,6 @@ inFunc = false; State_FreeScope(); return GET_PRIM("unit", 0); } - case NODE_FUNC_CALL: { - Function* func = State_GetFunc(node->funcCall.func); - if (!func) { - PrintError(node->i.err, "Function %s does not exist", node->funcCall.func); - } - - if (func->paramsLen != node->funcCall.paramsNum) { - PrintError( - node->i.err, "Expected %d parameters, got %d", - func->paramsLen, node->funcCall.paramsNum - ); - } - - for (size_t i = 0; i < func->paramsLen; ++ i) { - UsedType type = SemanticAnalysis_EvalType(&node->funcCall.params[i]); - UsedType param = func->params[i].type; - Type* paramType = State_GetTypeFromUsed(param); - Type* callType = State_GetTypeFromUsed(type); - - bool paramLit = strcmp(callType->name, "__lit") == 0; - - if (!State_UsedTypeEq(type, param)) { - if ( - (callType->type == TYPE_PRIM) && (paramType->type == TYPE_PRIM) && - (callType->primType == paramType->primType) && - (paramType->size >= callType->size) - ) { - continue; - } - - if (paramLit && (paramType->type == TYPE_PRIM)) continue; - - PrintError(node->i.err, - "Expected %s for parameter %s, got %s", - paramType->name, func->params[i].name, callType->name - ); - } - } - - if (func->sub) { - return GET_PRIM("unit", 0); - } - else { - return func->ret; - } - } case NODE_DIM: { Var var; var.type = SemanticAnalysis_NodeAsUsedType(node->dim.varType); @@ -428,7 +453,23 @@ PrintError(node->i.err, "Nested function definitions are not allowed"); } Function func = DecToFunc(node->funcDef.dec); - State_AddFunc(func); + + // create type for this function + Type type; + type.type = TYPE_FUNC; + type.name = NULL; + type.size = (size_t) -1; + type.func = func; + + size_t funcTypeIdx = State_AddType(type); + + // create variable for this function + Var funcVar; + funcVar.type = (UsedType) {0, funcTypeIdx, 0}; + funcVar.name = node->funcDef.dec.name; + + State_AddVar(funcVar); + return GET_PRIM("unit", 0); } case NODE_IF: { diff --git a/basic/source/state.c b/basic/source/state.c index 216160a16844058fa5187d8339e8479fa6181406..5cdc7e708e75eeffb2abc3afebb589af987f5e59 100644 --- a/basic/source/state.c +++ b/basic/source/state.c @@ -14,14 +14,14 @@ state.typeNum = 0; state.scopes[0] = NULL; state.scopeSize[0] = 0; state.scopeNum = 1; - state.funcs = NULL; - state.funcNum = 0; } -void State_AddType(Type type) { +size_t State_AddType(Type type) { ++ state.typeNum; state.types = SafeRealloc(state.types, state.typeNum * sizeof(Type)); state.types[state.typeNum - 1] = type; + + return state.typeNum - 1; } void State_AddVar(Var var) { @@ -43,12 +43,6 @@ state.scopes[state.scopeNum - 1] = NULL; return true; } -void State_AddFunc(Function func) { - ++ state.funcNum; - state.funcs = SafeRealloc(state.funcs, state.funcNum * sizeof(Function)); - state.funcs[state.funcNum - 1] = func; -} - void State_FreeScope(void) { Var* scope = state.scopes[state.scopeNum - 1]; size_t scopeNum = state.scopeSize[state.scopeNum - 1]; @@ -74,6 +68,8 @@ } Type* State_GetType(const char* name) { for (size_t i = 0; i < state.typeNum; ++ i) { + if (!state.types[i].name) continue; + if (strcmp(state.types[i].name, name) == 0) { return &state.types[i]; } @@ -82,16 +78,6 @@ return NULL; } -Function* State_GetFunc(const char* name) { - for (size_t i = 0; i < state.funcNum; ++ i) { - if (strcmp(state.funcs[i].name, name) == 0) { - return &state.funcs[i]; - } - } - - return NULL; -} - void State_MakePrimitive(const char* name, size_t size, int primType) { Type type; type.type = TYPE_PRIM; @@ -123,13 +109,6 @@ puts("GLOBALS"); puts("======="); for (size_t i = 0; i < state.scopeSize[0]; ++ i) { printf("- %s\n", state.scopes[0][i].name); - } - puts("\n"); - - puts("FUNCTIONS"); - puts("========="); - for (size_t i = 0; i < state.funcNum; ++ i) { - printf("- %s\n", state.funcs[i].name); } puts("\n"); } diff --git a/basic/source/state.h b/basic/source/state.h index decf9f57253ba9f349bcc40562a1dd26754b6492..d84934b50ebd589ab8c216db5de343191c424019 100644 --- a/basic/source/state.h +++ b/basic/source/state.h @@ -6,7 +6,8 @@ enum { TYPE_PRIM, // is this "primitive", or Primula the manul? TYPE_STRUCT, - TYPE_UNIT + TYPE_UNIT, + TYPE_FUNC }; enum { @@ -22,6 +23,19 @@ size_t array; // 0 if not array, contains length if not array } UsedType; typedef struct { + UsedType type; + char* name; +} FuncParam; + +typedef struct { + bool sub; + UsedType ret; + FuncParam* params; + size_t paramsLen; + char* name; +} Function; + +typedef struct { char* name; UsedType type; } TypeField; @@ -30,6 +44,8 @@ typedef struct { int type; char* name; size_t size; + + // TODO: put the stuff below into a union // only for "struct" types TypeField* structure; @@ -37,6 +53,9 @@ size_t structLen; // only for "primitive" types int primType; + + // only for "function" types + Function func; } Type; typedef struct { @@ -45,39 +64,22 @@ char* name; } Var; typedef struct { - UsedType type; - char* name; -} FuncParam; - -typedef struct { - bool sub; - UsedType ret; - FuncParam* params; - size_t paramsLen; - char* name; -} Function; - -typedef struct { Type* types; size_t typeNum; Var* scopes[16]; size_t scopeSize[16]; size_t scopeNum; - Function* funcs; - size_t funcNum; } State; extern State state; void State_Init(void); -void State_AddType(Type type); +size_t State_AddType(Type type); void State_AddVar(Var var); bool State_AddScope(void); -void State_AddFunc(Function func); void State_FreeScope(void); Var* State_GetVar(const char* name); Type* State_GetType(const char* name); -Function* State_GetFunc(const char* name); void State_MakePrimitive(const char* name, size_t size, int primType); bool State_UsedTypeEq(UsedType a, UsedType b); void State_DumpInfo(void); diff --git a/basic/test2.bas b/basic/test2.bas index 08fb2be0209cd470a4560c6a56948753682be1e5..cda0b34274133fe1842785c47369fd4b40b13e5e 100644 --- a/basic/test2.bas +++ b/basic/test2.bas @@ -1 +1,3 @@ -print(1+2+3+4) +'NITRON + +print("hello") diff --git a/basic-std/std/io.bas b/basic-std/std/io.bas index d751ab166b51048099aac4aa4d4f16ed1730d633..8d71472149b19410d55374414f249493717f056f 100644 --- a/basic-std/std/io.bas +++ b/basic-std/std/io.bas @@ -1,3 +1,5 @@ +'NITRON + extern func puts(str as ptr(char)) i32 extern func putchar(ch as char) i32