diff --git a/makefile b/makefile index 333b974..f4ecb09 100644 --- a/makefile +++ b/makefile @@ -1,26 +1,23 @@ TARGET := ./target SRC := ./src -CC := clang -c -std=c17 -Wall -Wextra -pedantic -Werror +CC := clang++ -c -std=c++17 -Wall -Wextra -pedantic -Werror SRCS := $(shell find $(SRC) -name '*.c') OBJS := $(SRCS:%=$(TARGET)/%.o) -$(TARGET)/lox: $(TARGET)/lox.c.o $(TARGET)/parser.c.o $(TARGET)/scanner.c.o $(TARGET)/tokens.c.o $(TARGET)/utils.c.o - clang $(TARGET)/lox.c.o -L$(TARGET) -lparser.c.o -ltokens.c.o -lscanner.c.o -lutils.c.o -o $(TARGET)/lox +$(TARGET)/lox: $(TARGET)/lox.cpp.o $(TARGET)/parser.cpp.o $(TARGET)/scanner.cpp.o + clang++ $(TARGET)/lox.cpp.o -L$(TARGET) -lscanner.cpp.o -o $(TARGET)/lox -$(TARGET)/utils.c.o: $(SRC)/utils.c +$(TARGET)/utils.cpp.o: $(SRC)/utils.cpp $(CC) $< -o $@ -$(TARGET)/tokens.c.o: $(SRC)/tokens.c +$(TARGET)/scanner.cpp.o: $(SRC)/scanner.cpp $(CC) $< -o $@ -$(TARGET)/scanner.c.o: $(SRC)/scanner.c +$(TARGET)/parser.cpp.o: $(SRC)/parser.cpp $(CC) $< -o $@ -$(TARGET)/parser.c.o: $(SRC)/parser.c - $(CC) $< -o $@ - -$(TARGET)/lox.c.o: $(SRC)/lox.c $(TARGET) +$(TARGET)/lox.cpp.o: $(SRC)/lox.cpp $(TARGET) $(CC) $< -o $@ $(TARGET): diff --git a/src/lox.c b/src/lox.c deleted file mode 100644 index 65f4870..0000000 --- a/src/lox.c +++ /dev/null @@ -1,83 +0,0 @@ -#include "scanner.h" -#include "tokens.h" -#include "utils.h" -#include -#include -#include -#include - -int run_file(char *file); -void run_prompt(void); -ScanResult run(char *source); - -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); - - ScanResult scan_result = run(content); - - // FREE UP - free(content); - - if (scan_result.had_error) { - return 65; - } - - tokenlist_print(&scan_result.token_list); - - return EXIT_SUCCESS; -} - -void run_prompt(void) { - char line[255]; - - for (;;) { - printf(">"); - char *r = fgets(line, 255, stdin); - - if (r == NULL) { - break; - } - - int len = (int)strlen(line); - ScanResult scan_result = run(substring(line, 1, len - 1)); - - tokenlist_print(&scan_result.token_list); - } -} - -ScanResult run(char *source) { return scan_tokens(source); } diff --git a/src/lox.cpp b/src/lox.cpp new file mode 100644 index 0000000..b5627a0 --- /dev/null +++ b/src/lox.cpp @@ -0,0 +1,68 @@ +#include "scanner.hpp" +#include "tokens.hpp" +#include +#include +#include +#include +#include + +void print_tokens(std::list *list); +int run_file(std::string file); +void run_prompt(void); +ScanResult run(std::string source); + +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(std::string filename) { + std::string content; + std::ifstream file; + file.open(filename); + if (file.is_open()) { + file >> content; + } else { + exit(1); + } + + ScanResult scan_result = run(content); + + return EXIT_SUCCESS; +} + +void run_prompt(void) { + std::string line; + + for (;;) { + std::cout << ">"; + std::cin >> line; + + ScanResult scan_result = run(line.substr(0, line.length())); + + print_tokens(&scan_result.token_list); + } +} + +ScanResult run(std::string source) { return scan_tokens(source); } + +void print_tokens(std::list *list) { + for (std::list::iterator token = list->begin(); token != list->end(); + ++token) { + + if (token->literal != NULL) { + std::cout << token_name(token->type) << "(" << token->literal << "), "; + } else { + std::cout << token_name(token->type) << ", "; + } + } + + std::cout << "\n"; +} diff --git a/src/parser.c b/src/parser.c deleted file mode 100644 index 8c10e2e..0000000 --- a/src/parser.c +++ /dev/null @@ -1,21 +0,0 @@ -#include "parser.h" -#include "tokens.h" - -enum ExprType { - Bin, -}; - -struct Binary { - Binary *left; - Token operator; - Binary *right; -}; - -union Expr { - Binary binary; -}; - -struct Expression { - enum ExprType type; - union Expr expr; -}; diff --git a/src/parser.cpp b/src/parser.cpp new file mode 100644 index 0000000..2c7ff0f --- /dev/null +++ b/src/parser.cpp @@ -0,0 +1,111 @@ +// #include "tokens.hpp" +// #include + +// static const TokenType eq[] = {BANG_EQUAL, EQUAL_EQUAL}; +// static const TokenType comp[] = {GREATER, GREATER_EQUAL, LESS, LESS_EQUAL}; +// static const TokenType unarytokens[] = {BANG, MINUS}; + +// // static int current = -1; +// // TokenList *tokens; + +// class Expression; + +// class Binary { +// public: +// Expression *left; +// Token *operator; +// Expression *right; +// }; + +// typedef struct Grouping { +// Expression *expr; +// } Grouping; + +// typedef struct Unary { +// Token *operator; +// Expression *expr; +// } Unary; + +// class Expression { +// public: +// enum ExprType { Bin, Grp, Lit, Una } type; +// union Expr { +// Binary *binary; +// Grouping *grouping; +// Token *literal; +// Unary *unary; +// } expr; +// }; + +// void parse(TokenList *tokenlist) { +// tokens = tokenlist; +// current = 0; +// } + +// static Token *peek(void) { return tokenlist_get(tokens, current); } + +// static bool is_at_end(void) { return peek()->type == END_OF_FILE; } + +// static bool check(TokenType type) { +// if (is_at_end()) { +// return false; +// } +// return peek()->type == type; +// } + +// static bool match(const TokenType tokens[], int n) { +// for (int i = 0; i < n; i++) { +// if (check(tokens[i])) { +// } +// } +// return false; +// } + +// static Token previous(void) { +// Token t = {NUMBER, "", 0, 0}; +// return t; +// } + +// static Expression unary(void) { +// if (match(unarytokens, 2)) { +// Token operator= previous(); +// Expression right = unary(); +// Expression un; +// un.type = Una; +// Unary new_una = {&operator, & right }; +// un.expr.unary = &new_una; +// return un; +// } +// return primary(); +// } + +// static Expression factor(void) {} + +// static Expression term(void) { Expression expr = factor(); } + +// static Expression comparison(void) { +// Expression expr = term(); +// while (match(comp, 4)) { +// Token operator= previous(); +// Expression right = term(); + +// Binary new_bin = {&expr, &operator, & right }; +// expr.expr.binary = &new_bin; +// expr.type = Bin; +// } +// return expr; +// } +// static Expression equality(void) { +// Expression expr = comparison(); + +// while (match(eq, 2)) { +// Token operator= previous(); +// Expression right = comparison(); +// Binary new_bin = {&expr, &operator, & right }; +// expr.expr.binary = &new_bin; +// expr.type = Bin; +// } +// return expr; +// } + +// // static Expression expression(void) { return equality(); } diff --git a/src/parser.h b/src/parser.h deleted file mode 100644 index 8b87c9f..0000000 --- a/src/parser.h +++ /dev/null @@ -1 +0,0 @@ -typedef struct Binary Binary; diff --git a/src/scanner.c b/src/scanner.cpp similarity index 72% rename from src/scanner.c rename to src/scanner.cpp index 71bd493..1af13ff 100644 --- a/src/scanner.c +++ b/src/scanner.cpp @@ -1,14 +1,13 @@ -#include "scanner.h" -#include "tokens.h" -#include "utils.h" -#include -#include -#include -#include +#include "scanner.hpp" +#include "tokens.hpp" +#include +#include +#include +#include static void scan_token(void); -static void error(char *message); -static void report(char *where, char *message); +static void error(std::string message); +static void report(std::string where, std::string message); static bool is_at_end(void); static bool match(char expected); static char peek(void); @@ -18,25 +17,22 @@ static bool is_digit(char c); static void number(void); static bool is_alpha(char c); static bool is_alphanumeric(char c); -static void identifier(void); +static void identifier(); static bool had_error = false; -static int current_pos = -1; +static size_t current_pos = -1; static int start = -1; static int current_line = -1; -static char *source; -static TokenList token_list; +static std::string source; +static std::list token_list; -ScanResult scan_tokens(char *src) { +ScanResult scan_tokens(std::string src) { current_pos = 0; start = 0; current_line = 1; source = src; - tokenlist_init(&token_list); - int len = (int)strlen(source); - - while (current_pos < len) { + while (current_pos < source.length()) { start = current_pos; scan_token(); } @@ -53,25 +49,25 @@ ScanResult scan_tokens(char *src) { static void add_token(TokenType type) { Token token; token.type = type; - token.lexeme = substring(source, start, current_pos); + token.lexeme = source.substr(start, current_pos); token.literal = NULL; token.line = current_line; - tokenlist_add(&token_list, token); + token_list.push_front(token); } -static void add_token_with_literal(TokenType type, char *literal) { +static void add_token_with_literal(TokenType type, std::string literal) { Token token; token.type = type; - token.lexeme = substring(source, start, current_pos); - token.literal = literal; + token.lexeme = source.substr(start, current_pos); + token.literal = static_cast(&literal); token.line = current_line; - tokenlist_add(&token_list, token); + token_list.push_front(token); } static char advance(void) { - char c = source[current_pos++]; + char c = source.at(current_pos++); return c; } @@ -151,7 +147,7 @@ static void identifier(void) { advance(); } - char *text = substring(source, start + 1, current_pos - start); + std::string text = source.substr(start + 1, current_pos - start); const TokenType *tokentype = get_keyword_token(text); if (tokentype == NULL) { @@ -168,8 +164,7 @@ static void number(void) { advance(); while (is_digit(peek())) advance(); - add_token_with_literal(NUMBER, - substring(source, start + 1, current_pos - start)); + add_token_with_literal(NUMBER, source.substr(start + 1, current_pos - start)); } bool is_digit(char c) { return c >= '0' && c <= '9'; } @@ -188,7 +183,7 @@ void string(void) { advance(); - char *string = substring(source, start + 2, current_pos - start - 2); + std::string string = source.substr(start + 2, current_pos - start - 2); add_token_with_literal(STRING, string); } @@ -204,7 +199,7 @@ static bool match(char expected) { } static char peek_next(void) { - if (current_pos + 1 >= (int)strlen(source)) { + if (current_pos + 1 >= source.length()) { return '\0'; } return source[current_pos + 1]; @@ -222,11 +217,12 @@ static bool is_alpha(char c) { static bool is_alphanumeric(char c) { return is_alpha(c) || is_digit(c); } -static bool is_at_end(void) { return current_pos >= (int)strlen(source); } +static bool is_at_end(void) { return current_pos >= source.length(); } -static void error(char *message) { report("", message); } +static void error(std::string message) { report("", message); } -static void report(char *where, char *message) { - printf("*[Line %i] Error %s : %s\n", current_line, where, message); +static void report(std::string where, std::string message) { + std::cout << "*[Line " << current_line << "] Error " << where << " : " + << message << "\n"; had_error = true; } diff --git a/src/scanner.h b/src/scanner.hpp similarity index 72% rename from src/scanner.h rename to src/scanner.hpp index 8bba336..e7ebd67 100644 --- a/src/scanner.h +++ b/src/scanner.hpp @@ -1,19 +1,20 @@ #ifndef SCANNER_H #define SCANNER_H -#include "tokens.h" -#include -#include +#include "tokens.hpp" +#include +#include +#include typedef struct { bool had_error; - TokenList token_list; + std::list token_list; } ScanResult; -ScanResult scan_tokens(char *source); +ScanResult scan_tokens(std::string source); typedef struct { - const char *key; + const std::string key; const TokenType value; } Item; @@ -23,14 +24,14 @@ static const Item keywords[] = { {"or", OR}, {"print", PRINT}, {"return", RETURN}, {"super", SUPER}, {"this", THIS}, {"true", TRUE}, {"var", VAR}, {"while", WHILE}}; -inline static const TokenType *get_keyword_token(char *key) { +inline static const TokenType *get_keyword_token(std::string key) { int low = 0; int high = sizeof(keywords) / sizeof(Item); while (low < high) { int mid = (low + high) / 2; - int c = strcmp(keywords[mid].key, key); + int c = keywords[mid].key.compare(key); if (c == 0) { return &keywords[mid].value; } diff --git a/src/tokens.c b/src/tokens.c deleted file mode 100644 index 480e7da..0000000 --- a/src/tokens.c +++ /dev/null @@ -1,40 +0,0 @@ -#include "tokens.h" -#include -#include - -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++) { - Token *token = tokenlist_get(tokenlist, i); - if (token->literal != NULL) { - printf("%s(%s), ", token_name(token->type), (char *)token->literal); - } else { - printf("%s, ", token_name(token->type)); - } - } - printf("\n"); -} - -void tokenlist_free(TokenList *list) { free(list->tokens); } diff --git a/src/tokens.h b/src/tokens.hpp similarity index 79% rename from src/tokens.h rename to src/tokens.hpp index 8ad66eb..739f797 100644 --- a/src/tokens.h +++ b/src/tokens.hpp @@ -1,6 +1,8 @@ #ifndef TOKENS_H #define TOKENS_H +#include + typedef enum { LEFT_PAREN, RIGHT_PAREN, @@ -59,25 +61,9 @@ static inline const char *token_name(TokenType type) { typedef struct { TokenType type; - char *lexeme; + std::string lexeme; void *literal; int line; } Token; -typedef struct TokenList { - 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 diff --git a/src/utils.c b/src/utils.c deleted file mode 100644 index 7a00364..0000000 --- a/src/utils.c +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include - -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+=1){ - *(ptr+c) = *(string+position-1); - string += sizeof(char); - } - *(ptr+c) = '\0'; - - return ptr; -} diff --git a/src/utils.h b/src/utils.h deleted file mode 100644 index 7356eb3..0000000 --- a/src/utils.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef UTILS_H -#define UTILS_H - -char* substring(char* string, int position, int length); - -#endif