From 88bd82b7628a64ac189b9daf2be94c4533a9b88d Mon Sep 17 00:00:00 2001 From: Ruben Date: Thu, 26 Jan 2023 16:51:56 +0100 Subject: [PATCH] Parser is now working, just need functionality. Added error output and line numbers. Next up: Proper functionality. --- src/lang.cc | 145 +++++++++++++++++++++++++++++++++++++--------- src/lang.h | 18 ++++-- test/lang_test.cc | 2 + 3 files changed, 133 insertions(+), 32 deletions(-) diff --git a/src/lang.cc b/src/lang.cc index 3eb082d..7ba88f3 100644 --- a/src/lang.cc +++ b/src/lang.cc @@ -1,30 +1,47 @@ #include "lang.h" +const char *here(int row, int col) { + char *ret = (char *)malloc(sizeof(char *)); + std::sprintf(ret, "%s:%d:%d", filename.string().c_str(), row, col); + return ret; +} + +int ferr(const char *fmt, ...) { + std::va_list va; + va_start(va, fmt); + vfprintf(stderr, fmt, va); + va_end(va); + return 1; +} + int read_file(std::deque args) { if (args.empty()) { - std::cout << bg_red(bold("ERROR")) << ": No file input" << std::endl; - return 1; + return ferr("%s: No file input.\n", bg_red(bold("ERROR")).c_str()); } - fs::path filename = args[0]; + filename = args[0]; args.pop_front(); std::ifstream file(filename); if (!file) { - std::cout << bg_red(bold("ERROR")) << ": Could not find file" << std::endl; - return 1; + return ferr("%s: Could not find file.\n", bg_red(bold("ERROR")).c_str()); } std::string line; + int row = 1; while (std::getline(file, line)) { - std::cout << line << std::endl; + int error = parse_line(line, row); + if (error) + return 1; + row++; } return 0; } -int parse_line(std::string line) { +int parse_line(std::string line, int row) { + int col = 1; struct parsed_token parsed { empty_token, empty_token }; - if (int sub = line.find("//")) - line = line.substr(sub); + if (line.length() == 0) + return 0; std::deque tokens; int start = 0; size_t end = line.find(" "); @@ -34,30 +51,106 @@ int parse_line(std::string line) { end = line.find(" ", start); } for (std::string &token : tokens) { + if (token == "//") + return 0; + const char *ctoken = token.c_str(); try { Token curr_token = CV_Tokens.at(token); - parsed.lastToken = parsed.currentToken; - if (curr_token == parsed.lastToken && curr_token.type == TokenType::SPACE) + parsed.last_token = parsed.current_token; + if (curr_token == parsed.last_token && + curr_token.type == TokenType::SPACE) continue; - else { - // TODO: Line number handling for better errors - std::cerr << "Invalid token `" << token << "'." << std::endl; - return 1; + parsed.current_token = curr_token; + switch (parsed.current_token.type) { + case TokenType::COLONCOLON: { + ferr("%s: Token `%s' is not yet implemented.\n", here(row, col), + ctoken); + break; + } + case TokenType::COMMA: { + ferr("%s: Token `%s' is not yet implemented.\n", here(row, col), + ctoken); + break; + } + case TokenType::EQ: { + ferr("%s: Token `%s' is not yet implemented.\n", here(row, col), + ctoken); + break; + } + case TokenType::LEFT_PAREN: { + ferr("%s: Token `%s' is not yet implemented.\n", here(row, col), + ctoken); + break; + } + case TokenType::RIGHT_PAREN: { + ferr("%s: Token `%s' is not yet implemented.\n", here(row, col), + ctoken); + break; + } + } + switch (parsed.current_token.intrinsic) { + case Intrinsic::INCLUDE: { + ferr("%s: Intrinsic `%s' is not yet implemented.\n", here(row, col), + ctoken); + break; + } + case Intrinsic::ENTER: { + ferr("%s: Intrinsic `%s' is not yet implemented.\n", here(row, col), + ctoken); + break; + } + case Intrinsic::EXIT: { + ferr("%s: Intrinsic `%s' is not yet implemented.\n", here(row, col), + ctoken); + break; + } + case Intrinsic::HIDE: { + ferr("%s: Intrinsic `%s' is not yet implemented.\n", here(row, col), + ctoken); + break; + } + case Intrinsic::LET: { + ferr("%s: Intrinsic `%s' is not yet implemented.\n", here(row, col), + ctoken); + break; + } + case Intrinsic::SHOW: { + ferr("%s: Intrinsic `%s' is not yet implemented.\n", here(row, col), + ctoken); + break; + } + case Intrinsic::UNLET: { + ferr("%s: Intrinsic `%s' is not yet implemented.\n", here(row, col), + ctoken); + break; + } + default: + break; + } + switch (parsed.current_token.constant) { + case Constant::CHARACTER: { + ferr("%s: Constant `%s' is not yet implemented.\n", here(row, col), + ctoken); + break; + } + case Constant::IMAGE: { + ferr("%s: Constant `%s' is not yet implemented.\n", here(row, col), + ctoken); + break; + } + case Constant::LOCATION: { + ferr("%s: Constant `%s' is not yet implemented.\n", here(row, col), + ctoken); + break; + } + default: + break; } - parsed.currentToken = curr_token; } catch (std::out_of_range &oor) { // this is most likely a variable or a string - if (parsed.lastToken.type == TokenType::INTRINSIC && - parsed.lastToken.intrinsic == Intrinsic::LET) { - VariableToken var{TokenType::VARIABLE, Intrinsic::EMPTY, - Constant::EMPTY, "", token}; - parsed.currentToken = var; - var_tokens.push_back(var); - } - // string parsing - std::cerr << "Not implemented. Found `" << token << "'." << std::endl; - continue; + ferr("%s: Invalid token `%s'.\n", here(row, col), ctoken); } + col += token.length() + 1; } return 0; } diff --git a/src/lang.h b/src/lang.h index 2a9ce16..b261fb2 100644 --- a/src/lang.h +++ b/src/lang.h @@ -1,14 +1,15 @@ #pragma once #include "colors.h" +#include #include #include #include #include -#include #include #include #include +#include #include namespace fs = std::filesystem; @@ -27,7 +28,7 @@ enum class TokenType { VARIABLE }; -enum class Intrinsic { EMPTY, LET, UNLET, ENTER, EXIT, SHOW, HIDE }; +enum class Intrinsic { INCLUDE, EMPTY, LET, UNLET, ENTER, EXIT, SHOW, HIDE }; enum class Constant { EMPTY, CHARACTER, LOCATION, IMAGE }; @@ -59,7 +60,7 @@ struct VariableToken : Token { } }; -std::map CV_Tokens{ +std::unordered_map CV_Tokens{ {"", Token{TokenType::EMPTY, Intrinsic::EMPTY, Constant::EMPTY, "", ""}}, {" ", Token{TokenType::SPACE, Intrinsic::EMPTY, Constant::EMPTY, "", ""}}, {"(", @@ -70,6 +71,8 @@ std::map CV_Tokens{ Token{TokenType::COLONCOLON, Intrinsic::EMPTY, Constant::EMPTY, "", ""}}, {"=", Token{TokenType::EQ, Intrinsic::EMPTY, Constant::EMPTY, "", ""}}, {",", Token{TokenType::COMMA, Intrinsic::EMPTY, Constant::EMPTY, "", ""}}, + {"%include", + Token{TokenType::INTRINSIC, Intrinsic::INCLUDE, Constant::EMPTY, "", ""}}, {"let", Token{TokenType::INTRINSIC, Intrinsic::LET, Constant::EMPTY, "", ""}}, {"unlet", @@ -92,11 +95,14 @@ std::map CV_Tokens{ Token empty_token{TokenType::EMPTY, Intrinsic::EMPTY, Constant::EMPTY, "", ""}; struct parsed_token { - Token lastToken; - Token currentToken; + Token last_token; + Token current_token; }; std::vector var_tokens; +fs::path filename; +const char *here(int row, int col); +int ferr(std::string fmt, ...); int read_file(std::deque args); -int parse_line(std::string line); +int parse_line(std::string line, int row); diff --git a/test/lang_test.cc b/test/lang_test.cc index f55f52a..f0870a1 100644 --- a/test/lang_test.cc +++ b/test/lang_test.cc @@ -4,9 +4,11 @@ int main(int argc, char **argv) { if (argc != 2) { + std::cout << "Wrong amount of args" << std::endl; return 1; } std::deque args; args.push_back(std::string(argv[1])); return read_file(args); + return 0; }