#include "parser.h" #include #include #include #include #include #include const char *PARSED_TOKEN_STRINGS[] = { "PARSED_TOKEN_NONE", "PARSED_TOKEN_ROOT", "PARSED_TOKEN_PARENTHESIS", "PARSED_TOKEN_FUNCTION_CALL", "PARSED_TOKEN_VALUE_STRING", "PARSED_TOKEN_VALUE_IDENTIFIER", "PARSED_TOKEN_DEFINE_VARIABLE", "PARSED_TOKEN_DEFINE_CONSTANT", "PARSED_TOKEN_EOL", "PARSED_TOKEN_COMMA", "PARSED_TOKEN_STRUCT", "PARSED_TOKEN_FUNCTION", "PARSED_TOKEN_FUNCTION_PARAMS", "PARSED_TOKEN_CODE_BODY", "PARSED_TOKEN_IMPORT", }; static const ParseOrder PARSE_ORDER[] = { { .ltr = true, .size = 2, .tokens = { TOKEN_OPERATOR_PARENTHESES_CLOSE, TOKEN_OPERATOR_CURLY_BRACKET_CLOSE, }, }, { .ltr = true, .size = 2, .tokens = { TOKEN_STRING, TOKEN_IDENTIFIER, }, }, { .ltr = true, .size = 3, .tokens = { TOKEN_OPERATOR_FUNCTION, TOKEN_KEYWORD_STRUCT, TOKEN_KEYWORD_IMPORT, }, }, { .ltr = true, .size = 3, .tokens = { TOKEN_OPERATOR_ASSIGN, TOKEN_OPERATOR_EQUAL, TOKEN_OPERATOR_COLON, }, }, { .ltr = true, .size = 2, .tokens = { TOKEN_OPERATOR_COMMA, TOKEN_OPERATOR_EOL, }, }, }; static size_t PARSE_ORDER_SIZE = sizeof(PARSE_ORDER) / sizeof(ParseOrder); ParsedNode *newParsedNode(char const *strBegin, char const *strEnd, ParsedToken token, void *metadata, ParsedNode *parent) { ParsedNode *parsedNode = a404m_malloc(sizeof(*parsedNode)); parsedNode->strBegin = strBegin; parsedNode->strEnd = strEnd; parsedNode->token = token; parsedNode->metadata = metadata; parsedNode->parent = parent; return parsedNode; } void _printParsedNode(const ParsedNode *parsedNode, int indent) { if (parsedNode == NULL) { for (int i = 0; i < indent; ++i) printf(" "); printf("null\n"); return; } for (int i = 0; i < indent; ++i) printf(" "); printf("{token=%s", PARSED_TOKEN_STRINGS[parsedNode->token]); switch (parsedNode->token) { case PARSED_TOKEN_FUNCTION_PARAMS: case PARSED_TOKEN_PARENTHESIS: case PARSED_TOKEN_CODE_BODY: case PARSED_TOKEN_ROOT: { ++indent; const ParserScopeMetadata *metadata = parsedNode->metadata; printf(",operands=[\n"); for (size_t i = 0; i < metadata->operands_size; ++i) { _printParsedNode(metadata->operands[i], indent + 1); } for (int i = 0; i < indent; ++i) printf(" "); printf("]\n"); --indent; goto END_SUCCESS; } case PARSED_TOKEN_VALUE_STRING: case PARSED_TOKEN_IDENTIFIER: printf(",str='%.*s'\n", (int)(parsedNode->strEnd - parsedNode->strBegin), parsedNode->strBegin); goto END_SUCCESS; case PARSED_TOKEN_COMMA: case PARSED_TOKEN_EOL: { const ParserEOLMetadata *metadata = parsedNode->metadata; printf(",operand=\n"); _printParsedNode(metadata, indent + 1); goto END_SUCCESS; } case PARSED_TOKEN_FUNCTION_CALL: { const ParserFunctionCallMetadata *metadata = parsedNode->metadata; printf(",functionName=%.*s,operands=[\n", (int)(metadata->functionNameEnd - metadata->functionNameBegin), metadata->functionNameBegin); ++indent; const ParserScopeMetadata *scope = metadata->scope; for (size_t i = 0; i < scope->operands_size; ++i) { _printParsedNode(scope->operands[i], indent + 1); } for (int i = 0; i < indent; ++i) printf(" "); printf("]\n"); --indent; goto END_SUCCESS; } case PARSED_TOKEN_DEFINE_CONSTANT: case PARSED_TOKEN_DEFINE_VARIABLE: { const ParserVariableDefineMetadata *metadata = parsedNode->metadata; printf(",name=%.*s\n", (int)(metadata->name->strEnd - metadata->name->strBegin), metadata->name->strBegin); if (metadata->type != NULL) { for (int i = 0; i < indent; ++i) printf(" "); printf(",type=\n"); _printParsedNode(metadata->type, indent + 1); } if (metadata->value) { for (int i = 0; i < indent; ++i) printf(" "); printf(",value=\n"); _printParsedNode(metadata->value, indent + 1); } goto END_SUCCESS; } case PARSED_TOKEN_STRUCT: { const ParserStructMetadata *metadata = parsedNode->metadata; printf(",body=\n"); _printParsedNode(metadata->body, indent + 1); goto END_SUCCESS; } case PARSED_TOKEN_FUNCTION: { const ParserFunctionMetadata *metadata = parsedNode->metadata; printf(",params=\n"); _printParsedNode(metadata->params, indent + 1); for (int i = 0; i < indent; ++i) printf(" "); printf(",type=\n"); _printParsedNode(metadata->type, indent + 1); for (int i = 0; i < indent; ++i) printf(" "); printf(",body=\n"); _printParsedNode(metadata->body, indent + 1); goto END_SUCCESS; } case PARSED_TOKEN_IMPORT: { const ParserImportMetadata *metadata = parsedNode->metadata; printf(",import=\n"); _printParsedNode(metadata, indent + 1); goto END_SUCCESS; } case PARSED_TOKEN_NONE: } fprintf(stderr, "bad parsed token %d at compiler line %d\n", parsedNode->token, __LINE__); exit(1); END_SUCCESS: for (int i = 0; i < indent; ++i) printf(" "); printf("}\n"); } void printParsedNode(const ParsedNode *parsedNode) { _printParsedNode(parsedNode, 0); } ParsedNode *getUntilCommonFather(ParsedNode *parsedNode, ParsedNode *parent) { while (parsedNode != NULL && parsedNode->parent != parent) { parsedNode = parsedNode->parent; } return parsedNode; } void deleteParsedNode(ParsedNode *parsedNode) { if (parsedNode == NULL) { return; } switch (parsedNode->token) { case PARSED_TOKEN_NONE: case PARSED_TOKEN_VALUE_STRING: case PARSED_TOKEN_IDENTIFIER: goto FREE; case PARSED_TOKEN_FUNCTION_PARAMS: case PARSED_TOKEN_CODE_BODY: case PARSED_TOKEN_PARENTHESIS: case PARSED_TOKEN_ROOT: { ParserScopeMetadata *metadata = parsedNode->metadata; for (size_t i = 0; i < metadata->operands_size; ++i) { deleteParsedNode(metadata->operands[i]); } free(metadata->operands); free(metadata); goto FREE; } case PARSED_TOKEN_COMMA: case PARSED_TOKEN_EOL: { ParserEOLMetadata *metadata = parsedNode->metadata; deleteParsedNode(metadata); goto FREE; } case PARSED_TOKEN_FUNCTION_CALL: { ParserFunctionCallMetadata *metadata = parsedNode->metadata; ParserScopeMetadata *scope = metadata->scope; for (size_t i = 0; i < scope->operands_size; ++i) { deleteParsedNode(scope->operands[i]); } free(scope->operands); free(scope); free(metadata); goto FREE; } case PARSED_TOKEN_DEFINE_CONSTANT: case PARSED_TOKEN_DEFINE_VARIABLE: { ParserVariableDefineMetadata *metadata = parsedNode->metadata; deleteParsedNode(metadata->name); deleteParsedNode(metadata->type); deleteParsedNode(metadata->value); free(metadata); goto FREE; } case PARSED_TOKEN_STRUCT: { ParserStructMetadata *metadata = parsedNode->metadata; deleteParsedNode(metadata->body); free(metadata); goto FREE; } case PARSED_TOKEN_FUNCTION: { ParserFunctionMetadata *metadata = parsedNode->metadata; deleteParsedNode(metadata->params); deleteParsedNode(metadata->type); deleteParsedNode(metadata->body); free(metadata); goto FREE; } case PARSED_TOKEN_IMPORT: { ParserImportMetadata *metadata = parsedNode->metadata; deleteParsedNode(metadata); goto FREE; } } fprintf(stderr, "bad parsed token %d at compiler line %d\n", parsedNode->token, __LINE__); exit(1); FREE: free(parsedNode); } ParsedNode *parser(SourceCode *code, size_t sourceIndex) { Nodes nodes = lexer(code, sourceIndex); if (nodes.size == ERROR_SIZE) { return NULL; } ParsedNode *root = _parser(nodes, code); deleteNodes(nodes); return root; } ParsedNode *_parser(Nodes lexedNodes, SourceCode *code) { ParsedNode *root = a404m_malloc(sizeof(*root)); root->token = PARSED_TOKEN_ROOT; root->parent = NULL; root->metadata = parserScopeCode( lexedNodes.nodes, lexedNodes.nodes + lexedNodes.size, root, code); if (root->metadata == NULL) { free(root); return NULL; } return root; } ParserScopeMetadata *parserScope( Node *nodesBegin, Node *nodesEnd, ParsedNode *parent, bool (*isAllowed)(ParsedToken token, bool isLast), SourceCode *code) { ParsedNode **nodes = a404m_malloc(0); size_t nodes_inserted = 0; for (size_t order_index = 0; order_index < PARSE_ORDER_SIZE; ++order_index) { const ParseOrder *order = &PARSE_ORDER[order_index]; for (Node *node = order->ltr ? nodesBegin : (nodesEnd - 1); nodesBegin <= node && node < nodesEnd; order->ltr ? ++node : --node) { for (size_t order_tokens_index = 0; order_tokens_index < order->size; ++order_tokens_index) { if (node->token == order->tokens[order_tokens_index]) { ParsedNode *parsedNode = parseNode(nodesBegin, nodesEnd, node, parent, code); if (parsedNode == NULL) { goto RETURN_ERROR; } size_t nodes_size = a404m_malloc_usable_size(nodes) / sizeof(ParsedNode *); if (nodes_size == nodes_inserted) { nodes_size += nodes_size / 2 + 1; nodes = a404m_realloc(nodes, nodes_size * sizeof(ParsedNode *)); } nodes[nodes_inserted] = parsedNode; ++nodes_inserted; break; } } } } for (Node *node = nodesBegin; node < nodesEnd; ++node) { if (node->token != TOKEN_PARSED) { printError("Unexpected node with token '%s'", code, node->strBegin, node->strEnd, TOKEN_STRINGS[node->token]); goto RETURN_ERROR; } } ParsedNode **operands = a404m_malloc(nodes_inserted * sizeof(ParsedNode *)); size_t nodes_size = nodes_inserted; nodes_inserted = 0; ParsedNode *last = NULL; for(size_t i = nodes_size-1;i != (typeof(i))-1;++i){ ParsedNode *currentNode = nodes[i]; if (currentNode->parent == parent) { last = currentNode; break; } } for (size_t i = 0; i < nodes_size; ++i) { ParsedNode *currentNode = nodes[i]; if (currentNode->parent == parent) { if (!isAllowed(currentNode->token, currentNode == last)) { printError("Token '%s' is not allowed here", code, currentNode->strBegin, currentNode->strEnd, PARSED_TOKEN_STRINGS[currentNode->token]); goto RETURN_ERROR; } operands[nodes_inserted] = currentNode; ++nodes_inserted; } } free(nodes); ParserScopeMetadata *metadata = a404m_malloc(sizeof(*metadata)); metadata->operands = a404m_realloc(operands, nodes_inserted * sizeof(ParsedNode *)); metadata->operands_size = nodes_inserted; return metadata; RETURN_ERROR: free(nodes); return NULL; } static bool isAllowedCodeScope(ParsedToken token, bool) { switch (token) { case PARSED_TOKEN_NONE: case PARSED_TOKEN_ROOT: case PARSED_TOKEN_PARENTHESIS: case PARSED_TOKEN_VALUE_STRING: case PARSED_TOKEN_IDENTIFIER: case PARSED_TOKEN_FUNCTION_CALL: case PARSED_TOKEN_DEFINE_VARIABLE: case PARSED_TOKEN_DEFINE_CONSTANT: case PARSED_TOKEN_COMMA: case PARSED_TOKEN_STRUCT: case PARSED_TOKEN_FUNCTION: case PARSED_TOKEN_FUNCTION_PARAMS: case PARSED_TOKEN_IMPORT: return false; case PARSED_TOKEN_EOL: case PARSED_TOKEN_CODE_BODY: return true; } fprintf(stderr, "bad token '%d' at compiler line %d\n", token, __LINE__); exit(1); } static bool isAllowedParenthesisScope(ParsedToken token, bool) { switch (token) { case PARSED_TOKEN_PARENTHESIS: case PARSED_TOKEN_VALUE_STRING: case PARSED_TOKEN_IDENTIFIER: case PARSED_TOKEN_FUNCTION_CALL: return true; case PARSED_TOKEN_NONE: case PARSED_TOKEN_ROOT: case PARSED_TOKEN_EOL: case PARSED_TOKEN_COMMA: case PARSED_TOKEN_DEFINE_VARIABLE: case PARSED_TOKEN_DEFINE_CONSTANT: case PARSED_TOKEN_STRUCT: case PARSED_TOKEN_FUNCTION: case PARSED_TOKEN_CODE_BODY: case PARSED_TOKEN_FUNCTION_PARAMS: case PARSED_TOKEN_IMPORT: return false; } fprintf(stderr, "bad token '%d' at compiler line %d\n", token, __LINE__); exit(1); } static bool isAllowedFunctionCallScope(ParsedToken token, bool isLast) { switch (token) { case PARSED_TOKEN_PARENTHESIS: case PARSED_TOKEN_VALUE_STRING: case PARSED_TOKEN_IDENTIFIER: case PARSED_TOKEN_FUNCTION_CALL: case PARSED_TOKEN_DEFINE_VARIABLE: case PARSED_TOKEN_DEFINE_CONSTANT: return isLast; case PARSED_TOKEN_COMMA: return true; case PARSED_TOKEN_NONE: case PARSED_TOKEN_ROOT: case PARSED_TOKEN_EOL: case PARSED_TOKEN_STRUCT: case PARSED_TOKEN_FUNCTION: case PARSED_TOKEN_FUNCTION_PARAMS: case PARSED_TOKEN_CODE_BODY: case PARSED_TOKEN_IMPORT: return false; } fprintf(stderr, "bad token '%d' at compiler line %d\n", token, __LINE__); exit(1); } static bool isAllowedFunctionParamScope(ParsedToken token, bool isLast) { switch (token) { case PARSED_TOKEN_DEFINE_VARIABLE: case PARSED_TOKEN_DEFINE_CONSTANT: return isLast; case PARSED_TOKEN_COMMA: return true; case PARSED_TOKEN_PARENTHESIS: case PARSED_TOKEN_VALUE_STRING: case PARSED_TOKEN_IDENTIFIER: case PARSED_TOKEN_FUNCTION_CALL: case PARSED_TOKEN_NONE: case PARSED_TOKEN_ROOT: case PARSED_TOKEN_EOL: case PARSED_TOKEN_STRUCT: case PARSED_TOKEN_FUNCTION: case PARSED_TOKEN_FUNCTION_PARAMS: case PARSED_TOKEN_CODE_BODY: case PARSED_TOKEN_IMPORT: return false; } fprintf(stderr, "bad token '%d' at compiler line %d\n", token, __LINE__); exit(1); } static bool isAllowedStructScope(ParsedToken token, bool) { switch (token) { case PARSED_TOKEN_PARENTHESIS: case PARSED_TOKEN_VALUE_STRING: case PARSED_TOKEN_IDENTIFIER: case PARSED_TOKEN_FUNCTION_CALL: case PARSED_TOKEN_DEFINE_VARIABLE: case PARSED_TOKEN_COMMA: case PARSED_TOKEN_EOL: case PARSED_TOKEN_NONE: case PARSED_TOKEN_ROOT: case PARSED_TOKEN_FUNCTION: case PARSED_TOKEN_STRUCT: case PARSED_TOKEN_DEFINE_CONSTANT: case PARSED_TOKEN_FUNCTION_PARAMS: case PARSED_TOKEN_CODE_BODY: case PARSED_TOKEN_IMPORT: return false; } fprintf(stderr, "bad token '%d' at compiler line %d\n", token, __LINE__); exit(1); } ParserScopeMetadata *parserScopeCode(Node *nodesBegin, Node *nodesEnd, ParsedNode *parent, SourceCode *code) { return parserScope(nodesBegin, nodesEnd, parent, isAllowedCodeScope, code); } ParserScopeMetadata *parserScopeParenthesis(Node *nodesBegin, Node *nodesEnd, ParsedNode *parent, SourceCode *code) { return parserScope(nodesBegin, nodesEnd, parent, isAllowedParenthesisScope, code); } ParserScopeMetadata *parserScopeFunctionCall(Node *nodesBegin, Node *nodesEnd, ParsedNode *parent, SourceCode *code) { return parserScope(nodesBegin, nodesEnd, parent, isAllowedFunctionCallScope, code); } ParserScopeMetadata *parserScopeFunctionParam(Node *nodesBegin, Node *nodesEnd, ParsedNode *parent, SourceCode *code) { return parserScope(nodesBegin, nodesEnd, parent, isAllowedFunctionParamScope, code); } ParserScopeMetadata *parserScopeStruct(Node *nodesBegin, Node *nodesEnd, ParsedNode *parent, SourceCode *code) { return parserScope(nodesBegin, nodesEnd, parent, isAllowedStructScope, code); } ParsedNode *parseNode(Node *nodesBegin, Node *nodesEnd, Node *node, ParsedNode *parent, SourceCode *code) { switch (node->token) { case TOKEN_OPERATOR_PARENTHESES_CLOSE: return parseParenthesis(nodesBegin, nodesEnd, node, parent, code); case TOKEN_STRING: return parseString(node, parent); case TOKEN_IDENTIFIER: return parseIdentifier(node, parent); case TOKEN_OPERATOR_EOL: return parseEOL(nodesBegin, node, parent, code); case TOKEN_OPERATOR_COLON: return parseVariable(nodesBegin, nodesEnd, node, parent, code); case TOKEN_OPERATOR_COMMA: return parseComma(nodesBegin, nodesEnd, node, parent, code); case TOKEN_KEYWORD_EXTERNAL: return parseStruct(nodesEnd, node, parent, code); case TOKEN_OPERATOR_CURLY_BRACKET_CLOSE: return parseCurly(nodesBegin, node, parent, code); case TOKEN_KEYWORD_STRUCT: return parseStruct(nodesEnd, node, parent, code); case TOKEN_OPERATOR_FUNCTION: return parseFunction(nodesBegin, nodesEnd, node, parent, code); case TOKEN_KEYWORD_IMPORT: return parseImport(nodesEnd, node, parent, code); case TOKEN_NONE: case TOKEN_NUMBER: case TOKEN_OPERATOR: case TOKEN_OPERATOR_PARENTHESES_OPEN: case TOKEN_OPERATOR_CURLY_BRACKET_OPEN: case TOKEN_OPERATOR_ASSIGN: case TOKEN_OPERATOR_EQUAL: case TOKEN_SYMBOL: case TOKEN_PARSED: } printError("Unexpected token '%s' at compiler line %d", code, node->strBegin, node->strEnd, TOKEN_STRINGS[node->token], __LINE__); return NULL; } ParsedNode *parseParenthesis(Node *nodesBegin, Node *nodesEnd, Node *closing, ParsedNode *parent, SourceCode *code) { ParsedNode *root = a404m_malloc(sizeof(*root)); Node *opening = NULL; for (Node *iter = closing - 1; iter >= nodesBegin; --iter) { if (iter->token == TOKEN_OPERATOR_PARENTHESES_OPEN) { opening = iter; break; } } if (opening == NULL) { printError("Found no opening for )", code, closing->strBegin, closing->strEnd, __LINE__); goto RETURN_ERROR; } Node *const functionName = opening - 1; Node *const functionTailOperator = closing + 1; if (functionName >= nodesBegin && functionName->token == TOKEN_IDENTIFIER) { functionName->token = TOKEN_PARSED; functionName->parsedNode = root; root->token = PARSED_TOKEN_FUNCTION_CALL; root->strBegin = (opening - 1)->strBegin; root->strEnd = closing->strEnd; root->parent = parent; ParserFunctionCallMetadata *metadata = root->metadata = a404m_malloc(sizeof(*metadata)); metadata->functionNameBegin = functionName->strBegin; metadata->functionNameEnd = functionName->strEnd; if ((metadata->scope = parserScopeFunctionCall(opening + 1, closing, root, code)) == NULL) { free(metadata); goto RETURN_ERROR; } } else if (functionTailOperator < nodesEnd && functionTailOperator->token == TOKEN_OPERATOR_FUNCTION) { root->token = PARSED_TOKEN_FUNCTION_PARAMS; root->strBegin = (opening - 1)->strBegin; root->strEnd = closing->strEnd; root->parent = parent; if ((root->metadata = parserScopeFunctionParam(opening + 1, closing, root, code)) == NULL) { goto RETURN_ERROR; } } else { root->token = PARSED_TOKEN_PARENTHESIS; root->strBegin = opening->strBegin; root->strEnd = closing->strEnd; root->parent = parent; ParserScopeMetadata *const scope = parserScopeParenthesis(opening + 1, closing, root, code); if (scope == NULL) { goto RETURN_ERROR; } else if (scope->operands_size != 1) { printError("Parenthesis should only contain one expression", code, opening->strBegin, closing->strEnd); goto RETURN_ERROR; } ParserParenthesisMetadata *const metadata = scope->operands[0]; root->metadata = metadata; } closing->parsedNode = opening->parsedNode = root; opening->token = closing->token = TOKEN_PARSED; return root; RETURN_ERROR: free(root); return NULL; } ParsedNode *parseCurly(Node *nodesBegin, Node *closing, ParsedNode *parent, SourceCode *code) { ParsedNode *root = a404m_malloc(sizeof(*root)); Node *opening = NULL; for (Node *iter = closing - 1; iter >= nodesBegin; --iter) { if (iter->token == TOKEN_OPERATOR_CURLY_BRACKET_OPEN) { opening = iter; break; } } if (opening == NULL) { printError("Found no opening for }", code, closing->strBegin, closing->strEnd, __LINE__); goto RETURN_ERROR; } if ((root->metadata = parserScopeCode(opening + 1, closing, parent, code)) == NULL) { goto RETURN_ERROR; } root->strBegin = opening->strBegin; root->strEnd = opening->strEnd; root->parent = parent; root->token = PARSED_TOKEN_CODE_BODY; closing->parsedNode = opening->parsedNode = root; opening->token = closing->token = TOKEN_PARSED; return root; RETURN_ERROR: free(root); return NULL; } ParsedNode *parseString(Node *node, ParsedNode *parent) { node->token = TOKEN_PARSED; return node->parsedNode = newParsedNode(node->strBegin, node->strEnd, PARSED_TOKEN_VALUE_STRING, NULL, parent); } ParsedNode *parseIdentifier(Node *node, ParsedNode *parent) { node->token = TOKEN_PARSED; return node->parsedNode = newParsedNode(node->strBegin, node->strEnd, PARSED_TOKEN_IDENTIFIER, NULL, parent); } ParsedNode *parseEOL(Node *nodesBegin, Node *node, ParsedNode *parent, SourceCode *code) { Node *before = node - 1; if (before < nodesBegin) { RETURN_EMPTY: return newParsedNode(node->strBegin, node->strEnd, PARSED_TOKEN_EOL, NULL, parent); } else if (before->token != TOKEN_PARSED) { printError("Unexpected EOL", code, node->strBegin, node->strEnd); return NULL; } ParsedNode *experession = getUntilCommonFather(before->parsedNode, parent); if (experession == NULL) { printError("Unexpected EOL", code, node->strBegin, node->strEnd); return NULL; } else if (experession->token == PARSED_TOKEN_EOL) { goto RETURN_EMPTY; } ParsedNode *root = a404m_malloc(sizeof(*root)); root->strBegin = node->strBegin; root->strEnd = node->strEnd; root->token = PARSED_TOKEN_EOL; root->parent = parent; root->metadata = experession; experession->parent = root; node->token = TOKEN_PARSED; node->parsedNode = root; return root; } ParsedNode *parseVariable(Node *nodesBegin, Node *nodesEnd, Node *node, ParsedNode *parent, SourceCode *code) { ParsedNode *root = a404m_malloc(sizeof(*root)); ParserVariableDefineMetadata *metadata = root->metadata = a404m_malloc(sizeof(*metadata)); Node *variableName = node - 1; if (variableName < nodesBegin) { printError("Variable definition needs name", code, node->strBegin, node->strEnd); goto RETURN_ERROR; } else if (variableName->token != TOKEN_PARSED) { BAD_VAR_NAME: printError("Variable name should be an identifier but got something else", code, node->strBegin, node->strEnd); goto RETURN_ERROR; } ParsedNode *const variableNameParsed = getUntilCommonFather(variableName->parsedNode, parent); if (variableNameParsed == NULL || variableNameParsed->token != PARSED_TOKEN_IDENTIFIER) { goto BAD_VAR_NAME; } variableNameParsed->parent = root; metadata->name = variableNameParsed; Node *follow = node + 1; ParsedNode *type; ParsedNode *value = NULL; if (follow == nodesEnd) { printError("Variable definition needs type or assignment to a value", code, node->strBegin, node->strEnd); goto RETURN_ERROR; } else if (follow->token == TOKEN_PARSED) { type = getUntilCommonFather(follow->parsedNode, parent); if (type == NULL) { printError("Expected type but got something else", code, follow->strBegin, follow->strEnd); goto RETURN_ERROR; } ++follow; while (follow->token == TOKEN_PARSED && getUntilCommonFather(follow->parsedNode, type) != NULL) { ++follow; } } else { type = NULL; } if (follow == nodesEnd || (follow->token != TOKEN_OPERATOR_ASSIGN && follow->token != TOKEN_OPERATOR_COLON)) { root->token = PARSED_TOKEN_DEFINE_VARIABLE; --follow; } else { if (follow->token == TOKEN_OPERATOR_ASSIGN) root->token = PARSED_TOKEN_DEFINE_VARIABLE; else root->token = PARSED_TOKEN_DEFINE_CONSTANT; follow->parsedNode = root; follow->token = TOKEN_PARSED; ++follow; if (follow == nodesEnd) { --follow; printError("Expected value after assignment but got nothing", code, follow->strBegin, follow->strEnd); goto RETURN_ERROR; } else if (follow->token == TOKEN_PARSED) { value = getUntilCommonFather(follow->parsedNode, parent); } else { BAD_VALUE: printError("Expected value after assignment but got something else", code, follow->strBegin, follow->strEnd); goto RETURN_ERROR; } } if (type == NULL && value == NULL) { printError("Variable definition needs type or assignment to a value", code, node->strBegin, node->strEnd); goto RETURN_ERROR; } if (type != NULL) { metadata->type = type; type->parent = root; } else { metadata->type = NULL; } if (value != NULL) { metadata->value = value = getUntilCommonFather(value, parent); if (value == NULL) { goto BAD_VALUE; } value->parent = root; } else { metadata->value = NULL; } root->strBegin = variableName->strBegin; root->strEnd = follow->strEnd; root->parent = parent; node->token = TOKEN_PARSED; node->parsedNode = root; return root; RETURN_ERROR: free(root); free(metadata); return NULL; } ParsedNode *parseComma(Node *nodesBegin, Node *, Node *node, ParsedNode *parent, SourceCode *code) { Node *before = node - 1; if (before < nodesBegin || before->token != TOKEN_PARSED) { UNEXPECTED: printError("Unexpected comma", code, node->strBegin, node->strEnd); return NULL; } ParsedNode *const experession = getUntilCommonFather(before->parsedNode, parent); if (experession == NULL || experession->token == PARSED_TOKEN_COMMA) { goto UNEXPECTED; } ParsedNode *root = a404m_malloc(sizeof(*root)); root->strBegin = node->strBegin; root->strEnd = node->strEnd; root->token = PARSED_TOKEN_COMMA; root->parent = parent; root->metadata = experession; experession->parent = root; node->token = TOKEN_PARSED; node->parsedNode = root; return root; } ParsedNode *parseStruct(Node *nodesEnd, Node *node, ParsedNode *parent, SourceCode *code) { ParsedNode *root = a404m_malloc(sizeof(*root)); ParserStructMetadata *metadata = root->metadata = a404m_malloc(sizeof(*metadata)); Node *const body = node + 1; if (body >= nodesEnd) { NO_BODY: printError("'struct' needs a body", code, node->strBegin, node->strEnd); goto RETURN_ERROR; } root->strBegin = node->strBegin; root->strBegin = body->strEnd; root->token = PARSED_TOKEN_STRUCT; root->parent = parent; node->token = TOKEN_PARSED; node->parsedNode = root; if (body->token == TOKEN_KEYWORD_EXTERNAL) { body->token = TOKEN_PARSED; body->parsedNode = root; metadata->body = NULL; } else if (body->token == TOKEN_PARSED) { if ((metadata->body = getUntilCommonFather(body->parsedNode, parent)) == NULL) { goto NO_BODY; } else { metadata->body->parent = root; } } else { goto NO_BODY; } return root; RETURN_ERROR: free(root); free(metadata); return NULL; } ParsedNode *parseFunction(Node *nodesBegin, Node *nodesEnd, Node *node, ParsedNode *parent, SourceCode *code) { ParsedNode *root = a404m_malloc(sizeof(*root)); ParserFunctionMetadata *metadata = root->metadata = a404m_malloc(sizeof(*metadata)); Node *const params = node - 1; Node *const type = node + 1; Node *const body = node + 2; if (params < nodesBegin || params->token != TOKEN_PARSED || params->parsedNode->token != PARSED_TOKEN_FUNCTION_PARAMS) { printError("Function definition needs a param list", code, node->strBegin, node->strEnd); goto RETURN_ERROR; } else { metadata->params = params->parsedNode; metadata->params->parent = root; } if (type >= nodesEnd || type->token != TOKEN_PARSED || type->parsedNode->token != PARSED_TOKEN_IDENTIFIER) { printError("Function definition needs a type to be identifier (for now)", code, node->strBegin, node->strEnd); goto RETURN_ERROR; } else { metadata->type = type->parsedNode; metadata->type->parent = root; } if (body >= nodesEnd) { NEED_BODY: printError("Function definition needs a body or be set to external", code, node->strBegin, node->strEnd); goto RETURN_ERROR; } else if (body->token == TOKEN_KEYWORD_EXTERNAL) { body->token = TOKEN_PARSED; body->parsedNode = root; metadata->body = NULL; } else if (type->token == TOKEN_PARSED && type->parsedNode->token == PARSED_TOKEN_CODE_BODY) { metadata->body = type->parsedNode; metadata->body->parent = root; } else { goto NEED_BODY; } node->token = TOKEN_PARSED; node->parsedNode = root; root->strBegin = params->strBegin; root->strEnd = params->strEnd; root->parent = parent; root->token = PARSED_TOKEN_FUNCTION; return root; RETURN_ERROR: free(metadata); free(root); return NULL; } ParsedNode *parseImport(Node *nodesEnd, Node *node, ParsedNode *parent, SourceCode *code) { ParsedNode *root = a404m_malloc(sizeof(*root)); root->parent = parent; root->token = PARSED_TOKEN_IMPORT; ParserImportMetadata *metadata; Node const *package = node + 1; if (package == nodesEnd) { NO_PATH: printError("Import needs a path", code, node->strBegin, node->strEnd); goto RETURN_ERROR; } else if (package->token != TOKEN_PARSED) { BAD_PATH: printError("Import path should be an string", code, package->strBegin, package->strEnd); goto RETURN_ERROR; } else if ((metadata = getUntilCommonFather(package->parsedNode, parent)) == NULL) { goto NO_PATH; } else if (metadata->token != PARSED_TOKEN_VALUE_STRING) { goto BAD_PATH; } metadata->parent = root; root->metadata = metadata; node->token = TOKEN_PARSED; node->parsedNode = root; root->strBegin = node->strBegin; root->strEnd = package->strEnd; return root; RETURN_ERROR: free(root); return NULL; }