Compare commits
3 Commits
f7b1436f87
...
23f23cd9b6
Author | SHA1 | Date |
---|---|---|
|
23f23cd9b6 | |
|
759db1ea7a | |
|
e968058249 |
|
@ -52,13 +52,27 @@ typedef struct TokenResult {
|
|||
typedef struct {
|
||||
SyncResultType type;
|
||||
union {
|
||||
struct TokenResult* result;
|
||||
TokenResult* result;
|
||||
GeneralError error;
|
||||
};
|
||||
} LexerResult;
|
||||
|
||||
typedef struct {
|
||||
size_t length;
|
||||
Token* tokens;
|
||||
} TokenArray;
|
||||
|
||||
typedef struct {
|
||||
SyncResultType type;
|
||||
union {
|
||||
TokenArray result;
|
||||
GeneralError error;
|
||||
};
|
||||
} TokenArrayResult;
|
||||
|
||||
void lexer_init(Lexer* lexer, const char* filename, const char* source);
|
||||
LexerResult lexical_analysis(Lexer* lexer);
|
||||
TokenArrayResult token_result_array(TokenResult* result);
|
||||
void clean_token_result(TokenResult* head);
|
||||
|
||||
#endif // SYNC_LEXER_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
|
|
@ -38,4 +38,14 @@ typedef enum {
|
|||
SYNC_RESULT,
|
||||
} SyncResultType;
|
||||
|
||||
typedef struct {
|
||||
SyncResultType type;
|
||||
union {
|
||||
FileInfo result;
|
||||
GeneralError error;
|
||||
};
|
||||
} FileInfoResult;
|
||||
|
||||
FileInfoResult add_file_infos(FileInfo a, FileInfo b, const char* start);
|
||||
|
||||
#endif // SYNC_TYPES_H
|
||||
|
|
22
src/lexer.c
22
src/lexer.c
|
@ -260,6 +260,28 @@ LexerResult lexical_analysis(Lexer *lexer) {
|
|||
return (LexerResult){SYNC_RESULT, .result = head};
|
||||
}
|
||||
|
||||
TokenArrayResult token_result_array(TokenResult* result) {
|
||||
TokenResult* head = result;
|
||||
size_t length = 0;
|
||||
while (head != NULL) {
|
||||
if (head->type == SYNC_ERROR)
|
||||
return (TokenArrayResult){SYNC_ERROR, .error = (GeneralError){"Invalid Token List.", 1}};
|
||||
length++;
|
||||
head = head->next;
|
||||
}
|
||||
|
||||
Token* token_array = (Token*)malloc(length * sizeof(Token));
|
||||
if (token_array == NULL)
|
||||
return (TokenArrayResult){SYNC_ERROR, .error = (GeneralError){"Failed to allocate memory.", 1}};
|
||||
head = result;
|
||||
for (int i = 0; i < length; i++) {
|
||||
token_array[i] = head->result;
|
||||
head = head->next;
|
||||
}
|
||||
|
||||
return (TokenArrayResult){SYNC_RESULT, length, .result = (TokenArray){length, token_array}};
|
||||
}
|
||||
|
||||
void clean_token_result(TokenResult* head) {
|
||||
while (head != NULL) {
|
||||
TokenResult* temp = head;
|
||||
|
|
12
src/main.c
12
src/main.c
|
@ -7,6 +7,7 @@
|
|||
#include <stdlib.h>
|
||||
#include "sync/types.h"
|
||||
#include "sync/lexer.h"
|
||||
#include "sync/syntax.h"
|
||||
|
||||
const char* TOKEN_TYPES[] = {
|
||||
"EOF", "IDENTIFIER", "NUMBER", "OPERATOR",
|
||||
|
@ -68,8 +69,19 @@ int main(void) {
|
|||
token_result = token_result->next;
|
||||
}
|
||||
|
||||
TokenArrayResult array_result = token_result_array(lexer_result.result);
|
||||
clean_token_result(lexer_result.result);
|
||||
if (array_result.type == SYNC_ERROR) {
|
||||
fprintf(stderr, "Error: %s\n", array_result.error.message);
|
||||
free(source);
|
||||
return array_result.error.code;
|
||||
}
|
||||
TokenArray tokens = array_result.result;
|
||||
|
||||
free(tokens.tokens);
|
||||
free(source);
|
||||
|
||||
printf("Compilation Completed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
// Kyler Olsen
|
||||
// ZINC Bootstrap compiler
|
||||
// Syntax
|
||||
// June 2025
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#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);
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
// Kyler Olsen
|
||||
// ZINC Bootstrap compiler
|
||||
// Type helper functions
|
||||
// June 2025
|
||||
|
||||
#include "sync/types.h"
|
||||
|
||||
FileInfoResult add_file_infos(FileInfo a, FileInfo b, const char* start) {
|
||||
if (a.filename != b.filename)
|
||||
return (FileInfoResult){SYNC_ERROR, .error = (GeneralError){"Cannot add two FileInfo structs from different files.", 1}};
|
||||
size_t line = a.line;
|
||||
size_t column = a.column;
|
||||
size_t length = a.length;
|
||||
size_t lines = a.lines;
|
||||
for (int i = a.length; ; i++) {
|
||||
if (start[i] == '\0')
|
||||
return (FileInfoResult){SYNC_ERROR, .error = (GeneralError){"Encountered end of string.", 1}};
|
||||
if (start[i] == '\n') {
|
||||
column = 1;
|
||||
line++;
|
||||
lines++;
|
||||
} else column++;
|
||||
length++;
|
||||
if (line == b.line && column == b.column) {
|
||||
length += b.length;
|
||||
lines += b.lines;
|
||||
break;
|
||||
}
|
||||
}
|
||||
FileInfo file_info = {
|
||||
.filename = a.filename,
|
||||
.line = a.line,
|
||||
.column = a.column,
|
||||
.length = length,
|
||||
.lines = lines
|
||||
};
|
||||
return (FileInfoResult){SYNC_RESULT, .result = file_info};
|
||||
}
|
Loading…
Reference in New Issue