diff --git a/include/sync/syntax.h b/include/sync/syntax.h new file mode 100644 index 0000000..438bfb4 --- /dev/null +++ b/include/sync/syntax.h @@ -0,0 +1,63 @@ +// Kyler Olsen +// ZINC Bootstrap compiler +// Syntax Header +// June 2025 + +#ifndef SYNC_SYNTAX_H +#define SYNC_SYNTAX_H + +#include "types.h" +#include "lexer.h" + +typedef enum { + NODE_FILE, + NODE_BLOCK, + NODE_STATEMENT, + + NODE_IDENTIFIER, + NODE_NUMBER, + NODE_UNARY_OPERATOR, + NODE_BINARY_OPERATOR, + NODE_LPAREN, + NODE_RPAREN, + NODE_SEMICOLON, + NODE_LBRACE, + NODE_RBRACE, + NODE_LBRACKET, + NODE_RBRACKET, + NODE_CHARACTER, + NODE_STRING, +} NodeType; + +typedef struct Children { + size_t length; + struct SyntaxNode* nodes; +} Children; + +typedef struct SyntaxNode { + NodeType type; + const char *start; + size_t length; + FileInfo file_info; + Children children; +} SyntaxNode; + +typedef struct { + SyncResultType type; + union { + SyntaxNode result; + SyncError error; + }; +} NodeResult; + +typedef struct { + SyncResultType type; + union { + NodeResult result; + GeneralError error; + }; +} SyntaxResult; + +SyntaxResult syntactical_analysis(TokenArray tokens); + +#endif // SYNC_SYNTAX_H diff --git a/src/main.c b/src/main.c index 5e79833..3074f6b 100644 --- a/src/main.c +++ b/src/main.c @@ -7,6 +7,7 @@ #include #include "sync/types.h" #include "sync/lexer.h" +#include "sync/syntax.h" const char* TOKEN_TYPES[] = { "EOF", "IDENTIFIER", "NUMBER", "OPERATOR", @@ -80,5 +81,7 @@ int main(void) { free(tokens.tokens); free(source); + printf("Compilation Completed."); + return 0; } diff --git a/src/syntax.c b/src/syntax.c new file mode 100644 index 0000000..c06756d --- /dev/null +++ b/src/syntax.c @@ -0,0 +1,166 @@ +// Kyler Olsen +// ZINC Bootstrap compiler +// Syntax +// June 2025 + +#include +#include +#include +#include "sync/types.h" +#include "sync/lexer.h" +#include "sync/syntax.h" + +typedef struct { + const char* filename; + TokenArray tokens; + size_t pos; +} Parser; + +typedef struct Child { + struct Child* next; + SyntaxNode node; +} Child; + +typedef struct ChildrenResult { + SyncResultType type; + union { + Children result; + GeneralError error; + }; +} ChildrenResult; + +static GeneralError add_child(Child* list, SyntaxNode node) { + if (list == NULL) return (GeneralError){"Headless linked list.", 1}; + Child* new_child = (Child*)malloc(sizeof(Child)); + if (new_child == NULL) + return (GeneralError){"Failed to allocate memory.", 1}; + + new_child->next = NULL; + new_child->node = node; + + while (list->next != NULL) list = list->next; + list->next = new_child; + + return (GeneralError){NULL, 0}; +} + +static ChildrenResult children_array(Child* list) { + if (list == NULL) + return (ChildrenResult){SYNC_ERROR, .error = (GeneralError){"Headless linked list.", 1}}; + + Child* head = list; + size_t length = 0; + while (head != NULL) { + length++; + head = head->next; + } + + SyntaxNode* nodes = (SyntaxNode*)malloc(length * sizeof(SyntaxNode)); + if (nodes == NULL) + return (ChildrenResult){SYNC_ERROR, .error = (GeneralError){"Failed to allocate memory.", 1}}; + head = list; + for (int i = 0; i < length; i++) { + nodes[i] = head->node; + head = head->next; + } + + while (list != NULL) { + Child* temp = list; + list = list->next; + free(temp); + } + + return (ChildrenResult){SYNC_RESULT, .result = (Children){length, nodes}}; +} + +static SyntaxResult aggregate_children(NodeType type, Children children) { + const char* start = children.nodes[0].start; + size_t length = children.nodes[0].length; + FileInfo file_info = children.nodes[0].file_info; + for (int i = 1; i < children.length; i++) { + for (int j = 0; (j + start + length) <= children.nodes[i].start; j++) + if (*(j + start + length) == '\0') + return (SyntaxResult){SYNC_ERROR, .error = (GeneralError){"Non-continuous string.", 1}}; + length = (children.nodes[i].start + children.nodes[i].length) - start; + FileInfoResult file_info_result = add_file_infos(file_info, children.nodes[i].file_info, start); + if (file_info_result.type == SYNC_ERROR) return (SyntaxResult){SYNC_ERROR, .error = file_info_result.error}; + file_info = file_info_result.result; + } + SyntaxNode node = {type, start, length, file_info, children}; + return (SyntaxResult){SYNC_RESULT, .result = (NodeResult){SYNC_RESULT, .result = node}}; +} + +static SyntaxResult syntax_result(NodeType type, Child* list) { + ChildrenResult result = children_array(list); + list = NULL; + if (result.type == SYNC_ERROR) return (SyntaxResult){SYNC_RESULT, .error = result.error}; + return aggregate_children(type, result.result); +} + +static SyntaxResult syntax_error(const char* message, Token token) { + return (SyntaxResult){SYNC_RESULT, .result = (NodeResult){ + .type = SYNC_ERROR, + .error.type = SYNC_SYNTACTICAL_ERROR, + .error.message = message, + .error.file_info = token.file_info, + }}; +} + +static SyntaxResult parse_statement(Parser* parser) { +} + +static SyntaxResult parse_block(Parser* parser) { + Child* children = NULL; + + if (parser->tokens.tokens[parser->pos].type == TOKEN_RBRACE) { + parser->pos++; + while (parser->tokens.tokens[parser->pos].type != TOKEN_LBRACE) { + SyntaxResult result = parse_statement(parser); + if (result.type == SYNC_ERROR) return result; + if (result.result.type == SYNC_ERROR) return result; + if (children == NULL) { + children = (Child*)malloc(sizeof(Child)); + if (children == NULL) return (SyntaxResult){SYNC_ERROR, .error = (GeneralError){"Failed to allocate memory.", 1}}; + children->next = NULL; + children->node = result.result.result; + } else add_child(children, result.result.result); + if (parser->tokens.tokens[parser->pos].type == TOKEN_EOF) + return syntax_error("Expected '}'", parser->tokens.tokens[parser->pos]); + } + parser->pos++; + } else { + SyntaxResult result = parse_statement(parser); + if (result.type == SYNC_ERROR) return result; + if (result.result.type == SYNC_ERROR) return result; + children = (Child*)malloc(sizeof(Child)); + if (children == NULL) return (SyntaxResult){SYNC_ERROR, .error = (GeneralError){"Failed to allocate memory.", 1}}; + children->next = NULL; + children->node = result.result.result; + } + + return syntax_result(NODE_BLOCK, children); +} + +SyntaxResult syntactical_analysis(TokenArray tokens) { + Parser* parser = (Parser*)malloc(sizeof(Parser)); + if (parser == NULL) return (SyntaxResult){SYNC_ERROR, .error = (GeneralError){"Failed to allocate memory.", 1}}; + Child* children = NULL; + + while (parser->tokens.tokens[parser->pos].type != TOKEN_EOF) { + SyntaxResult result = parse_block(parser); + if (result.type == SYNC_ERROR) { free(parser); return result; } + if (result.result.type == SYNC_ERROR) { free(parser); return result; } + if (children == NULL) { + children = (Child*)malloc(sizeof(Child)); + if (children == NULL) { + free(parser); + return (SyntaxResult){SYNC_ERROR, .error = (GeneralError){"Failed to allocate memory.", 1}}; + } + children->next = NULL; + children->node = result.result.result; + } else add_child(children, result.result.result); + } + + free(parser); + return syntax_result(NODE_FILE, children); +}