diff --git a/cclox_src/main.cc b/cclox_src/main.cc index 9c73496..e2694f5 100644 --- a/cclox_src/main.cc +++ b/cclox_src/main.cc @@ -1,6 +1,75 @@ -#include +#include "token.hh" +#include "scanner.hh" +#include +#include +#include +#include +#include +#include + +#define PROMPT "> " + +static bool had_error = false; + +void run_file(const char *path); +void run_prompt(); +void run(const std::string &code); +void error(int line, const std::string &message); +void report(int line, const std::string &where, const std::string &message); + +int main(int argc, char *argv[]) { + if (argc > 2) { + std::cout << "Usage: cclox [script]\n"; + exit(EX_USAGE); + } + + if (argc == 2) { + run_file(argv[1]); + } else { + run_prompt(); + } -int main() { - printf("Hello from cclox\n"); return 0; } + +void run_file(const char *path) { + if (std::ifstream source_code{path, std::ios::ate}) { + uint64_t size = source_code.tellg(); + std::string code(size, '\0'); + source_code.seekg(0); + source_code.read(&code[0], size); + + run(code); + if (had_error) { + exit(EX_DATAERR); + } + } +} + +void run_prompt() { + std::string line{}; + std::cout << PROMPT; + while (std::getline(std::cin, line)) { + run(line); + std::cout << PROMPT; + had_error = false; + } +} + +void run(const std::string &code) { + Scanner scanner{code}; + std::vector tokens = scanner.scan_tokens(); + + for (auto token : tokens) { + std::cout << token << '\n'; + } +} + +void error(int line, const std::string &message) { + report(line, "", message); +} + +void report(int line, const std::string &where, const std::string &message) { + std::cout << "[line " << line << "] Error" << where << ": " << message << '\n'; + had_error = true; +} diff --git a/cclox_src/object.cc b/cclox_src/object.cc new file mode 100644 index 0000000..32560a6 --- /dev/null +++ b/cclox_src/object.cc @@ -0,0 +1,18 @@ +#include "object.hh" + +void Identifier::write(std::ostream &os) const { + os << identifier; +}; + +void StringLit::write(std::ostream &os) const { + os << literal; +}; + +void Number::write(std::ostream &os) const { + os << number; +}; + +std::ostream &operator<<(std::ostream &os, const Object &obj) { + obj.write(os); + return os; +} diff --git a/cclox_src/object.hh b/cclox_src/object.hh new file mode 100644 index 0000000..fd59666 --- /dev/null +++ b/cclox_src/object.hh @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +struct Object { + Object() = delete; + virtual ~Object() = default; + virtual void write(std::ostream &os) const = 0; +}; + +struct Identifier : public Object { + virtual void write(std::ostream &os) const final; + std::string identifier; +}; + +struct StringLit : public Object { + virtual void write(std::ostream &os) const final; + std::string literal; +}; + +struct Number : public Object { + virtual void write(std::ostream &os) const final; + double number; +}; + +std::ostream &operator<<(std::ostream &os, const Object &obj); diff --git a/cclox_src/scanner.cc b/cclox_src/scanner.cc new file mode 100644 index 0000000..68259aa --- /dev/null +++ b/cclox_src/scanner.cc @@ -0,0 +1,7 @@ +#include "scanner.hh" +#include "token.hh" +#include + +std::vector Scanner::scan_tokens() { + return std::vector{}; +} diff --git a/cclox_src/scanner.hh b/cclox_src/scanner.hh new file mode 100644 index 0000000..ae24ce1 --- /dev/null +++ b/cclox_src/scanner.hh @@ -0,0 +1,11 @@ +#pragma once + +#include "token.hh" +#include + +struct Scanner { + Scanner(const std::string &code) : code{code} {}; + std::vector scan_tokens(); + + std::string code; +}; diff --git a/cclox_src/token.cc b/cclox_src/token.cc new file mode 100644 index 0000000..a60b490 --- /dev/null +++ b/cclox_src/token.cc @@ -0,0 +1,5 @@ +#include "token.hh" + +std::ostream &operator<<(std::ostream &os, const Token &token) { + return os << uint8_t(token.type) << ' ' << token.lexeme << ' ' << token.literal; +} diff --git a/cclox_src/token.hh b/cclox_src/token.hh new file mode 100644 index 0000000..4f3e88e --- /dev/null +++ b/cclox_src/token.hh @@ -0,0 +1,39 @@ +#pragma once + +#include "object.hh" +#include +#include + +enum class TokenType : uint8_t { + // Single-character tokens. + LEFT_PAREN, RIGHT_PAREN, LEFT_BRACE, RIGHT_BRACE, + COMMA, DOT, MINUS, PLUS, SEMICOLON, SLASH, STAR, + + // One or two character tokens. + BANG, BANG_EQUAL, + EQUAL, EQUAL_EQUAL, + GREATER, GREATER_EQUAL, + LESS, LESS_EQUAL, + + // Literals. + IDENTIFIER, STRING, NUMBER, + + // Keywords. + AND, CLASS, ELSE, FALSE, FUN, FOR, IF, NIL, OR, + PRINT, RETURN, SUPER, THIS, TRUE, VAR, WHILE, + + EOFILE, +}; + +struct Token { + Token(TokenType type, const std::string &lexeme, Object &literal, int line) + : type{type}, lexeme{lexeme}, literal{literal}, line{line} + {}; + + TokenType type; + std::string lexeme; + Object &literal; + int line; +}; + +std::ostream &operator<<(std::ostream &os, const Token &token);