commit c497732cb522f1e3b5a14f721a679b745c607222 Author: Sander Hautvast Date: Fri Oct 11 15:20:02 2024 +0200 WIP diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2f7896d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +target/ diff --git a/makefile b/makefile new file mode 100644 index 0000000..bd3137f --- /dev/null +++ b/makefile @@ -0,0 +1,20 @@ +TARGET := ./target +SRC := ./src +CC := clang -c -std=c17 -Wall -Wextra -pedantic -Werror + +SRCS := $(shell find $(SRC) -name '*.c') +OBJS := $(SRCS:%=$(TARGET)/%.o) + +#$(TARGET)/lox: $(OBJS) +# clang $(TARGET)/lox.o -L$(TARGET) -ltokens.o -o $(TARGET)/lox + + +$(TARGET)/%.c.o: $(SRC)/%.c $(TARGET) + $(CC) $< -o $@ + +$(TARGET): + mkdir -p $(TARGET) + +clean: + rm -r $(TARGET)/* + diff --git a/src/lox.c b/src/lox.c new file mode 100644 index 0000000..57c78bf --- /dev/null +++ b/src/lox.c @@ -0,0 +1,156 @@ +#include +#include +#include +#include +#include "tokens.h" + +int run_file(char* file); +void run_prompt(void); +void run(char* source); +void scan_tokens(char* source); +void scan_token(char* source, int line, int start, int* current_pos, TokenList* token_list); +void error(int line, char* nessage); +void report(int line, char* where, char* message); +char* substring(char* string, int position, int length); + +static bool had_error = false; + +int main(int argc, char* argv[]){ + if (argc>2){ + puts("Usage: lox [script]"); + return EXIT_FAILURE; + } else if (argc == 2){ + return run_file(argv[1]); + } else { + run_prompt(); + } + return EXIT_SUCCESS; +} + + +int run_file(char* filename){ + FILE* file = fopen(filename, "r"); + if (file == NULL){ + printf("unable to open file '%s'\n", filename); + return EXIT_FAILURE; + } + char line[255]; + + char* content = malloc(1); + if (content == NULL){ + puts("Out of memory"); + return EXIT_FAILURE; + } + content[0] = '\0'; + + + while (fgets(line, sizeof(line), file)){ + content = realloc(content, strlen(content) + strlen(line) + 1 ); + if (content == NULL){ + return EXIT_FAILURE; + } + strcat(content, line); + } + + fclose(file); + + run(content); + + // FREE UP + free(content); + + if (had_error){ + return 65; + } + + return EXIT_SUCCESS; +} + +void run_prompt(void){ + char line[255]; + + for (;;){ + printf(">"); + char* r = fgets(line, 255, stdin); + + if (r == NULL){ + break; + } + + run(line); + had_error = false; + } +} + +void run(char* source){ + printf("%s", source); + scan_tokens(source); +} + +void scan_tokens(char* source){ + int current = 0; + int start = 0; + int line = 1; + + TokenList token_list; + tokenlist_init(&token_list); + + while (current < (int)strlen(source)) { + start = current; + scan_token(source, line, start, ¤t, &token_list); + } + tokenlist_print(&token_list); +} + +void add_token(char* source, int line, TokenList* token_list, enum TokenType type, int start, int current_pos){ + Token token; + token.type = type; + token.lexeme = substring(source, start, current_pos); + token.literal = NULL; + token.line = line; + + tokenlist_add(token_list, token); +} + +void scan_token(char* source, int line, int start, int* current_pos, TokenList* token_list){ + char c = source[*current_pos]; + (*current_pos) += 1; + switch (c){ + case '(': add_token(source, line, token_list, LEFT_PAREN, start, *current_pos); break; + case ')': add_token(source, line, token_list, RIGHT_PAREN, start, *current_pos); break; + case '{': add_token(source, line, token_list, LEFT_BRACE, start, *current_pos); break; + case '}': add_token(source, line, token_list, RIGHT_BRACE, start, *current_pos); break; + case ',': add_token(source, line, token_list, COMMA, start, *current_pos); break; + case '.': add_token(source, line, token_list, DOT, start, *current_pos); break; + case '+': add_token(source, line, token_list, PLUS, start, *current_pos); break; + case ';': add_token(source, line, token_list, SEMICOLON, start, *current_pos); break; + case '/': add_token(source, line, token_list, SLASH, start, *current_pos); break; + } +} + +void error(int line, char* message){ + report(line, "", message); +} + +void report(int line, char* where, char* message){ + printf("[Line %i] Error %s : %s\n", line, where, message); + had_error = true; +} + +char* substring(char* string, int position, int length){ + char* ptr = malloc(length+1); + if (ptr == NULL) { + printf("out of memory"); + exit(EXIT_FAILURE); + } + + int c; + for (c=0; c< length; c++){ + *(ptr+c) = *(string+position-1); + string += sizeof(char); + } + *(ptr+c) = '\0'; + + return ptr; +} + diff --git a/src/tokens.c b/src/tokens.c new file mode 100644 index 0000000..b6793d1 --- /dev/null +++ b/src/tokens.c @@ -0,0 +1,83 @@ +#include +#include +#include "tokens.h" + +char* token_name(Token* token){ + char* type; + switch (token->type){ + case LEFT_PAREN: type = "LEFT_PAREN"; break; + case RIGHT_PAREN: type = "RIGHT_PAREN"; break; + case LEFT_BRACE: type = "LEFT_BRACE"; break; + case RIGHT_BRACE: type = "RIGHT_BRACE"; break; + case COMMA: type = "COMMA"; break; + case DOT: type = "DOT"; break; + case MINUS: type = "MINUS"; break; + case PLUS: type = "PLUS"; break; + case SEMICOLON: type = "SEMICOLON"; break; + case SLASH: type = "SLASH"; break; + case STAR: type = "STAR"; break; + case BANG: type = "BANG"; break; + case BANG_EQUAL: type = "BANG_EQUAL"; break; + case EQUAL: type = "EQUAL"; break; + case EQUAL_EQUAL: type = "EQUAL_EQUAL"; break; + case GREATER: type = "GREATER"; break; + case GREATER_EQUAL: type = "GREATER_EQUAL"; break; + case LESS: type = "LESS"; break; + case LESS_EQUAL: type = "LESS_EQUAL"; break; + case IDENTIFIER: type = "IDENTIFIER"; break; + case STRING: type = "STRING"; break; + case NUMBER: type = "NUMBER"; break; + case AND: type = "AND"; break; + case CLASS: type = "CLASS"; break; + case ELSE: type = "ELSE"; break; + case FALSE: type = "FALSE"; break; + case FUN: type = "FUN"; break; + case FOR: type = "FOR"; break; + case IF: type = "IF"; break; + case NIL: type = "NIL"; break; + case OR: type = "OR"; break; + case PRINT: type = "PRINT"; break; + case RETURN: type = "RETURN"; break; + case SUPER: type = "SUPER"; break; + case THIS: type = "THIS"; break; + case TRUE: type = "TRUE"; break; + case VAR: type = "VAR"; break; + case WHILE: type = "WHILE"; break; + case END_OF_FILE: type = "EOF"; break; + } + return type; +} + +void tokenlist_init(TokenList* list){ + list->tokens = malloc(sizeof(Token) * 32); + list->size = 0; + list->capacity = 32; +} + +void tokenlist_add(TokenList* list, Token value){ + if (list->size >= list->capacity){ + list->capacity *= 2; + list->tokens = realloc(list->tokens, sizeof(Token)* list->capacity); + } + list->tokens[list->size] = value; + list->size +=1; +} + +Token* tokenlist_get(TokenList* list, int index){ + if (index >= list->size || index < 0){ + printf("Index %d out of bounds for list of size %d\n", index, list->size); + exit(1); + } + return &list->tokens[index]; +} + +void tokenlist_print(TokenList* tokenlist){ + for (int i=0; i< tokenlist->size; i++){ + printf("%s, ", token_name(tokenlist_get(tokenlist, i))); + } +} + +void tokenlist_free(TokenList* list){ + free(list->tokens); +} + diff --git a/src/tokens.h b/src/tokens.h new file mode 100644 index 0000000..e63dfd4 --- /dev/null +++ b/src/tokens.h @@ -0,0 +1,40 @@ +#ifndef TOKENS_H +#define TOKENS_H + +enum TokenType{ + LEFT_PAREN, RIGHT_PAREN, LEFT_BRACE, RIGHT_BRACE, + COMMA, DOT, MINUS, PLUS, SEMICOLON, SLASH, STAR, + BANG, BANG_EQUAL, EQUAL, EQUAL_EQUAL, + GREATER, GREATER_EQUAL, LESS, LESS_EQUAL, + IDENTIFIER, STRING, NUMBER, + AND, CLASS, ELSE, FALSE, FUN, FOR, IF, NIL, OR, + PRINT, RETURN, SUPER, THIS, TRUE, VAR, WHILE, + END_OF_FILE +}; + +typedef struct { + enum TokenType type; + char* lexeme; + void* literal; + int line; +} Token; + +char* token_name(Token* token); + +typedef struct { + Token* tokens; + int size; + int capacity; +} TokenList; + +void tokenlist_init(TokenList* list); + +void tokenlist_add(TokenList* list, Token value); + +Token* tokenlist_get(TokenList* list, int index); + +void tokenlist_print(TokenList* tokenlist); + +void tokenlist_free(TokenList* list); + +#endif